Является ли минус ноль (-0) эквивалентно нулю (0) в C # - PullRequest
25 голосов
/ 29 июня 2010

Является ли минус ноль (-0) эквивалентным нулю (0) в C #?

Ответы [ 4 ]

31 голосов
/ 29 июня 2010

Для целых чисел не существует двоичного представления, которое делает разницу между 0 и -0, поэтому они по определению равны.

Для чисел с плавающей запятой IEEE существует различие отрицательного и положительного нуля,Я провел несколько тестов (CLR .NET Framework 2.0, C # 3), и кажется, что они считаются равными, что на самом деле является поведением, ожидаемым в соответствии со стандартом IEEE 754.

Вот мой тестовый код, чтобы показать, что:

    double minusOne = -1.0;
    double positiveZero = 0.0;
    double negativeZero = minusOne*positiveZero;
    Console.WriteLine("{0} == {1} -> {2}", positiveZero, negativeZero, positiveZero == negativeZero);
    Console.WriteLine("Binary representation is equal: {0}", BitConverter.DoubleToInt64Bits(positiveZero) == BitConverter.DoubleToInt64Bits(negativeZero));

Возвращает:

0 == 0 -> True
Binary representation is equal: False
12 голосов
/ 29 июня 2010

Для десятичных чисел есть как минимум 4 типа нулей:

Decimal zero = Decimal.Zero;
Decimal negativeZero1 = new Decimal(0, 0, 0, true, 0);
Decimal negativeZero2 = -0.0m;
Decimal negativeZero3 = Decimal.Negate(Decimal.Zero);

Хотя все они равны и распечатываются как "0", они имеют различное битовое представление:

zero:          {0x00000000 00000000 00000000 00000000 }
negativeZero1: {0x00000000 00000000 00000000 80000000 }
negativeZero2: {0x00000000 00000000 00000000 80010000 }
negativeZero3: {0x00000000 00000000 00000000 80000000 }

Источник: Десятичное отрицательное представление с нулем

4 голосов
/ 05 июня 2018

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

object.Equals на struct с

> struct SomeStruct { public double X; }
> var a = new SomeStruct { X = 0d };
> var b = new SomeStruct { X = -0d };
> a.Equals(b)
false
>

Инверсия

> 1/0d
∞
> 1/-0d
-∞
>

Явное преобразование байтов

Любой тип явной побитовой или побитовой деконструкции, конечно, или тип Punning.Эти примеры с ПК:

> BitConverter.GetBytes(0d)
byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 }
> BitConverter.GetBytes(-0d)
byte[8] { 0, 0, 0, 0, 0, 0, 0, 128 }
> 

Math.Sign

Несмотря на то, что вы можете ожидать, Math.Sign не не различает отрицательный и положительный ноль.Он только сообщает вам, равно ли число, больше или меньше 0.

> Math.Sign(-0f)
0 

Math.Min и Math.Max

Некоторые арифметические операции имеют крайние случаи для -0.Один интересный - Math.Min (и эквивалентно для max), который заключается в том, что при сравнении нулей со знаком он возвращает второй.Итак:

> BitConverter.GetBytes(Math.Min(0.0, -0.0))
byte[8] { 0, 0, 0, 0, 0, 0, 0, 128 }
> BitConverter.GetBytes(Math.Min(-0.0, 0.0))
byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 }
> 

Примечание о нерегулярных decimal представлениях

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

> new decimal(new int[4] { 0, 0, 0, 0 })
0
> new decimal(new int[4] { 0, 0, 0, -2147483648 })
0
> 

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

> new decimal(new int[4] { 0, 0, 0, 131072 })
0.00
> new decimal(new int[4] { 0, 0, 0, 1835008 })
0.0000000000000000000000000000
> new decimal(new int[4] { 0, 0, 0, 65536 })
0.0

Тем не менее, вы сможете толькоотличать их друг от друга средствами двоичного сравнения или двоичного преобразования.Из экспериментов видно, что вышеприведенный трюк struct на них не работает.Math.Min возвращает, какой бы ни был дан ноль в секунду.

Бонус: Субнормальные числа

Определенные комбинации битов в типах float и double представляют субнормальные (иначе денормалированные)) ценности.Я не буду вдаваться в то, что они есть - вместо этого посмотрите ссылку - но важно знать, что спецификация CLI явно объявляет их операции как специфичные для реализации.Я не знаю , что существуют платформы, которые рассматривают их как 0, но может быть.С другой стороны, Язык программирования C # говорит, что они "считаются действительными ненулевыми значениями".

1 голос
/ 29 июня 2010
if (-0 == 0) Console.WriteLine("YES, it is!");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...