Отличия в применении знаковых нолей +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 случается на практике не так уж и часто и еще реже когда она может как-то повлиять на логику программы. Но "очень редко" и "никогда" это все-таки разные понятия и в каких-то редких случаях (как уже было указано на примере выше), эти особенности могут дать знать о себе. В любом случае, знание про такие особенности будет не лишним.