Можно ли различать 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
В случае отрицательных значений это зависит от того, как они хранятся. В случае
- Два дополнения -2,147,483,648 до 2,147,483,647
- Один дополнительный вариант -2,147,483,647 до 2,147,483,647
В случае Один дополнительный значение -0 существует.