Подтвердить что ты не робот

Как 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;
}

Остается вопрос: что будет печатать?

4b9b3361

Ответ 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.