Decimal Negative Zero Representation [Lakshan Fernando]

One of our customers wondered recently if we represent negative zero in Decimal. At first glance, it doesn’t look to be the case as seen below;

   Decimal zero = Decimal.Zero;

   Decimal negativeZero_1 = new Decimal(0, 0, 0, true, 0);
   Decimal negativeZero_2 = -0.0m;    Decimal negativeZero_3 = Decimal.Negate(Decimal.Zero);

   Console.WriteLine("Negative Zero: {0}, {1}, {2} Positive Zero: {3}", negativeZero_1, negativeZero_2, negativeZero_3, zero);
   Console.WriteLine("Negative and Positive Zero comparison: {0}", zero.CompareTo(negativeZero_1));

Will output

Negative Zero: 0, 0, 0 Positive Zero: 0
Negative and Positive Zero comparison: 0

But we do recognize negative zero and persist the information in the bit representation and can be seen via the Decimal.GetBits method. Calling the following method for the above 4 Decimal values,

   public staticString HexValue(Decimal value)
       Int32[] bits = Decimal.GetBits(value);
       return String.Format("{{0x{0:X8} {1:X8} {2:X8} {3:X8} }}", bits[0], bits[1], bits[2], bits[3]);

Will output,

zero: {0x00000000 00000000 00000000 00000000 }
negativeZero_1: {0x00000000 00000000 00000000 80000000 }
negativeZero_2: {0x00000000 00000000 00000000 80010000 }
negativeZero_3: {0x00000000 00000000 00000000 80000000 }

We don’t show a negative decimal in the ToString() method because it was considered more clean to do it this way.  Some applications depend on zero printing as “0” whether it is “positive” or “negative” zero.  Likewise, the two decimals compare Equal, because they represent the same value, regardless of scale or sign (see also  Our documentation for Decimal.GetBits mentions the bit representation for Negative zero. BTW, C# compiler does not treat “-0m” as negative zero, although it does get both the sign and the scale correctly for “-0.0m”

It would be interesting to know of any applications build on top of this.

Comments (3)

  1. WillSmith says:

    Keep up the good work.  This blog to me is one of the most important.  And BTW, please continue to evolve and improve the Decimal class.  An example, impliment a Decminal sepecific Pow method.  Decimal::Pow().  The Math::Pow() uses doubles.  Precision is lost, or at least I can’t control it.

  2. Somewhere in between zero and the smallest possible negative number there lies another number. NEGATIVE

  3. The weirdness is easily noted if you try the following code in both .NET <= 1.1 and .NET >= 2.0:

Skip to main content