.NET中的double multiplication损坏了吗?
如果我在C#中执行以下expression式:
double i = 10*0.69;
i
是: 6.8999999999999995
。 为什么?
我知道像1/3这样的数字很难用二进制表示,因为它具有无限循环的小数位数,但0.69并不是这种情况。 而0.69可以很容易地用二进制表示,一个二进制数为69,另一个表示小数位的位置。
我如何解决这个问题? 使用decimal
types?
因为你误会了浮点运算和数据的存储方式。
事实上,在这种情况下,你的代码实际上并没有执行任何algorithm – 编译器会完成它,然后在生成的可执行文件中保存一个常量。 但是,它不能存储6.9的精确值,因为该值不能以浮点格式精确表示,就像1/3不能精确地存储在有限十进制表示中一样。
看看这篇文章是否对你有帮助。
为什么框架没有解决这个问题,并从我这里隐藏这个问题,并给我正确的答案,0.69!
停止像dilbert经理一样的行为,并接受电脑,虽然酷,真棒,有限制。 在你的具体情况下,它不会“隐藏”这个问题,因为你已经明确地告诉它不要。 该语言(电脑)提供了格式的替代品,你没有select。 你select了double,与decimal相比有一定的优势,有一些缺点。 现在,知道答案,你不高兴的是,缺点不会神奇消失。
作为一名程序员,你有责任从pipe理者身上隐藏这个缺点,而且有很多方法可以做到这一点。 但是,C#的制作者有责任使浮点运行正确,正确的浮点运算偶尔会导致math错误。
所以将所有其他数字存储方法,因为我们没有无限的位。 我们作为程序员的工作就是使用有限的资源来做一些很酷的事情。 他们给你90%的路程,把火炬送回家。
而0.69可以很容易地用二进制表示,一个二进制数为69,另一个表示小数位的位置。
我认为这是一个常见的错误 – 你正在考虑浮点数,就好像它们是基数为10(即小数 – 因此我强调)。
所以 – 你认为这个double有两个整数部分: 69 除以100得到小数点的位置 – 也可以表示为:
-2的功率为69 x 10 。
然而,浮点数存储“点的位置”为基数2 。
你的float实际上被存储为:
68999999999999995 x 2给一些大负数的力量
一旦你习惯了这个问题,这不是一个很大的问题 – 大多数人都知道并期望1/3不能准确地表示为小数或百分比。 只是不能用基数2表示的分数是不同的。
但为什么框架没有解决这个问题,并且把这个问题隐藏起来,给我正确的答案,0.69 !!!
因为你告诉它使用二进制浮点 ,解决scheme是使用十进制浮点数 ,所以你build议框架应该忽略你指定的types,并使用十进制代替,这是非常慢,因为它不直接实现硬件。
更有效的解决scheme是不输出表示的全部值,并明确指定输出所需的精度。 如果将输出格式化为小数点后两位,您将看到预期的结果。 但是,如果这是一个财务应用程序, 十进制正是你应该使用的 – 你已经看到超人III(和办公空间)没有你;)
请注意,这是一个无限范围的有限近似值,仅仅是小数点和双精度值使用了一组不同的近似值。 十进制的优点在于,它可以产生与您自己执行计算时相同的近似值。 例如,如果你计算了1/3,那么当它“足够好”时,你最终会停止写3。
出于同样的原因,在十进制系统中1/3出现为0.3333333333333333333333333333333333333333333而不是确切的分数,这是无限长的。
要解决这个问题(例如在屏幕上显示),请尝试以下操作:
double i = (double) Decimal.Multiply(10, (Decimal) 0.69);
每个人似乎都回答了你的第一个问题,但是却忽略了第二个问题。