c# - Convert.ToDecimal(double x) - System.OverflowException

标签 c# .net

可以表示\转换为小数的最大 double 值是多少?

如何得出这个值 - 请举例。

更新

给定可以转换为小数的 double 的最大值,我希望能够将 double 往返为小数,然后再返回。然而,给定一个数字,如 @Jirka 的答案中的 (2^52)-1 ,这是行不通的。例如:

    Test]
    public void round_trip_double_to_decimal()
    {
        double maxDecimalAsDouble = (Math.Pow(2, 52) - 1);

        decimal toDecimal = Convert.ToDecimal(maxDecimalAsDouble);

        double toDouble = Convert.ToDouble(toDecimal);

        //Fails.
        Assert.That(toDouble, Is.EqualTo(maxDecimalAsDouble));
    }

最佳答案

-9,007,199,254,740,992 和 9,007,199,254,740,991 之间的所有整数都可以用 double 值精确表示。(请继续阅读。)

上限导出为 2^53 - 1 。如果您原谅我的十六进制语法,它的内部表示类似于 (0x1.fffffffffffff * 2^52)。

在此范围之外,许多整数如果是 2 的幂的倍数,仍然可以精确表示。

因此,可以准确表示的最大整数将是 9,007,199,254,740,991 * (2 ^ 1023),它甚至高于 Decimal.MaxValue,但这非常漂亮毫无意义的事实,因为该值不会改变,例如,当您在 double 算术中减去 1 时。

根据评论和进一步的研究,我添加了有关 C# 的 .NET 和 Mono 实现的信息,这些信息使您和我可能想要得出的大多数结论相对化。

  • Math.Pow 似乎不能保证任何特定的准确性,并且它提供的结果似乎比 double 所能表示的少一两点。对于浮点函数来说,这并不奇怪。英特尔浮点硬件没有求幂指令,我预计计算涉及 logarithm and multiplication指令,中间结果会失去一些精度。如果需要积分精度,可以使用 BigInteger.Pow。

  • 但是,即使 (decimal)(double)9007199254740991M 也会导致往返违规。然而,这一次是 known bug ,直接违反了 C# 规范第 6.2.1 节。有趣的是,即使在 Mono 2.8 中我也看到了同样的错误。 (引用的来源表明,即使使用低得多的值,也会出现此转换错误。)

  • double 文字的四舍五入程度较低,但仍然有一点:9007199254740991D 打印为 9007199254740990D。这是解析字符串文字时内部乘以 10 的结果(在基于“小数点后的第一个零”,上限和下限收敛到相同的 double 值之前)。这再次违反了 C# 规范,这次是第 9.4.4.3 节。

  • 与 C 不同,C# 没有十六进制浮点文字,因此我们无法避免通过任何其他语法乘以 10,除非通过 DecimalBigInteger,如果这些只提供了准确的转换运算符。我尚未测试 BigInteger

  • 上面的内容几乎会让您怀疑 C# 是否没有发明自己独特的降低精度的浮点格式。否,第 11.1.6 节引用 64 位 IEC 60559表示。所以以上确实是bug。

因此,总而言之,您甚至应该能够将 9007199254740991M 精确地放入 double 型中,但要获得该值是一个相当大的挑战!

这个故事的寓意是,“算术应该比数据和期望结果更精确”的传统观念是错误的,如 this famous article演示(第 36 页),尽管是在不同的编程语言的上下文中。

除非必要,否则不要将整数存储在浮点变量中。

关于c# - Convert.ToDecimal(double x) - System.OverflowException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10783625/

相关文章:

c# - 在 DataGridView 中选择一行并跟随行标题上的箭头

.net - 形式成为焦点

.net - 如何检查控件是否已加载?

.net - 使用 serilog 记录 json

c# - 将度/分/秒转换为小数坐标

c# - UDP打洞实现

c# - 保护 Excel 工作簿中的代码?

c# - 编写 C++ 旨在从 C# 调用?

.net - Visual Studio 解决方案项目引用或 Dll 引用

c# - 从事务中排除操作