Компьютеры не умеют вычитать числа. Внутри процессора нет “вычитатора”, есть только сумматор (adder). Поэтому когда надо посчитать, например, 3 – 2, компьютер внутри себя переписывает это выражение как 3 + (-2), то-есть, складывает тройку с минус двойкой.
Числа внутри компьютера, конечно же, двоичные. Самый значимый бит в числе — знаковый, если он 0, то число неотрицательное, а если 1 — то отрицательное. Если мы пишем слева направо, так что самый значимый бит — самый первый слева (к слову, внутри себя компьютеры же пишут по-еврейски, справа налево (little endian)).
Так, знаковое целое число 3 записывается как 0011 (пусть у меня будет четырёхбитный процессор), а знаковое целое число -2 пишется как 1110 (т.н. дополнительный код, two’s complement). Ну, и складываем эти числа, пользуясь двоичной математикой, получаем искомый 0001 (вернее, 10001, но процессор у нас четырёхбитный, так что мнимое переполнение идёт в игнор).
Все современные процессоры (x86/AMD64, процессоры ARM, и так далее) записывают отрицательные целые числа, пользуясь дополнительным кодом. А вот на некоторых более ранних компьютерах, типа PDP-1 или советской ЭВМ БЭСМ-2, для записи таких чисел использовался более простой обратный код. Получить обратный код из двоичного числа проще — надо просто поменять единички на нолики и наоборот. Так, чтобы записать -2, берём +2 — это 0010, и меняем единички на нолики, а нолики на единички: 1101, вот вам и обратный код.
И на этом месте появляется хохма!
Вот, например, обыкновенный нуль: 0000
Можно из него сделать отрицательный нуль: 1111
Таким образом, у тебя в системе есть два нуля — положительный и отрицательный, и записываются они по-разному 🙂 И если арифметические действия с ними проблем не вызывают, так как на таких компьютерах (-0 == +0) было TRUE, то с побитовыми операциями, хешированием, сортировкой уже возникают эффекты, и к концу 1970х от простого обратного кода (one’s complement) для записи знаковых целых чисел отказались, перейдя на запись дополнительным кодом (two’s complement), в котором нуль как Аллах — один 🙂
Забавно.
PS: А вообще я сталкивался к некоторыми задачами, где мне бы пригодилось наличие двух нулей, отрицательного и положительного. А ещё было бы прикольно записывать этими разными нулями результаты вычисления некоторых пределов — было бы понятнее, с какой стороны предел подкрадывается к нулю: lim (x → -∞) 1/x = -0 😉