在C#中,负零(-0)是否等同于零(0)?
在C#中,负零(-0)是否等同于零(0)?
对于整数来说,不存在二进制表示法可以区分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));
返回:
0 == 0 -> True
Binary representation is equal: False
double negativeZero = -0.0
的结果与其他相同,这意味着常量 -0.0
被正确地解析为 double 类型的 "负零" 值。 - Lucero听起来你想知道它们不能互换的边缘情况,这里有一些例子。
struct
上的object.Equals
> 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
-∞
>
任何类型的显式按字节或按位进行分解,当然也包括类型判断。以下示例来自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 }
>
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 }
>
十进制
表示法的说明十进制
类型本身没有负零,但它确实有多个二进制表示形式的零:
> 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#编程语言》表示它们被认为是“有效的非零值”。
对于小数,至少有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 }
来源:十进制负零表示法
negativeZero1
和 negativeZero3
在我的看法中看起来非常相似? - Lucero十进制
中,0有256种表示方法(或多或少),其中大约一半具有符号位设置。 - Matt Tsōnto