Oenone said:
Can anyone explain why the following happens?
\\\
Dim d1 As Decimal = CDec("100")
Dim d2 As Decimal = CDec("100.00")
MsgBox(d1.ToString) 'displays "100"
MsgBox(d2.ToString) 'displays "100.00"
MsgBox(d1 = d2) 'displays "True"
///
How are the Decimal variables remembering the fact that I provided the two
decimal places for d2, but not for d1? I can't see any properties of the
Decimal structure that would allow it to do this...
This was pretty interesting! For the short answer, set a breakpoint on
a msgbox and note the difference in output here (GetBits is what we use
when we find that BitConverter.GetBytes doesn't accept a Decimal...)
?system.decimal.getbits(d1)
{Length=4}
(0): 100
(1): 0
(2): 0
(3): 0
?system.decimal.getbits(d2)
{Length=4}
(0): 10000
(1): 0
(2): 0
(3): 131072
Now the reason .Equals (which is what = gets compiled to) returns true
is because these two values do both represent the same value (exactly
100) but as you can see, internally they have different
representations!
A decimal number is a signed, fixed-point value consisting of an
integral part and an optional fractional part. The integral and
fractional parts consist of a series of digits that range from zero to
nine (0 to 9), separated by a decimal point symbol.
The binary representation of an instance of Decimal consists of a 1-bit
sign, a 96-bit integer number, and a scaling factor used to divide the
96-bit integer and specify what portion of it is a decimal fraction.
The scaling factor is implicitly the number 10, raised to an exponent
ranging from 0 to 28.
So without poking around too much, we can surmise that CDec("100") gets
you a decimal which is stored as 100 * 10^0, but CDec("100.00") gets
you a decimal which is stored as 10000 * 10^-2. And a plain vanilla
..ToString just dumps out the internal representation.
The lesson? Always specify a format for outputting Decimals, I suppose.