Авторский проект IT-специалиста Олега Барабанова Персональные публикации на тему IT и не только…

Отличия в применении знаковых нолей +0 и -0 в JavaScript и не только

На написание текущей статьи меня вдохновил вопрос на Stackoverflow про то, как можно элегантно избавиться от отрицательного нуля в JavaScript, и где пользователь @pilchard, подсказал довольно таки элегантное решение с простым сложением отрицательного нуля и положительного. Т.е. -0 + 0 = 0. При этом интересно, что в том же вопросе, можно увидеть людей, которых удивило различие между +0 и -0 (но это ни в коем случае не принижает их профессиональных качеств!).

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

Итак, как вы думаете, может ли условие x >= 0 быть истинным при x с отрицательным знаком? Возможно вы удивитесь, но может! Взгляните на следующие примеры кода:

const x = -0;
if (x >= 0) console.log(x); // условие сработает и будет выведено -0

Как видите, знак "минус" смог пролезть. Вы конечно можете озадачиться вопросом, а может ли знак вообще хоть как-то влиять, ведь даже -0 === +0 вернет true. Но позвольте представить вам другой, довольно таки интересный пример:

-0 === 0; // => true;
(5 + -0) === (5 + 0); // => true
(5 - -0) === (5 - 0); // => true
(5 * -0) === (5 * 0); // => true
(5 / -0) === (5 / 0) // внимание - false!

Вы можете увидеть, что на примере деления уже появляются различия между использованием +0 и -0. Обратите внимание, что в JS не является ошибкой деление на ноль и результатом этого деления становится бесконечность (или Infinity в JS), но вот при делении числа на -0, результатом будет уже -∞ (или -Infinity в JS). А как известно -∞ !== ∞. Другими словами:

const a = 5 / 0; // => Infinity
const b = 5 / -0; // => -Infinity
a === b; // => false, поскольку Infinity !== -Infinity

Как вы можете заметить, есть ситуации, когда отрицательный знак в нуле может привести к отличному от обычного нуля результату. Более подробно вы можете ознакомиться на странице Википедии про знаковый ноль. А про сравнения 0 и -0 вы можете ознакомиться на странице MDN, где вы также можете ознакомиться про специальный метод Object.is(), предназначенный для сравнения (отличным по поведению от == и ===) и который учитывает знаковый ноль. Пример ниже:

0 === -0; // => true
Object.is(0, -0); // => false

Тем не менее, если необходимо избавиться от отрицательно нуля, достаточно просто приплюсовать к нему положительный ноль (о чем упомянул в начале статьи):

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

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

Заключение

Сама по себе ситуация с +0 и -0 случается на практике не так уж и часто и еще реже когда она может как-то повлиять на логику программы. Но "очень редко" и "никогда" это все-таки разные понятия и в каких-то редких случаях (как уже было указано на примере выше), эти особенности могут дать знать о себе. В любом случае, знание про такие особенности будет не лишним.