Можно ли отличить 0 от -0?
Я знаю, что целочисленные значения 0
и -0
по существу то же самое.
Но мне интересно, можно ли их различать.
например, как узнать, была ли присвоена переменная -0
?
bool IsNegative(int num)
{
// How ?
}
int num = -0;
int additinon = 5;
num += (IsNegative(num)) ? -addition : addition;
значение -0
сохраненные в памяти точно так же, как 0
?
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
в случае отрицательных значений зависит от того, как они хранятся. На всякий случай
- дополнение -2,147,483,648 to 2,147,483,647
- дополнения -2,147,483,647 до 2,147,483,647
в случае дополнения значение -0 существует.