Можно ли различать 0 и -0?

Я знаю, что целые значения 0 и -0 по существу одинаковы. Но мне интересно, можно ли различать их.

Например, как узнать, была ли назначена переменная -0?

bool IsNegative(int num)
{
    // How ?
}

int num = -0;
int additinon = 5;

num += (IsNegative(num)) ? -addition : addition;

Сохранено ли значение -0 в памяти точно так же, как 0?

Ответ 1

Это зависит от машины, на которую вы нацеливаете.

На машине, использующей представление 2 дополнение для целых чисел, нет разницы на уровне бит между 0 и -0 (они имеют одинаковое представление)

Если ваша машина использовала один комплект, вы определенно могли

0000 0000   -> signed   0 
1111 1111   -> signed   −0

Очевидно, мы говорим об использовании собственной поддержки, процессоры серии x86 имеют встроенную поддержку двух дополнительных представлений подписанных чисел. Использование других представлений, безусловно, возможно, но, вероятно, будет менее эффективным и потребует больше инструкций.

(Как сказал Джерри Коффин: даже если одно дополнение рассматривается в основном по историческим причинам, подписанные представления величины все еще довольно распространены и имеют отдельный представление для отрицательного и положительного нуля)

Ответ 2

При a int (в почти универсальном представлении "2 комплемента" представления 0 и -0 совпадают. (Они могут отличаться для других представлений чисел, например, с плавающей точкой IEEE 754.)

Ответ 3

Начнем с представления 0 в 2 дополнениях (конечно, существует много других систем и представлений, здесь я имею в виду этот конкретный), предполагая, что 8-бит, ноль:

0000 0000

Теперь позвольте перевернуть все биты и добавить 1, чтобы получить 2 дополнения:

1111 1111 (flip)
0000 0001 (add one)
---------
0000 0000

мы получили 0000 0000, а также представление -0.

Но учтите, что в 1 дополнении подпись 0 равна 0000 0000, но -0 1111 1111.

Ответ 4

Я решил оставить этот ответ, так как реализации C и С++ обычно тесно связаны, но на самом деле он не откладывает стандарт C, как я думал. Дело в том, что в стандарте С++ не указывается, что происходит для таких случаев. Также важно, чтобы представления о не-двойном дополнении были чрезвычайно редки в реальном мире и что даже там, где они существуют, они часто скрывают разницу во многих случаях, а не раскрывают ее как нечто, что можно легко ожидать обнаружить.


Поведение отрицательных нулей в целых представлениях, в которых они существуют, не так строго определено в стандарте С++, как в стандарте C. Однако он ссылается на стандарт C (ISO/IEC 9899: 1999) как нормативную ссылку на верхнем уровне [1.2].

В стандарте C [6.2.6.2] отрицательный ноль может быть только результатом побитовых операций или операций, в которых уже присутствует отрицательный ноль (например, умножение или деление отрицательного нуля на значение или добавление отрицательный ноль до нуля) - применение унарного оператора минус к значению нормального нуля, как в вашем примере, поэтому гарантированно приведет к нормальному нулю.

Даже в случаях, которые могут генерировать отрицательный ноль, нет гарантии, что они будут, даже в системе, которая поддерживает отрицательный ноль:

Неизвестно, действительно ли эти случаи генерируют отрицательный нуль или нормальный нуль, и является ли отрицательный нуль нормальным нулем при хранении в объекте.

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

Стандарт С++, со своей стороны, не упоминает термин "отрицательный ноль" и очень мало обсуждает детали подписанной величины и одного представления дополнений, за исключением примечания [3.9.1, пункт 7], что они разрешены.

Ответ 5

Если ваш аппарат имеет четкие представления для -0 и +0, то memcmp сможет их отличить.

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

Ответ 6

В спецификации языка С++ нет такого int как отрицательный ноль.

Единственное значение, которое имеют эти два слова, - это унарный оператор -, примененный к 0, так же, как три плюс пять - это всего лишь двоичный оператор +, примененный к 3 и 5.

Если бы существовал отличный отрицательный ноль, два дополнения (наиболее распространенное представление целых типов) были бы недостаточным представлением для реализаций С++, так как нет возможности представлять две формы нуля.


Напротив, плавающие точки (после IEEE) имеют отдельные положительные и отрицательные нули. Их можно отличить, например, при делении 1 на них. Положительный ноль создает положительную бесконечность; отрицательный ноль создает отрицательную бесконечность.


Однако, если существуют различные представления памяти для int 0 (или любого int или любого другого значения любого другого типа), вы можете использовать memcmp, чтобы обнаружить, что:

#include <string>

int main() {
    int a = ...
    int b = ...
    if (memcmp(&a, &b, sizeof(int))) {
        // a and b have different representations in memory
    }
}

Конечно, если это произошло, то за пределами операций с прямой память эти два значения будут работать точно так же.

Ответ 7

Чтобы упростить, мне было легче визуализировать.

Тип int (_ 32) сохраняется с 32 бита. 32 бита означают 2 ^ 32 = 4294967296 уникальные значения. Таким образом:

unsigned int диапазон данных от 0 до 4 294 967 295

В случае отрицательных значений это зависит от того, как они хранятся. В случае

В случае Один дополнительный значение -0 существует.