Как std:: cout печатает отрицательный ноль в системе с одним дополнением?
На платформе с одним дополнением, что будет печатать следующий код?
#include <iostream>
int main() {
int i = 1, j = -1;
std::cout << i+j << std::endl;
return 0;
}
Я бы заподозрил, что напечатал бы "0" вместо "-0", но я не могу найти ничего авторитетного.
Изменить: Чтобы уточнить, меня интересует, как -0 будет напечатано, несколько человек предположили, что на практике реализация одних-комплиментов может не генерировать отрицательный ноль с вышеуказанным кодом.
В этих случаях было предложено фактически создать a -0:
#include <iostream>
int main() {
std::cout << ~0 << std::endl;
return 0;
}
Остается вопрос: что будет печатать?
Ответы
Ответ 1
Прежде всего, просто для выяснения сути, обработка отрицательного нуля с помощью побитовых операций, а затем использование полученного значения не является переносимым. Тем не менее, ничто не указывает в документации fprintf
(таким образом, из std::basic_ostream::operator<<(int)
), является ли знаковый бит в представлении int бит заполнения в представлении unsigned
или бит фактического значения.
Как вывод, это неопределенное поведение.
#include <iostream>
int main() {
std::cout << ~0 << std::endl;
return 0;
}
Ответ 2
Действительно, добавление n
в -n
должно дать вам отрицательный ноль. Но генерация -0 не происходит на практике, поскольку в дополнение к дополнению используется метод, называемый дополняющим вычитателем (второй аргумент дополняется и вычитается из первого).
(Идиоматический способ получения подписанной нулевой точки с плавающей точкой здесь не применяется, так как вы не можете разделить целое на ноль).
Ответ 3
Просматривая исходный код glibc, я нашел эти строки в файле vfprintf.c:
532 is_negative = signed_number < 0; \
533 number.word = is_negative ? (- signed_number) : signed_number; \
534 \
535 goto LABEL (number); \
...
683 if (is_negative) \
684 outchar (L_('-')); \
Таким образом, казалось бы, что условие signed_number < 0
, которое вернет false для a -0
.
как указано в @Ysc, ничто в документации не дает никаких спецификаций для печати -0
, поэтому другая реализация платформы libc (на одном-комплименте) может дать другой результат.
Ответ 4
Если мы рассмотрим теоретическую точку одного дополнения. Поскольку нуль определяется как (+/-) 0, будет два двоичных значения для 0, если мы имеем 4 битовых значения, ноль будет 0000 (+0) и 1111 (-0). В результате этого вам всегда нужно делать коррекцию, если операция, сложение или подделка имеет операцию пересечения нуля.
Так, например, если мы выполним следующую операцию -2+6=4
, результат будет вычисляться следующим образом:
1101 (-2)
+ 0110 (6)
------
1100 (add carry)
======
0011 (+3)
Как вы можете видеть в операции Бит результат неверен и является лишь неполным результатом. В этом случае мы должны добавить +1 к значению, чтобы получить правильный результат. Чтобы определить, нужно ли добавить +1, мы должны взглянуть на результат переноса переноса. Если самый левый номер 1 100 равен ONE, мы должны добавить +1 к результату, чтобы получить правильный результат.
Если мы посмотрим на ваш пример:
0001 (+1)
+ 1110 (-1)
------
0000 (add carry)
======
1111 (-0)
Мы видим, что результат будет -0, и это будет конечный результат, потому что бит переноса слева слева равен 0.