双倍真的不适合金钱吗?
我总是告诉在c#中的一个variablestypes双不适合金钱。 所有奇怪的事情都可能发生。 但我似乎无法创build一个示例来展示其中的一些问题。 任何人都可以提供这样的例子?
(编辑;这篇文章最初是标记为C#;一些回复指的是decimal
具体细节,因此意味着System.Decimal
)。
(编辑2:我是具体要求一些C#代码,所以我不认为这只是语言不可知的)
非常非常不合适 使用小数。
double x = 3.65, y = 0.05, z = 3.7; Console.WriteLine((x + y) == z); // false
(例如从Jon的页面 – 推荐阅读; -p)
四舍五入会导致奇怪的错误。 另外,与精确值的比较是非常棘手的 – 通常需要应用某种types的epsilon来检查实际值是否“接近”某个值。
这里有一个具体的例子:
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位小数可以工作,所以单个操作可以使用的最大数量仍然远高于美国国债。 但是随着时间的推移,舍入误差会加起来。 如果你的软件运行很长时间,你最终会开始失去美分。 某些行动会使情况变得更糟。 例如,大量添加less量将会导致严重的精度损失。
你需要定点数据types的钱操作,大多数人不介意,如果你失去了一分钱,但会计师不是像大多数人一样。
编辑
根据这个网站http://msdn.microsoft.com/en-us/library/678hzkk9.aspx双打实际上有15至16位有效数字,而不是17。;
@Jon Skeet十进制比由于其更高的精度,28或29个重要的小数更适合于双倍。 这意味着积累的舍入误差变得很重要的可能性较小。 固定点数据types(即像我见过的代表百分之一美分的整数)就像Boojum提到的那样,实际上更适合。
由于decimal
使用10的倍数的比例因子,因此可以精确地表示像0.1这样的数字。 本质上,小数types表示为1/10 ^ 1,而double
表示为104857/2 ^ 20(实际上它更像真的大数 / 2 ^ 1023)。
decimal
可以精确地表示任何基数为10的值,最多28/29个有效数字(如0.1)。 double
不能。
我的理解是,大多数金融体系使用整数来表示货币 – 即以美分计算所有东西。
IEEE双精度实际上可以表示正好在-2 ^ 53到+ 2 ^ 53范围内的所有整数。 (Hacker's Delight,第262页)如果只使用加法,减法和乘法,并将所有内容都保存在这个范围内,那么你就不会看到精度的损失。 但是,我会非常警惕分裂或更复杂的操作。
当你不知道你在做什么是不合适的。
“双”可以代表一万亿美元的数额,误差为1/90分。 所以你会得到高度精确的结果。 想要计算把一个人放在火星上让他活着回来需要多less成本? 双将做得很好。
但有了钱,通常有非常明确的规则,说某个计算必须给出一定的结果,而不是其他的。 如果您计算的金额非常非常接近98.135美元,那么通常会有一条规则确定结果应该是$ 98.14还是$ 98.13,并且您必须遵循该规则并获得所需的结果。
根据你居住的地方,使用64位整数来表示美分,便士或高等教育,或者是你所在国家最小的单位,通常工作得很好。 例如,代表美分的64位有符号整数可以表示92,223万亿美元的值。 32位整数通常是不合适的。
没有一个双将总是有四舍五入错误,使用“十进制”,如果你在.Net …
实际上,浮点双数非常适合代表大量的金钱,只要你select一个合适的单位。
请参阅http://www.idinews.com/moneyRep.html
所以是定点长 。 要么消耗8个字节,当然最好是十进制数所消耗的16个字节。
无论是否有效(即产生预期的和正确的结果)不是一个投票或个人偏好的问题。 一种技术或者工作,或者不工作。