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

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

Например, как узнать, присвоено ли переменной значение -0?

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

int num = -0;
int additinon = 5;

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

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


person Filip Minx    schedule 30.04.2015    source источник
comment
Почему бы вам не проверить бит знака?   -  person tema    schedule 30.04.2015
comment
Для целых чисел разницы нет.   -  person Maroun    schedule 30.04.2015
comment
Это зависит от реализации, но для реализаций, где int представлено в дополнении до 2 (наиболее часто встречающееся), 0 и -0 имеют идентичные побитовые представления.   -  person Mankarse    schedule 30.04.2015
comment
На машине с дополнением до 2 нет разницы на битовом уровне.   -  person Marco A.    schedule 30.04.2015
comment
Нет, это нереально. В двоичном формате -0 и 0 представляют одинаково   -  person VirtualSnake    schedule 30.04.2015
comment
Нет, это невозможно. Там нет -0 ... поэтому длинный диапазон идет от -2 147 483 648 до 2 147 483 647 ... вы можете видеть, что нижний диапазон имеет на единицу не больше, чем верхний диапазон.   -  person Mr.Yellow    schedule 30.04.2015
comment
@VirtualSnake: Что значит в двоичном формате? На самом деле существуют двоичные кодировки, для которых существует различие между -0 и 0. Например, знак и величина.   -  person Benjamin Lindley    schedule 30.04.2015
comment
@BenjaminLindley Конечно, но мы говорим о int   -  person VirtualSnake    schedule 30.04.2015
comment
@VirtualSnake Верно, мы говорим о int. См. дополнительное кодирование единиц.   -  person CiaPan    schedule 30.04.2015
comment
Если бы вы использовали числа с плавающей запятой, была бы разница... Но с целыми числами в сценариях реальной жизни (2-s дополнительные машины) нет никакой разницы   -  person Mints97    schedule 30.04.2015
comment
целочисленные значения 0 и -0 практически одинаковы. По крайней мере, в математике они абсолютно одинаковы. Ожидаете ли вы также различных представлений для 1 и -(-1)? (и еще один для -(-(-(-1))), ...)   -  person ypercubeᵀᴹ    schedule 06.05.2015


Ответы (7)


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

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

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

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

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

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

person Marco A.    schedule 30.04.2015
comment
Можете ли вы сказать, насколько вероятно наличие комплемента? Является ли он достаточно экзотичным и на каких машинах он есть? Есть ли преимущество у такого представления или оно только менее эффективно? - person TobiMcNamobi; 30.04.2015
comment
@TobiMcNamobi: Вряд ли стоит об этом беспокоиться. Я был бы удивлен, если бы кто-нибудь когда-либо удосужился портировать компилятор C++ для получения вывода для такой машины. - person Benjamin Lindley; 30.04.2015
comment
Я согласен с Бенджамином, исторически его использовали машины, но в настоящее время я не Случайно не знаю производственных машин, которые его используют. Тем не менее всегда полезно знать и иметь в виду. - person Marco A.; 30.04.2015
comment
Дополнение @TobiMcNamobi до сих пор используется в системе UNISYS 2200 stackoverflow.com/a/12277974/995714 stackoverflow.com/q/6971886/995714 - person phuclv; 30.04.2015
comment
Я никогда не смотрел на требования к дополнению - действительно ли стандарт гарантирует, что 0 и -0 различны? Честно говоря, я ожидал, что поведение будет больше похоже на двухбитовое представление одного и того же значения, и ваша программа может использовать любое из них. - person ; 30.04.2015
comment
@Hurkly: нет, даже если существует отрицательное нулевое представление, стандарт не гарантирует, что присваивание или инициализация с использованием выражения -0, то есть результат применения унарного оператора - к целочисленной константе 0, является отрицательным нулем представление. Независимо от представления стандарт никогда не говорит, что 0 и -0 являются математически разными значениями, а только то, что может быть битовый шаблон с отрицательным нулем. Если есть, он по-прежнему представляет то же числовое значение, 0. - person Steve Jessop; 30.04.2015
comment
@SteveJessop Если использование стандарта C в качестве общей нормативной ссылки означает, что он применим здесь, то фактически он гарантирует, что он не является отрицательным нулем. Смотрите мой ответ. - person Random832; 30.04.2015
comment
Хотя вы ответили про -0 и 0, на самом деле вопрос был о коде, который сохраняет такое значение в переменную. У меня есть вопрос: действительно ли компиляторы для процессоров со знаком различают значения представления при выполнении оптимизации (что усложняет задачу для кросс-компиляторов)? Или такие компиляторы будут постоянно распространять -0 во время компиляции и в конечном итоге получат битовое представление 0...0b, переданное IsNegative? Какие здесь гарантии архитектуры и компилятора? - person Johannes Schaub - litb; 01.05.2015
comment
Обратите внимание, что меня не столько интересует C-Standard (который оставляет его неуказанным или определенная реализация, не уверен), сколько фактические гарантии реализации. - person Johannes Schaub - litb; 01.05.2015

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

