C#中的零(-0)等于零(0)

Ben*_*Ben 25 c#

C#中的零(-0)等于零(0)?

Luc*_*ero 31

对于整数,没有二进制表示形式在0和-0之间产生差异,因此根据定义它们是相等的.

对于IEEE浮点数,存在负零和正零的区别.我做了一些测试(.NET Framework 2.0的CLR,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));
Run Code Online (Sandbox Code Playgroud)

返回:

0 == 0 -> True
Binary representation is equal: False
Run Code Online (Sandbox Code Playgroud)

  • `double negativeZero = -0.0`也产生相同的结果,这意味着常量`-0.0`被正确解析为double的"负零"值. (3认同)

Kob*_*obi 12

对于小数,至少有4种类型的零:

Decimal zero = Decimal.Zero;
Decimal negativeZero1 = new Decimal(0, 0, 0, true, 0);
Decimal negativeZero2 = -0.0m;
Decimal negativeZero3 = Decimal.Negate(Decimal.Zero);
Run Code Online (Sandbox Code Playgroud)

虽然所有都是相同的并且打印出来"0",但它们具有不同的位表示:

zero:          {0x00000000 00000000 00000000 00000000 }
negativeZero1: {0x00000000 00000000 00000000 80000000 }
negativeZero2: {0x00000000 00000000 00000000 80010000 }
negativeZero3: {0x00000000 00000000 00000000 80000000 }
Run Code Online (Sandbox Code Playgroud)

来源:十进制负零表示

  • +1 - 但是:你的二进制`negativeZero1`和`negativeZero3`对我看起来几乎一样? (9认同)

Emd*_*dot 5

听起来您正在寻找不可互换的边缘情况,因此这里有一些示例。

object.Equalsstructs

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

反演

> 1/0d
?
> 1/-0d
-?
>
Run Code Online (Sandbox Code Playgroud)

显式字节转换

当然,任何类型的显式字节分解或按位分解都可以,或者类型为punning。这些示例来自PC:

> 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 }
> 
Run Code Online (Sandbox Code Playgroud)

Math.Sign

尽管您可能会期望,Math.Sign不能区分负零和正零。它只会告诉您数字是否等于,大于或小于0。

> Math.Sign(-0f)
0 
Run Code Online (Sandbox Code Playgroud)

Math.MinMath.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 }
> 
Run Code Online (Sandbox Code Playgroud)

关于不规则decimal陈述的说明

decimal类型本身并不具有负0,但它确实具有多个二进制表示为零的值:

> new decimal(new int[4] { 0, 0, 0, 0 })
0
> new decimal(new int[4] { 0, 0, 0, -2147483648 })
0
> 
Run Code Online (Sandbox Code Playgroud)

第二个示例可以被视为负零,因为它与常规零在位上相同,但设置了否定位除外。但是就格式化程序而言,它只是一个零。实际上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
Run Code Online (Sandbox Code Playgroud)

也就是说,您只能通过二进制比较或二进制转换的方式将它们彼此区分开。从实验来看,struct上面的技巧似乎不适用于它们。Math.Min返回第二个零。

奖励:次正规数

in floatdoubletype中的某些位模式表示次正规(aka非正规)值。我将不讨论它们的含义,而是查看链接,但是要知道的重要一点是,CLI规范明确将其操作声明为特定于实现的。我不知道有平台会将其视为0,但可能存在。另一方面,C#编程语言说它们“被认为是有效的非零值”。