3

If I try and convert Decimal.MaxValue from Decimal to Single and back again, the conversion fails with an OverflowException:

Convert.ToDecimal(Convert.ToSingle(Decimal.MaxValue))
// '...' threw an exception of type 'System.OverflowException'
//     base: {"Value was either too large or too small for a Decimal."}

What gives? Surely the value of Decimal.MaxValue as a Single should be a valid Decimal value?

I understand that the differences between Single and Decimal and expect a loss of precision converting from Decimal to Single but as Single.MaxValue is greater than Decimal.MaxValue it doesn't make sense that the "Value was either too large or too small for Decimal". If you think that does make sense please explain why in an answer.

Additionally,

Convert.ToSingle(Decimal.MaxValue)
// 7.92281625E+28

so there is no problem converting this number to a Single.

simonwo
  • 3,171
  • 2
  • 19
  • 28
  • Are you confusing `double` and `decimal`? `Decimal.MaxValue` is 79,228,162,514,264,337,593,543,950,335, `Single.MaxValue` is 3.402823e38. – kat0r Sep 30 '15 at 13:00
  • @DStanley No it's not. `var s = Convert.ToSingle(Decimal.MaxValue);` runs just fine. – juharr Sep 30 '15 at 13:29
  • 1
    Note that `float` will only have an approximation of the decimal value and it looks like the approximation is larger. – juharr Sep 30 '15 at 13:33
  • @juharr Actually the approximation is smaller (79,228,160,000,000,000,000,000,000,000 versus 79,228,162,514,264,337,593,543,950,335) – D Stanley Sep 30 '15 at 14:01

1 Answers1

4

You're making an incorrect assumption:

Surely the value of Decimal.MaxValue as a Single should be a valid Decimal value?

The value of Decimal.MaxValue is 79,228,162,514,264,337,593,543,950,335. A float can't represent anywhere near that level of precision, so when you convert the decimal value to a float you end up with an approximation.

In this case the float is represented internally as 2^96. This turns out to be a pretty good approximation -- 79,228,162,514,264,337,593,543,950,336 -- but take note of that last digit.

The value of the float is larger than Decimal.MaxValue, which is why your attempt to convert it back into a decimal fails.

(The .NET framework doesn't offer much help when trying to diagnose these kind of problems. It'll always display a pre-rounded value for the float -- 7.92281625E+28 or similar -- and never the full approximation that it's using internally.)

LukeH
  • 263,068
  • 57
  • 365
  • 409