Is a double really unsuitable for money?
我总是用C表示,双精度型变量不适合货币。所有奇怪的事情都可能发生。但我似乎无法创建一个例子来演示其中的一些问题。有人能举个例子吗?
(编辑:这篇文章最初被标记为C;一些回复提到了
(编辑2:我特别要求一些C代码,所以我不认为这只是语言不可知论)
非常,非常不合适。使用十进制。
1 2 | double x = 3.65, y = 0.05, z = 3.7; Console.WriteLine((x + y) == z); // false |
(这里是乔恩的页面示例-推荐阅读;-p)
四舍五入会有效地产生奇数错误。此外,与精确值进行比较非常困难——通常需要应用某种epsilon来检查实际值是否"接近"某个特定值。
下面是一个具体的例子:
1 2 3 4 5 6 7 8 9 10 11 | using System; class Test { static void Main() { double x = 0.1; double y = x + x + x; Console.WriteLine(y == 0.3); // Prints False } } |
是的,这不合适。
如果我记得正确的话,double大约有17个有效数字,所以通常舍入误差会远远超过小数点。大多数金融软件使用小数点后4位小数,剩下13位小数可供使用,因此单次操作所能使用的最大数字仍然远远高于美国国债。但舍入误差会随着时间的推移而增加。如果你的软件长时间运行,你最终会损失美分。某些操作会使情况更糟。例如,将大量添加到少量将导致严重的精度损失。
您需要固定点数据类型来进行货币操作,大多数人不介意您在这里或那里损失一分钱,但会计师不像大多数人。
编辑根据这个网站http://msdn.microsoft.com/en-us/library/678hzk9.aspx doubles实际上有15到16个有效数字,而不是17个。
@由于精度较高,所以jon skeet decimal比double更适合28或29位有效小数。这意味着累积舍入误差变得显著的可能性更小。像boojum提到的固定点数据类型(即表示美分或百分之一的整数,如我所见)实际上更适合。
由于
我的理解是,大多数金融系统用整数来表示货币——也就是说,用美分来计算所有的东西。
ieee双精度实际上可以精确地表示-2^53到+2^53范围内的所有整数。(Hacker's Delight,第262页)如果您只使用加法、减法和乘法,并将所有内容都保持在这个范围内,那么您应该不会看到精度损失。不过,我对部门或更复杂的行动非常谨慎。
当你不知道自己在做什么的时候,就用双份。
"双倍"可以代表一万亿美元,误差为1/90美分。所以你会得到非常精确的结果。想知道把一个人放在火星上然后让他活着要花多少钱吗?双份正好。
但是对于金钱,经常有非常具体的规则说,一定的计算必须给出一定的结果,而不是其他的。如果您计算的金额非常接近98.135美元,那么通常会有一个规则来确定结果应该是98.14美元还是98.13美元,并且您必须遵循该规则并获得所需的结果。
根据你住的地方,用64位整数来表示美分、便士、Kopek或者其他任何你所在国家最小的单位,通常都可以。例如,表示美分的64位有符号整数可以表示高达92223万亿美元的值。32位整数通常不适用。
没有一个双精度数总是有舍入误差,如果你在.NET上,使用"decimal"…
实际上,只要你选择一个合适的单位,浮点双精度就非常适合于表示金额。
请访问http://www.idinnews.com/moneyreep.html
固定点长度也是如此。两者都消耗8个字节,当然比小数项消耗的16个字节要好。
某件事是否有效(即产生预期和正确的结果)不是投票或个人偏好的问题。一种技术要么有效,要么无效。