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


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

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

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

int num = -0;
int additinon = 5;

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

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

7 92

7 ответов:

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

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

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

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

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

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

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

давайте начнем с представления 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.

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


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

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

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

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

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

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

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

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

в спецификации языка C++, нет такого int как отрицательный нуль.

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

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


напротив, плавающие точки (после 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
    }
}

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

для упрощения я нашел его легче визуализировать.

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

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

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

в случае дополнения значение -0 существует.