+0 и -0 одинаковы?

Чтение через спецификацию ECMAScript 5.1, +0 а также -0 различаются

Почему тогда +0 === -0 оценить true?

11 ответов

Решение

JavaScript использует стандарт IEEE 754 для представления чисел. Из Википедии:

Ноль со знаком - это ноль со связанным знаком. В обычной арифметике −0 = +0 = 0. Однако в вычислениях некоторые числовые представления допускают существование двух нулей, часто обозначаемых как -0 (отрицательный ноль) и +0 (положительный ноль). Это происходит в некоторых представлениях чисел со знаком для целых чисел и в большинстве представлений чисел с плавающей запятой. Число 0 обычно кодируется как +0, но может быть представлено либо +0, либо -0.

Стандарт IEEE 754 для арифметики с плавающей запятой (в настоящее время используется большинством компьютеров и языков программирования, которые поддерживают числа с плавающей запятой) требует +0 и -0. Нули можно рассматривать как вариант расширенной линии действительных чисел, такой, что 1/−0 = −∞ и 1/+0 = +∞, деление на ноль не определено только для ±0/±0 и ±∞/±∞,

Статья содержит дополнительную информацию о различных представлениях.

Так что это причина, почему, технически, оба нуля должны быть различены.

Тем не мение, +0 === -0 оценивает как истинное. Это почему (...)?

Это поведение явно определено в разделе 11.9.6, Алгоритм сравнения строгого равенства (выделение частично мое):

Сравнение x === y, где x а также y являются значениями, производит истину или ложь. Такое сравнение выполняется следующим образом:

(...)

  • Если тип (х) является число, то

    1. Если x равен NaN, вернуть false.
    2. Если y равен NaN, вернуть false.
    3. Если x - это то же самое числовое значение, что и y, вернуть true.
    4. Если x равен +0, а y равен −0, вернуть true.
    5. Если x равен −0, а y равен +0, верните true.
    6. Вернуть ложь.

(...)

(То же самое относится и к +0 == -0Кстати.)

Кажется логично лечить+0а также-0как равный В противном случае мы должны были бы принять это во внимание в нашем коде, и я лично не хочу этого делать;)


Замечания:

ES2015 представляет новый метод сравнения,Object.is, Object.is четко различает -0 а также +0:

Object.is(-0, +0); // false

Я добавлю это как ответ, потому что я пропустил комментарий @user113716.

Вы можете проверить на -0, выполнив это:

function isMinusZero(value) {
  return 1/value === -Infinity;
}

isMinusZero(0); // false
isMinusZero(-0); // true

Я только что натолкнулся на пример, где +0 и -0 ведут себя совершенно по-разному:

Math.atan2(0, 0);  //returns 0
Math.atan2(0, -0); //returns Pi

Будьте осторожны: даже при использовании Math.round с отрицательным числом, таким как -0,0001, оно будет на самом деле -0 и может привести к некоторым последующим вычислениям, как показано выше.

Быстрый и грязный способ исправить это сделать что-то вроде:

if (x==0) x=0;

или просто:

x+=0;

Это преобразует число в +0, если оно было -0.

Ответ 2021 года

+0 и -0 - это одно и то же?

Краткий ответ: в зависимости от того, какой оператор сравнения вы используете.

Длинный ответ:

По сути, до сих пор у нас было 4 типа сравнения :

  1. «свободное» равенство
      console.log(+0 == -0); // true
  1. «строгое» равенство
      console.log(+0 === -0); // true
  1. Равенство «одинаковой ценности» (ES2015's Object.is)
      console.log(Object.is(+0, -0)); // false
  1. Равенство "одинаковое значение-ноль" (ES2016)
      console.log([+0].includes(-0)); // true

В результате просто Object.is(+0, -0) имеет значение с другими.

В стандарте IEEE 754, используемом для представления типа Number в JavaScript, знак представлен битом (1 означает отрицательное число).

В результате для каждого представимого числа существует как отрицательное, так и положительное значение, включая 0,

Вот почему оба -0 а также +0 существовать.

Я бы свалил вину на метод сравнения строгого равенства ( '==='). Посмотрите на раздел 4d введите описание изображения здесь

см. 7.2.13 Сравнение строгого равенства в спецификации

Отвечая на оригинальное название Are +0 and -0 the same?:

brainslugs83 (в комментариях ответа Spudley) указал на важный случай, когда +0 и -0 в JS не совпадают - реализованы как функция:

var sign = function(x) {
    return 1 / x === 1 / Math.abs(x);
}

Это будет, кроме стандартных Math.sign верните правильный знак +0 и -0.

Мы можем использовать Object.is различать +0 и -0, и еще одну вещь, NaN==NaN,

Object.is(+0,-0) //false

Object.is(NaN,NaN) //true

Если тебе надо sign функция, которая поддерживает -0 а также +0:

      var sign = x => 1/x > 0 ? +1 : -1;

Он действует как Math.sign, Кроме этого sign(0) возвращается 1 а также sign(-0) возвращается -1.

Есть два возможных значения (битовые представления) для 0. Это не уникально. Особенно в числах с плавающей точкой это может произойти. Это потому, что числа с плавающей запятой на самом деле хранятся в виде формулы.

Целые числа также могут храниться разными способами. Вы можете иметь числовое значение с дополнительным битом знака, поэтому в 16-битном пространстве вы можете хранить 15-битное целочисленное значение и бит знака. В этом представлении значения 1000 (hex) и 0000 оба равны 0, но одно из них равно +0, а другое - -0.

Этого можно избежать, вычитая 1 из целочисленного значения, чтобы оно варьировалось от -1 до -2^16, но это было бы неудобно.

Более распространенный подход - хранить целые числа в "двух дополнениях", но, очевидно, ECMAscript решил этого не делать. В этом методе числа в диапазоне от 0000 до 7FFF положительны. Отрицательные числа начинаются с FFFF (-1) до 8000.

Конечно, те же правила применимы и к большим целым числам, но я не хочу, чтобы мой F изнашивался.;)

В Википедии есть хорошая статья, чтобы объяснить это явление: http://en.wikipedia.org/wiki/Signed_zero

Вкратце, это и +0, и -0 определены в спецификациях IEEE с плавающей запятой. Они оба технически отличаются от 0 без знака, который является целым числом, но на практике все они оцениваются как ноль, поэтому различие можно игнорировать для всех практических целей.

Другие вопросы по тегам