Reputation: 55759
Is minus zero (-0) equivalent to zero (0) in C#?
Upvotes: 30
Views: 16472
Reputation: 138097
For Decimals, there are at least 4 types of zeros:
Decimal zero = Decimal.Zero;
Decimal negativeZero1 = new Decimal(0, 0, 0, true, 0);
Decimal negativeZero2 = -0.0m;
Decimal negativeZero3 = Decimal.Negate(Decimal.Zero);
While all are equal and printed out as "0"
, they have different bit representation:
zero: {0x00000000 00000000 00000000 00000000 }
negativeZero1: {0x00000000 00000000 00000000 80000000 }
negativeZero2: {0x00000000 00000000 00000000 80010000 }
negativeZero3: {0x00000000 00000000 00000000 80000000 }
Source: Decimal Negative Zero Representation
Upvotes: 13
Reputation: 1701
It sounds like you're looking for the edge cases where they aren't interchangeable, so here are some examples.
object.Equals
on struct
s> 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
-∞
>
Any type of explicit byte-wise or bit-wise deconstruction, of course, or type punning. These examples are from a 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
Despite what you might expect, Math.Sign
does not distinguish between negative and positive zero. It only tells you whether a number is equal to, greater than, or less than 0.
> Math.Sign(-0f)
0
Math.Min
and Math.Max
A few arithmetic operations have edge cases for -0. One interesting one is Math.Min
(and equivalently for max), which is that when comparing signed zeros it returns the second one. So:
> 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
representationsThe decimal
type doesn't have a negative 0 per se, but it does have multiple binary representations for zero:
> new decimal(new int[4] { 0, 0, 0, 0 })
0
> new decimal(new int[4] { 0, 0, 0, -2147483648 })
0
>
The second example there could be considered a negative zero because it's bitwise-identical to the regular zero except with the negation bit set. But as far as the formatter's concerned it's just a zero. There are, in fact dozens of zero representations for decimal
, for different decimal point shifts, all of which are arithmetically equivalent and display as 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
That said, you'll only be able to distinguish them from each other by binary-comparison or binary-conversion means. From just experimentation, it seems that the struct
trick above doesn't work on them. Math.Min
returns whichever zero was given second.
Certain patterns of bits in float
and double
types represent subnormal (aka denormal) values. I won't go into what they are—see the link instead—but the important thing to know is that the CLI spec explicitly declares their operations as implementation-specific. I don't know that there are platforms that treat them as 0, but there could be. On the other hand, The C# Programming Language says that they're "considered valid non-zero values".
Upvotes: 16
Reputation: 60236
For integers, there is no binary representation that makes a difference between 0 and -0, so they are by definition equal.
For IEEE floating-point numbers, there is a distinction of negative and positive zero. I made some tests (CLR of .NET Framework 2.0, C# 3) and it seems that they are considered equal, which is actually the behavior expected according to the IEEE 754 standard.
Here's my test code to show that:
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));
Returns:
0 == 0 -> True
Binary representation is equal: False
Upvotes: 37