【问题标题】:Convert from Decimal to Single and back. Why does it throw an Overflow Exception?从十进制转换为单个并返回。为什么会抛出溢出异常?
【发布时间】:2014-01-25 00:39:04
【问题描述】:

我发现了这种奇怪的行为。然后我在Visual Studio的Immediate窗口上做了几个实验……

? Convert.ToSingle(Decimal.MinValue)
-7.92281625E+28

这里没有惊喜。

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

第一个奇怪的行为:即使 Decimal.MinValue 位于 Decimal 域的边界,我认为将其转换为浮点数不会将其推过域限制。

? Convert.ToDecimal(-7.92281625E+28)
-79228162500000000000000000000

嗯……很奇怪……哦,没那么奇怪:它将表达式视为双重。

? Convert.ToDecimal(-7.92281625E+28F)
'Convert.ToDecimal(-7.92281625E+28F)' threw an exception of type 'System.OverflowException'
    base: {"Value was either too large or too small for a Decimal."}

让我们试试这个......

? Convert.ToDecimal(-7.92281625E+28D)
-79228162500000000000000000000

...好吧。正如我所想的那样,如果它认为它是浮点数,它就无法转换该数字,但在将它视为双精度时,将它转换回十进制没有问题。

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

等等!什么!? 现在我真的迷路了。最后两个表达式有什么区别?为什么它无法从浮点数转换回来?

【问题讨论】:

  • Decimal 是 128 位的数据类型,也许 .MinValue 会因为这个而被淘汰,如果尝试强制转换会发生什么?
  • 完全一样: ? (Decimal)Convert.ToSingle(Decimal.MinValue) '(Decimal)Convert.ToSingle(Decimal.MinValue)' 抛出类型为 'System.OverflowException' 的异常 base: {"Value 对于 Decimal 来说太大或太小。 “}? Convert.ToDecimal((float)Decimal.MinValue) 'Convert.ToDecimal((float)Decimal.MinValue)' 抛出类型为 'System.OverflowException' 的异常 base: {"对于 Decimal 而言,值太大或太小。 "}

标签: c# c#-4.0 c#-3.0 type-conversion


【解决方案1】:

您可以使用 Eric Lipper 在他的博客上发布的代码检查您的值在 double 变量中的准确表示方式:Looking inside a double

对于您的Convert.ToDouble(decimal.MinValue),它会打印以下信息:

Raw sign: 1
Raw exponent: 10001011111
Raw mantissa: 0000000000000000000000000000000000000000000000000000
Normal
Sign: -
Exponent: 96
Exact binary fraction: 1.0000000000000000000000000000000000000000000000000000
Nearest approximate decimal: -7,92281625142643E+28
Exact rational fraction: -79228162514264337593543950336
Exact decimal fraction: -79228162514264337593543950336

精确小数是这里最重要的部分。

exact decimal fraction: -79,228,162,514,264,337,593,543,950,336
decimal.MinValue:       -79,228,162,514,264,337,593,543,950,335

如您所见,它略低于decimal.MinValue,这就是您遇到异常的原因。

同样的情况也适用于Convert.ToSingle(Convert.ToSingle(decimal.MinValue))

【讨论】:

    【解决方案2】:

    SingleDouble 类型并不像 Decimal 类型那样准确地表示所有值。

    Double 文字 -7.92281625E+28 最终不会作为包含该值的 Double,仅包含该类型可以表示的最接近的值。大多数字面值会略微向上或向下调整,因为浮点类型中的存储基于二进制数,而不是十进制数。

    当您将Decimal.MinValue 转换为Single 时,它会略微向下调整,这意味着它刚刚超出了Decimal 可以表示的范围。当您尝试将其转换回 Decimal 时,它将失败,因为它超出了范围。仅当数字在 Decimal 的范围内时,转换才有效,而不是在 Decimal 可以转换到的范围内时。

    【讨论】:

      【解决方案3】:

      Decimal.MinValue 的双精度表示不准确,比 Decimal.MinValue 小一点导致溢出。

      VS 2012 即时窗口给出了以下结果,这表明这一点要好一些。

      ?Decimal.MinValue
      -79228162514264337593543950335
      ?Convert.ToDouble(Decimal.MinValue)
      -7.9228162514264338E+28
      

      Convert.ToDouble 是...

      -79228162514264338000000000000
      

      请注意,Decimal.MinValue 中的最后一位数字是 8 vs 7,这使得它太小而无法放入 Decimal。

      【讨论】:

        猜你喜欢
        • 2021-09-25
        • 1970-01-01
        • 1970-01-01
        • 2021-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-11
        • 1970-01-01
        相关资源
        最近更新 更多