The fact is that 0.45 does not have an exact binary representation. This leads to a loss of accuracy even where the developer expects a more accurate result.
In your case, upcast float values of 0.45 to double occur.
0.45f looks like this
0 01111101 1100 11001100 11001100 110
This is approximately 0.449999988079071044921875 .
.NET knows that float accuracy is insufficient, and when converting to a string, uses 7 significant digits. 0.4499999 88 displayed as 0.45 . Therefore, in the debugging, and when outputting to the console, you will see 0.45 .
0.45d - looks like this:
0 0111111 1101 1100 11001100 11001100 11001100 11001100 11001100 11001101
That is approximately equal to 0.450000000000000011102230246252 . For double, when converting to a string, .NET uses 14 significant digits. The value is represented as 0.45000000000000 00 -> 0.45
Ok, now you give the processor 0.45f and ask it to convert it to double. The processor takes and finishes with zeros:
0 0111111 1101 1100 11001100 11001100 11000000 00000000 00000000 00000000
What is still 4.49999988079071044921875
From the point of view of the processor - the accuracy was not affected. But now it is double, and during operations with it it is assumed that it is precise enough to grab more numbers when working with it as a decimal number.
It is no longer "around 0.45 ". This is double. Now there are about 14 significant digits in it - the value from the point of view of .NET and the processor has turned into "approximately 0.449999988079071 ".
Those. in the binary representation, the accuracy was not lost, in the decimal - also - but the resulting number now differs from 0.45d, which leads to rounding in an unexpected direction.
Why does a similar call work with the cast to decimal:
Math.Round((Decimal)0.45f, 1, MidpointRounding.AwayFromZero) // 0.5
The reduction to decimal occurs through the system call of the method VarDecFromR4 , which converts the float to 7 significant decimal digits when converting, making 0.449999988079071044921875 nice 0.4500000 :
// Round the input to a 7-digit integer. The R4 format has // only 7 digits of precision, and we want to keep garbage digits // out of the Decimal were making.
Actually, the conversion code itself (a pair of screens) is mainly devoted to this rounding, followed by cutting off the insignificant zeros.
0.45f != 0.45dand have deviations in different directions from0.45from that and the difference. - Dmitry Chistik