Чи однакові +0 і -0?


171

Читання через ECMAScript 5.1 специфікації , +0і -0відрізняються.

Чому тоді +0 === -0оцінюють true?


можливий дублікат диференціації +0 та -0
GolezTrol

6
Зауважте, що в ES2015 ви можете Object.isрозрізняти +0 і -0
Бенджамін Груенбаум

Цитуючи Девіда Фланагана з JS остаточне керівництво : Underflow виникає, коли результат числової операції ближче до нуля, ніж найменше представлене число. У цьому випадку JavaScript повертає 0. Якщо підтікання відбувається з від'ємного числа, JavaScript повертає спеціальне значення, відоме як "негативний нуль".
RBT

Відповіді:


193

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є значеннями, дає істинне або хибне . Таке порівняння проводиться так:

(...)

  • Якщо Тип (x) - Число, то

    1. Якщо x NaN, поверніть false.
    2. Якщо y - NaN, поверніть хибне.
    3. Якщо x - те саме значення числа, що і y, поверніть true.
    4. Якщо x дорівнює +0, а y - 0, поверніть true.
    5. Якщо x дорівнює -0, а y +0, поверніть true.
    6. Повернути помилково.

(...)

(Те ж саме стосується і +0 == -0BTW.)

Здається, логічно ставитись +0і -0як до рівних. Інакше нам доведеться це враховувати у своєму коді, і я особисто цього не хочу робити;)


Примітка:

ES2015 вводить новий метод порівняння, Object.is. Object.isчітке розходження між -0і +0:

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

15
Справді 1/0 === Infinity; // trueі 1/-0 === -Infinity; // true.
користувач113716

48
Так у нас є 1 === 1і +0 === -0але 1/+0 !== 1/-0. Як дивно!
Randomblue

8
@ Випадково: Я думаю, що це, звичайно, краще, ніж +0 !== -0;) Це справді може створити проблеми.
Фелікс Клінг

@FelixKling, або 0 !== +0/ 0 !== -0, що теж створило б проблеми!
Янік Рошон

5
Власне, такі моделі поведінки обмежують обчислення в математиці. Наприклад, функція 1 / x має значення нескінченності в 0, однак вона відокремлена, якщо ми наближаємось до 0 від позитивної негативної сторони; в першому результат - + інф, в другому - -в.
Агостон Хорват

19

Я додам це як відповідь, тому що я не помітив коментаря @ user113716.

Ви можете протестувати на -0, зробивши це:

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

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

6
Напевно, слід також перевірити наявність == 0, вищевикладене isMinusZero (-1e-323) повертає істину!
Кріс

1
@Chris, обмеження показника подвійної точності полягає в тому e±308, що ваше число може бути представлене лише в денормалізованій формі, а різні реалізації мають різні думки щодо того, де їх взагалі підтримувати чи ні. Справа в тому, що на деяких машинах у деяких режимах з плаваючою точкою ваше число представлено як, -0а на інших - денормоване число 0.000000000000001e-308. Такі поплавки, такі веселі
слабкішпаза

Це може працювати і для інших мов (я тестував на C і це працює)
Мукул Кумар

11

Я щойно натрапив на приклад, коли +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.


Дякую. Так дивно, як додавання нуля вирішить проблему, в яку я зіткнувся. "Якщо все інше не вдалося, додайте нуль." Урок на все життя.
Мікроз

Я щойно стикався з цим у Math.atan (y / x), який (можливо, дивно) може справлятись позитивно чи негативно нескінченно "y / x", за винятком випадків, коли він дає неправильну відповідь у випадку, коли x дорівнює -0. Заміни "x" на "(x + 0)" виправляє його.
Джейкоб К. каже, що

5

У стандарті IEEE 754, який використовується для представлення типу Числа в JavaScript, знак представлений бітом (a 1 означає негативне число).

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

Ось чому обидва -0і +0існують.


3
Доповнення двох також використовує трохи для ознаки, але має лише один нуль (додатний).
Фелікс Клінг

1
Так, але у доповненнях Two негативний біт також є частиною значення, тому щойно ви встановите негативний біт, він більше не дорівнює нулю.
Арно Ле Блан

3

Відповідь на оригінальну назву 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.


2

Можливі два значення (бітові подання) для 0. Це не унікально. Особливо в числах з плаваючою комою це може статися. Це тому, що числа з плаваючою комою насправді зберігаються як своєрідна формула.

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

Цього можна уникнути, віднімаючи 1 від цілого числа, так що воно становило від -1 до -2 ^ 16, але це було б незручно.

Більш поширений підхід - зберігання цілих чисел у "двох доповненнях", але, очевидно, ECMAscript вирішив не робити. У цьому методі цифри варіюються від 0000 до 7FFF додатними. Негативні цифри починаються від FFFF (-1) до 8000.

Звичайно, ті ж правила застосовуються і до більших цілих чисел, але я не хочу, щоб мій F зношувався. ;)


4
Але ви не вважаєте +0 === -0це трохи дивним. Тому що тепер у нас є 1 === 1і +0 === -0але 1/+0 !== 1/-0...
Randomblue

2
Звичайно +0 -0. Це обоє нічого. Але існує величезна різниця між + нескінченністю та -безмежністю? Ці числа нескінченності можуть навіть бути причиною того, що ECMA підтримує і +0, і -1.
GolezTrol

Ви не пояснюєте, чому +0 === -0незважаючи на те, що представлення двох бітів відрізняються.
Randomblue

1
+0 є -0 - 0, нічого, nada, niente. Має сенс, що вони однакові. Чому небо синє? 4 + 3 також такий же, як 1 + 6, хоча уявлення різні. Вони мають різні подання (і, отже, різне значення біта), але при порівнянні вони обробляються як той самий нуль, яким вони є.
GolezTrol

1
Вони не однакові. Див. Stackoverflow.com/questions/7223717/differentiating-0-and-0 для прикладів, що показують це.
Randomblue

2

Ми можемо використовувати , Object.isщоб розрізняти +0 і -0, і ще одну річ, NaN==NaN.

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

Object.is(NaN,NaN) //true


0

У Вікіпедії є гарна стаття для пояснення цього явища: http://en.wikipedia.org/wiki/Signed_zero

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


2
Це не зовсім правильно - наприклад, 1 / -0 == 1/0 оцінює значення false у JavaScript. Вони не "оцінюють" до магічного беззнакового нуля, оскільки в IEEE 754. немає такого поняття, як "непідписаний цілий нуль"
BrainSlugs83,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.