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

94

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

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

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

int num = -0;
int additinon = 5;

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

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

Филип Минкс
источник
9
Для целых чисел разницы нет.
Maroun
14
Это зависит от реализации, но для реализаций, которые intпредставлены в виде двух дополнений (наиболее часто встречающихся) 0и -0имеют идентичные побитовые представления.
Mankarse
11
На машине с дополнением до 2 нет разницы на битовом уровне.
Марко А.
17
@VirtualSnake: Что означает «в двоичном формате»? Есть, на самом деле, бинарные кодировки , для которых есть различие между 0 и 0. Знак и величиной, например.
Бенджамин Линдли
8
@VirtualSnake Правильно, мы говорим int. См. Дополнительное кодирование Единиц .
CiaPan

Ответы:

112

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

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

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

0000 0000   -> signed01111 1111   -> signed   0

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

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

Марко А.
источник
6
@TobiMcNamobi: Скорее всего, не стоит беспокоиться. Я был бы удивлен, если бы кто-нибудь когда-нибудь потрудился портировать компилятор C ++ для вывода на такую ​​машину.
Бенджамин Линдли
1
Я согласен с Бенджамином, исторически были машины, использующие его, но в настоящее время я не знаю производственных машин, которые его используют. Тем не менее всегда полезно знать и помнить.
Марко А.
4
Дополнение @TobiMcNamobi до сих пор используется в системе UNISYS 2200 stackoverflow.com/a/12277974/995714 stackoverflow.com/q/6971886/995714
phuclv
2
Я никогда не смотрел на требования своих комплемента - делает стандарт фактически гарантией того, что 0и -0являются разные ? Честно говоря, я ожидал, что он будет вести себя больше как разрешение двухбитовых представлений одного и того же значения, и ваша программа может использовать любое из них, которое ей нравится.
8
@Hurkly: нет, даже если существует отрицательное нулевое представление, стандарт не гарантирует, что присвоение или инициализация с использованием выражения -0, то есть результат применения унарного -оператора к целочисленной константе 0, является отрицательным нулевым представлением. Независимо от представления, в стандарте никогда не говорится 0и -0математически разные значения, только то, что может быть битовый шаблон отрицательного нуля. Если есть, то оно по-прежнему представляет собой то же числовое значение, 0.
Стив Джессоп
14

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

РичиХиндл
источник
9
>> Предполагая представление с дополнением до 2
Марко А.
12

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

0000 0000

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

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

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

Но обратите внимание, что в дополнении до 1 знаковый 0 - это 0000 0000, а -0 - 1111 1111.

Марун
источник
1
Могу ли я узнать, почему я опускаюсь, чтобы улучшить свой ответ?
Maroun
1
Хотя большинство других ответов технически верны, ваш ответ практичен и обеспечивает реализацию. Хорошо.
umlcat
9

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


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

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

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

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

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

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

Случайный832
источник
В общем, нет, тот факт, что что-то верно / требуется в C , не обязательно означает, что это правда / требуется в C ++. Тот факт, что C является нормативной ссылкой, означает, что C ++ относится к стандарту C для различных вещей (в основном, содержимого стандартных заголовков), но определение целочисленных типов не входит в их число. Однако отсутствие гарантированного способа получения отрицательного нуля означает, что то, что вы делаете, все еще верно, нет надежного способа сгенерировать его с помощью арифметики, даже если представление существует.
Стив Джессоп,
Тогда почему в стандарте C ++ гораздо меньше подробностей о подобных вещах?
Random832
1
Личный вкус, я думаю, если количество людей, голосующих по стандарту C ++, можно считать «личным» :-) Однако, если он собирался подчиниться стандарту C для определений, то он мог бы справиться с этим должным образом. и не содержат не подробно, как это происходит в некоторых других случаях.
Стив Джессоп,
Есть ли «C ++ - это язык программирования общего назначения, основанный на языке программирования C, как описано в ISO / IEC 9899: 1999« Языки программирования - C »(далее именуемые стандартом C)». [1.1 абз. 2] имеют какое-либо нормативное значение? Я думал, что это было предназначено для включения стандарта C для всего, что специально не отменяется стандартом C ++.
Random832
@ Random832 Нет. Это просто историческая справка (например, в C ++ нет _Boolили _Complexили назначенных инициализаторов, или составных литералов). Стандарт C ++ знает, как включить стандарт C, когда он этого хочет - например, [basic.fundamental] / p3: «Целочисленные типы со знаком и без знака должны удовлетворять ограничениям, приведенным в стандарте C, раздел 5.2.4.2.1».
TC
8

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

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

Бен Фойгт
источник
5

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

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

Если бы существовал отчетливый отрицательный ноль , дополнение до двух (наиболее распространенное представление целочисленных типов) было бы недостаточным представлением для реализаций 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
    }
}

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

Пол Дрейпер
источник
3
На самом деле, язык, не требующий его существования, не означает, что он требует его отсутствия. Подсказка: это не требует ни того, ни другого.
Дедупликатор
2
@ Дедупликатор, вроде того. Под «на языке C ++» я имею в виду «в спецификации языка C ++ ». Поскольку в спецификации также нет упоминания о фробинаторах, я мог бы без особой двусмысленности сказать, что «C ++ не имеет фробинаторов». Я думал, что это ясно, но я исправлю это.
Пол Дрейпер
1
В спецификации языка единорогов также не упоминается.
ypercubeᵀᴹ
2

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

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

диапазон данных unsigned int от 0 до 4294967295

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

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

Маргус
источник
2
Я не голосовал против, но платформы, для которых intне хранятся 32 бита, в настоящее время более популярны, чем платформы с одним дополнением.
Maciej Piechotka