person RichieHindle    schedule 30.04.2015
comment
›› Предполагая представление с дополнением до 2 - person Marco A.; 30.04.2015

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

person Maroun    schedule 30.04.2015
comment
Могу ли я узнать, почему отрицательные голоса, чтобы улучшить мой ответ, пожалуйста? - person Maroun; 30.04.2015
comment
Хотя большинство других ответов технически правильны, ваш ответ практичен и обеспечивает реализацию. Хорошо. - person umlcat; 06.05.2015

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


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

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

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

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

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

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

person Random832    schedule 30.04.2015
comment
В общем нет, тот факт, что что-то истинно/требуется в C, не обязательно означает, что это истинно/требуется в C++. Тот факт, что C является нормативной ссылкой, означает, что C++ ссылается на стандарт C для различных вещей (в основном содержимого стандартных заголовков), но определение целочисленных типов не является одной из таких вещей. Однако отсутствие гарантированного способа получить отрицательный нуль означает, что ваш вывод по-прежнему верен, нет надежного способа сгенерировать его с помощью арифметики, даже если представление существует. - person Steve Jessop; 01.05.2015
comment
Тогда почему в стандарте С++ так мало подробностей о подобных вещах? - person Random832; 01.05.2015
comment
Я думаю, что личный вкус, если количество людей, голосующих по стандарту C++, можно считать личным :-) Однако, если бы он собирался полагаться на стандарт C для определений, тогда он мог бы сделать это должным образом и содержать никаких подробностей, как это бывает в некоторых других случаях. - person Steve Jessop; 01.05.2015
comment
Является ли C++ языком программирования общего назначения, основанным на языке программирования C, как описано в стандарте ISO/IEC 9899:1999 «Языки программирования — C» (далее — стандарт C). [1.1 пункт 2] имеют какое-либо нормативное значение? Я думал, что это было предназначено для того, чтобы в целом включить стандарт C для всего, что не было специально переопределено стандартом C++. - person Random832; 01.05.2015
comment
@ Random832 Нет. Это просто историческое примечание (например, в C++ нет _Bool или _Complex или назначенных инициализаторов или составных литералов). Стандарт C++ знает, как включить стандарт C, когда он захочет, например, [basic.fundamental]/p3: целые типы со знаком и без знака должны удовлетворять ограничениям, указанным в стандарте C, раздел 5.2.4.2.1. - person T.C.; 01.05.2015

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

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

person Ben Voigt    schedule 30.04.2015

В спецификации языка 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
    }
}

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

person Paul Draper    schedule 30.04.2015
comment
На самом деле, язык, не предписывающий его существование, не означает, что он предписывает его отсутствие. Подсказка: это не требует ни того, ни другого. - person Deduplicator; 30.04.2015
comment
@Дедупликатор, вроде того. Под языком C++ я имею в виду спецификацию языка C++. Поскольку в спецификации также нет упоминания о фробинаторах, я мог бы сказать, что в C++ нет фробинаторов без особой двусмысленности. Я думал, что это было ясно, но я улучшу это. - person Paul Draper; 30.04.2015
comment
В спецификации языка также не упоминаются единороги. - person ypercubeᵀᴹ; 06.05.2015

Для упрощения мне было легче визуализировать.

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

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

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

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

person Margus    schedule 30.04.2015
comment
Я не минусовал, но платформы, для которых int не хранится в 32 битах, в настоящее время более популярны, чем платформы с одним дополнением. - person Maciej Piechotka; 01.05.2015