十进制转双精度浮点数

4
我有以下测试代码:

decimal test1 = 0.0500000000000000045656554454M;
double test2 = (double)test1;

这会导致在调试时test2显示为0.05。为什么会四舍五入到小数点后两位呢?
谢谢。
4个回答

8

该转换的值实际上是0.050000000000000009714451465470119728706777095794677734375,如DoubleConverter所示。这是最接近你转换的十进制数的双精度浮点数的确切值。

当你使用调试器或普通字符串格式化时,通常不会显示精确结果。


好的,但为什么序列化后这个值显示为0.05呢? - Jon Archway
好问题:“通常不会显示确切的结果” -> 为什么?对于输出格式来说,还可以,但在调试器中,这可能会很方便,正如这个问题所示。 - Peter
@Peter:我怀疑大多数人不想看到像这里显示的那么长的值。从某种程度上说,它也会给人一种错误的印象——他们可能期望能够调整第25位数字,只是因为显示了更多的数字。我选择显示精确值,但离此最近的精确值将具有许多不同的有效数字。 - Jon Skeet
@Jon,错误印象是一个好观点,尽管调试器应该只显示工作内容。 - Peter
@Jon Archway(抱歉之前@了错误的人:我没有意识到你们两个都是Jon):你问题的答案是:“因为.NET默认使用15位小数来表示双精度浮点数”,结合Jon的回答,我想这就是答案。 - Peter

4
原因是double类型最多只能包含15-16个有效数字。
请参见double (C# 参考)

+1对于C#的引用。我认为在最坏的情况下,它可能有15-16位数,但在某些情况下可能会更好(这取决于是否可以用double来表示...)。 - Anna
+1,附注:C#使用IEEE-754标准来表示单精度和双精度浮点数数据。 - user7116
这个答案是错误的:原因是你的调试器没有显示0.05000000000000000971445146547011972870677709579467773437,正如Jon所指出的。尽管15/16位有效数字是正确的,但数字的位数和有效数字的位数是有区别的。 - Peter

3
你应该查看关于浮点数算术和.NET的这篇文章。舍入是由于数字如何转换为双精度浮点值以及在打印时如何格式化而发生的,因为.NET默认为双精度小数保留15位,而你的原始数字包含超过15位的小数。
你可以尝试test2.ToString("0.000000000000000000000000")来查看是否可以从数字中挤出更多信息,但我怀疑这样做没有用。

1

我能想到两个原因:

  1. 由于十进制和双精度浮点数的表示方式不同。请参阅this文章,了解更多关于浮点数表示的信息。可能在双精度中没有足够的位来表示整数。
  2. 由于数字的打印方式。你的打印选项中可能指定小数点后不到18个数字——在这种情况下,你会得到舍入后的结果。

我会首先检查调整打印选项以确保问题不在那里。

.. 但要知道,第一个问题的唯一解决方案是停止使用双精度浮点数 :-)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接