在.NET中双倍乘法?

时间:2009-09-14 10:30:57

标签: c# .net math

如果我在C#中执行以下表达式:

double i = 10*0.69;

i是:6.8999999999999995。为什么?

我理解像1/3这样的数字很难用二进制表示,因为它有无限的重复小数位,但这不是0.69的情况。 0.69可以很容易地用二进制表示,一个二进制数表示69,另一个表示小数位的位置。

我该如何解决这个问题?使用decimal类型?

6 个答案:

答案 0 :(得分:156)

因为你误解了浮点运算以及如何存储数据。

实际上,在这种特殊情况下,你的代码实际上并没有在执行时执行任何算术 - 编译器将完成它,然后在生成的可执行文件中保存一个常量。但是,它不能存储6.9的精确值,因为该值不能以浮点值格式精确表示,就像1/3不能精确地存储在有限的十进制表示中一样。

查看this article是否可以帮助您。

答案 1 :(得分:53)

  

为什么框架不能解决这个问题并将这个问题隐藏起来并给我这个问题   正确答案,0.69 !!!

停止表现得像一个迪尔伯特经理,并接受计算机,虽然很酷,很棒,有限制。在您的具体情况下,它不仅仅是“隐藏”问题,因为您已经明确告诉它不要。语言(计算机)提供了您没有选择的格式的替代方案。你选择了double,它具有超过十进制的某些优点,以及某些缺点。现在,知道了答案,你会感到不安的是,缺点不会神奇地消失。

作为一名程序员,您有责任将这种缺点隐藏在管理者之外,并且有很多方法可以做到这一点。但是,C#的制造者有责任正确地使浮点工作,并且正确的浮点有时会导致错误的数学运算。

所有其他数字存储方法也是如此,因为我们没有无限位。我们作为程序员的工作是使用有限的资源来制作很酷的事情。他们让你90%的路程,让火炬回家。

答案 2 :(得分:15)

  

可以很容易地表示0.69   二进制,一个二进制数为69和   另一个表示的位置   十进制的地方。

我认为这是一个常见的错误 - 你认为浮点数好像它们是基数10(即十进制 - 因此我的重点)。

所以 - 你认为这个双倍有两个整数部分: 69 除以100 以获得小数点移动 - 这可能也表示为:
69 x 10到-2 的力量。

然而,浮点数将“点的位置”存储为 base-2

您的浮动实际上存储为:
     68999999999999995 x 2给一些大负数的力量

一旦你习惯了,这并不是一个问题 - 大多数人都知道并且期望1/3不能以十进制或百分比的形式准确表达。只是不能用base-2表达的分数是不同的。

答案 3 :(得分:11)

  

但为什么框架不能解决这个问题并将这个问题隐藏起来并给我正确答案,0.69!

因为你告诉它使用二进制浮点,解决方案是使用十进制浮点,所以你建议框架应该忽略你指定的类型并使用十进制,这非常慢,因为它没有直接在硬件中实现。

更有效的解决方案是不输出表示的完整值并明确指定输出所需的准确度。如果将输出格式化为两位小数,您将看到预期的结果。但是,如果这是一个财务应用十进制正是你应该使用的 - 你已经看到超人III(和Office Space)没有你;)

请注意,它只是无限范围的有限近似,只是十进制 double 使用一组不同的近似值。 decimal 的优点是它会产生与您自己执行计算时相同的近似值。例如,如果你计算了1/3,那么当它“足够好”时你最终会停止写3个。

答案 4 :(得分:8)

出于同样的原因,十进制系统中的1/3出现为0.3333333333333333333333333333333333333333333而不是精确分数,这是无限长的。

答案 5 :(得分:2)

要解决此问题(例如在屏幕上显示),请尝试以下操作:

double i = (double) Decimal.Multiply(10, (Decimal) 0.69);

似乎每个人都回答了你的第一个问题,但忽略了第二个问题。