Это сложный вопрос с количеством граней к нему, так что я собираюсь попытаться разбить его, как могу.
Во-первых, существует математическая концепция нуля и является ли она положительной или отрицательной. К сожалению, ответ на это, по сути, заключается в том, что он зависит от контекста, и иногда разумно включать нуль в набор положительных чисел или отрицательных чисел. Математики признают двусмысленность и имеют особый термин, когда им нужно четко понимать, находится ли нуль в определенном наборе чисел или нет - «неотрицательные» и «неположительные» оба включают ноль. Некоторые «здравые» определения положительного и отрицательного позволяют исключить исключительное сравнение с нулем, что ставит ноль в особый случай не быть ни положительным, ни отрицательным. Другие имеют всеобъемлющее понятие о положительном или отрицательном, которое может сделать ноль как положительным, так и отрицательным. https://math.stackexchange.com/questions/26705/is-zero-positive-or-negative
Так что же это значит для языка Java?Опять же, есть несколько различных случаев для рассмотрения: примитивные интегральные типы, примитивные типы с плавающей запятой, примитивы в штучной упаковке, произвольные классы точности BigDecimal и BigInteger и, что наиболее важно, какие эффекты видны?
Java представляет собой примитивные интегральные типы с использованием системы 2s complement и поэтому имеет только одно представление для нуля. В том смысле, что 0 не имеет установленного бита знака, было бы разумно сказать, что 0 положительно. Тем не менее, это действительно спорный вопрос, поскольку на языке нет ничего другого, что связано с тем, является ли ноль положительным или отрицательным, и поэтому он действительно не имеет практического эффекта. В коробчатых версиях этих типов наблюдается очень то же поведение.
В чем состоит дополнение 2, заключается в том, что любой заданный диапазон чисел неравномерно сбалансирован вокруг нуля. Итак, если вы берете 8-битное значение, вы можете представить с ним 256 значений. Один из них - 0, который оставляет вам 255 ненулевых значений. Однако вы разделили остаток, вы получаете одну сторону немного больше, чем другую. 2 добавляет -128 действительное отрицательное значение и 127 наибольшее положительное значение, которое вы можете представить с 8 бит. То же самое верно для более крупных интегральных типов int
и long
- они могут представлять еще одно ненулевое отрицательное целое число, отличное от ненулевого положительного целого. Это не ошибка, а ошибка, это простой факт.
Для примитивных типов с плавающей запятой, double
и float
, Java использует IEEE 754 для их представления. Это позволяет использовать два разных способа представления 0,0, и поэтому технически каждый ноль равен -0,0 или +0,0. Стандарт IEEE, однако, ясно, что эти два значения практически неотличимы - они равны, и поэтому -0.0 == +0.0
оценивает значение true. Для большинства математических операций -0,0 и +0,0 имеют тот же эффект. Это до тех пор, пока вы не попытаетесь что-то, что генерирует Inf. Итак, деление на -0.0 даст вам -Inf и деление на +0.0 получит + inf. В любом случае ваш расчет попал в черную дыру. К счастью, все NaN одинаковы, поэтому -0.0/0.0 доставит вам Nan точно так же, как 0.0/0.0. Для других математических операций -0.0 действует последовательно. Таким образом, Math.sqrt(-0.0)
составляет -0,0 и Math.sqrt(0.0)
составляет 0,0. Math.abs(-0.0)
вернется 0.0. Но разница между -0.0 и 0.0 очень мало.
Важно иметь в виду, что при отображении чисел в форматированной строке знак остается. Если вы действительно заботитесь об этом, вы можете использовать Math.abs(), чтобы превратить «отрицательный» ноль в «положительный» ноль, но обычно это не проблема, о которой стоит подумать.
Есть любопытный эффект, когда речь идет о коробках для чисел с плавающей запятой и о методе 'equals(). Примитивные типы: -0.0 == +0.0
- true
. Однако Double.valueOf(-0.0).equals(Double.valueOf(+0.0))
оценивает значение false, то есть documented, но контр-интуитивно понятный и, возможно, запутанный. В сочетании с автоматическим боксированием и автоматической распаковкой это может иметь некоторые запутанные побочные эффекты - например, Double.valueOf(-0.0) == Double.valueOf(+0.0)
неверно, но -0.0 == +0.0
- это правда. Между тем, верно Double.valueOf(-0.0) == +0.0d
. Как всегда с Java - будьте немного осторожны с бокс-примитивами и всегда будьте осторожны с микшированием вложенных и распакованных примитивов.
BigDecimal выдает дополнительный гаечный ключ в работах, имея немного отличающуюся реализацию equals(). Итак, BigDecimal.valueOf(-0.0).equals(BigDecimal.valueOf(0.0))
оценивает true, но BigDecimal.valueOf(-0.0).equals(BigDecimal.ZERO)
является ложным. Это связано с тем, что масштаб рассматривается вместе со значением. BigDecimal.ZERO на самом деле равен 0, что рассматривается как другое значение от 0.0, которое опять отличается от 0.00 - new BigDecimal("-0.0").equals(new BigDecimal("-0.00"))
оценивается как false.
Еще одна вещь, которую мы можем рассмотреть, - это функция Math.signum()
, которая определяется как возвращающая -1, 0 или 1 в зависимости от того, отрицательный аргумент, ноль или положительный аргумент.То же самое верно для метода signum на классах BigInteger
и BigDecimal
в пакете java.math. К сожалению, функция Math.signum()
возвращает double, и поэтому вы получаете -0.0 для -0.0 и 0.0 для 0.0, тогда как BigDecimal.signum()
возвращает int. Но что подразумевается в том, что, однако, вы определяете нуль, это не очень позитивно или отрицательно.
Что означает «считать отрицательным»? Почему это имеет значение? (с точки зрения программирования) –
Ноль не является отрицательным, и я согласен, что это не имеет значения в любом случае. – androiddev19
Для большинства людей это может быть неважно, что касается программирования приложений, но это может быть в какой-то момент ...? В любом случае, факт, что они передавали эту информацию как истину, не выглядит хорошо для остальной части их информации, если она является законным сайтом, который существует уже давно. – XaolingBao