gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 21:07:00 25 4
gpt4 key购买 nike

可以表示\转换为小数的最大 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 中也看到了同样的错误。 (引用的来源表明,即使 低得多的值,此转换错误也可能发生。)

  • 双字面量不太圆润,但仍然有一点: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(双 x) - System.OverflowException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10783625/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com