7

I was playing with decimal today. I noticed this:

Decimal.MaxValue 
79228162514264337593543950335

Decimal.MaxValue - 0.5m
79228162514264337593543950334

The following code prints true.

static void Main(string[] args)
        {
            decimal d = Decimal.MaxValue - 0.5M;
            var b = d % 1 == 0;
            Console.WriteLine(b);

        }

I am sure there is a reason behind this but I don't know what it is.

chikak
  • 1,702
  • 1
  • 18
  • 21

3 Answers3

13

The decimal type uses 96 bits to store the sequence of digits (ref), plus a sign (1 bit) and a scaling factor that specifies the location of the decimal place.

For this decimal number:

79228162514264337593543950335

All 96 bits are used to the left of the decimal point - there's nothing left to represent the fractional part of the answer. So, it gets rounded.

If you divide the number by 10:

7922816251426433759354395033.5

Then you have a few bits available to represent the fractional part - but only to 1/10, no finer.

The key difference between decimal and double/float is that it is based on a decimal scaling factor specifying the location of a decimal point; the other floating types are based on a binary scaling factor specifying the location of a binary point.

Bevan
  • 43,618
  • 10
  • 81
  • 133
  • 1
    If you were right about the result being rounded instead of the operands, the result would be 79228162514264337593543950335 not 79228162514264337593543950334, because 79228162514264337593543950334.5 rounds upwards. – Anton Tykhyy Aug 17 '10 at 11:12
  • I did some calculation myself and this answer sounds correct. – chikak Aug 17 '10 at 12:47
  • 4
    @Anton - the `decimal` type is primarily intended for handling amounts of money/currency, one area where people tend to notice the flaws of double/float. For that reason, `decimal` uses *Bankers Rounding* (see http://en.wikipedia.org/wiki/Rounding). Why? Always rounding 0.5 up gives a statistical bias that causes a small amount of overstating, especially significant when totalling a column of rounded values. Bankers rounding avoids this by rounding 0.5 to the *nearest even value*. So, 3.5 rounds to 4.0; 4.5 also rounds to 4.0. – Bevan Aug 18 '10 at 01:34
1

0.5 is being rounded before subtraction. decimal strives to make the result as precise as possible, so the operation becomes 79228162514264337593543950335 - 00000000000000000000000000000.5. But 0.5 cannot be represented as a decimal of the required precision and is rounded upwards to 1.

Anton Tykhyy
  • 19,370
  • 5
  • 54
  • 56
0

It is not an integer, it is in fact a Decimal.

Integers (Int32) can have values from negative 2,147,483,648 positive 2,147,483,647.

As you can see, this is well out of these ranges.

In term of the display and accuracy, 79228162514264337593543950334.5 cannot be represented by Decimal.

Read this for more details (What Every Computer Scientist Should Know About Floating-Point Arithmetic).

alanc
  • 4,102
  • 21
  • 24
Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • 2
    Integer and `int`/`Int32` aren't necessarily synonyms. – LukeH Aug 17 '10 at 09:26
  • -1 because following code prints True. decimal d = Decimal.MaxValue - 0.5M; b = d % 1 == 0; Console.WriteLine(b); – chikak Aug 17 '10 at 09:27
  • 1
    @chikak - That doesn't make it an integer. `var d = decimal.MaxValue - 0.5M; Console.WriteLine(typeof(decimal).ToString());` prints out `System.Decimal`. – Oded Aug 17 '10 at 09:31
  • 2
    @Oded, @chikak: You're arguing about semantics. An integer is a whole number. The result in this case is an integer but it's stored in a `decimal` variable. If I type `decimal foo = 9876543210;` then `foo` is a `decimal`, but that doesn't magically mean that `9876543210` is no longer an integer. – LukeH Aug 17 '10 at 09:35
  • I know it is a decimal and can't fit into an int variable. What I meant was that the result should have a decimal point in it. Why can't 79228162514264337593543950334.5 fit into a decimal? I am reading the link you gave but it is a bit long document :-) – chikak Aug 17 '10 at 09:37
  • @LukeH I agree with your comment. – chikak Aug 17 '10 at 09:38