Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is minus zero (-0) equivalent to zero (0) in C#

Tags:

c#

Is minus zero (-0) equivalent to zero (0) in C#?

like image 748
Ben Aston Avatar asked Jun 29 '10 09:06

Ben Aston


People also ask

Is zero and minus zero the same?

Signed zero is zero with an associated sign. In ordinary arithmetic, the number 0 does not have a sign, so that −0, +0 and 0 are identical.

Is negative zero a thing?

There's no such thing as negative zero. For a binary integer, setting the sign bit to 1 and all other bits to zero, you get the smallest negative value for that integer size. (Assuming signed numbers.) Negative zero is actually used in mathematical analysis, especially in limit calculations.

How is zero equal to its negative?

1 and –1are the rational numbers that are equal to their reciprocals. (iii). 0 is the rational number that is equal to its negative. Hence our answer is, 0 is the rational number that is equal to its negative.

Is zero positive or negative programming?

Zero, 0, is neither positive nor negative.


2 Answers

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 
like image 158
Lucero Avatar answered Sep 18 '22 16:09

Lucero


It sounds like you're looking for the edge cases where they aren't interchangeable, so here are some examples.

object.Equals on structs

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

Inversion

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

Explicit byte conversion

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 } >  

A note on irregular decimal representations

The 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.

Bonus: Subnormal numbers

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".

like image 29
Matt Tsōnto Avatar answered Sep 20 '22 16:09

Matt Tsōnto