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)
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)
来源:十进制负零表示
听起来您正在寻找不可互换的边缘情况,因此这里有一些示例。
object.Equals在structs> 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.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 }
>
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 float和doubletype中的某些位模式表示次正规(aka非正规)值。我将不讨论它们的含义,而是查看链接,但是要知道的重要一点是,CLI规范明确将其操作声明为特定于实现的。我不知道有平台会将其视为0,但可能存在。另一方面,C#编程语言说它们“被认为是有效的非零值”。