双人真的不适合赚钱吗?

时间:2008-11-25 08:49:41

标签: c# language-agnostic decimal currency

我总是在c#中告诉double类型的变量不适合赚钱。所有奇怪的事情都可能发生。但我似乎无法创建一个示例来演示其中的一些问题。任何人都可以提供这样的例子吗?

(编辑;此帖最初标记为C#;有些回复引用decimal的具体详情,因此意为System.Decimal)。

(编辑2:我特别要求提供一些c#代码,所以我不认为这只是语言无关)

8 个答案:

答案 0 :(得分:115)

非常非常不合适。使用小数。

double x = 3.65, y = 0.05, z = 3.7;
Console.WriteLine((x + y) == z); // false

(例如Jon的页面here - 推荐阅读;-p)

答案 1 :(得分:34)

您将因舍入而导致奇怪的错误。此外,与精确值的比较非常棘手 - 您通常需要应用某种类型的epsilon来检查实际值是否接近特定值。

这是一个具体的例子:

using System;

class Test
{
    static void Main()
    {
        double x = 0.1;
        double y = x + x + x;
        Console.WriteLine(y == 0.3); // Prints False
    }
}

答案 2 :(得分:7)

是的,它不合适。

如果我没记错,double有大约17个有效数字,所以通常舍入误差会远远落后于小数点。大多数财务软件使用小数点后面的4位小数,留下13位小数,因此单次操作可以使用的最大数量仍远高于美国国债。但是舍入错误会随着时间的推移而增加。如果你的软件运行很长时间,你最终会开始失去美分。某些操作会使情况变得更糟。例如,将少量添加到少量将导致严重的精度损失。

你需要定点数据类型进行资金操作,大多数人不介意你在这里和那里输了一分钱,但会计师不像大多数人..

修改
根据这个网站http://msdn.microsoft.com/en-us/library/678hzkk9.aspx双打实际上有15到16位有效数字而不是17位。

@Jon Skeet decimal比double更合适,因为它的精度更高,28或29位有效小数。这意味着累积舍入误差变得越来越大的可能性越小。像Boojum提到的定点数据类型(即代表美分或100分钱的整数,如我所见过的)实际上更适合。

答案 3 :(得分:5)

由于decimal使用倍数为10的缩放因子,因此可以精确表示0.1之类的数字。实质上,十进制类型将此表示为1/10 ^ 1,而double将此表示为104857/2 ^ 20(实际上它更像是真正的大数字 / 2 ^ 1023)。

decimal可以精确表示任何基数为10的值,最高为28/29位有效数字(如0.1)。 double不能。

答案 4 :(得分:4)

我的理解是,大多数金融系统使用整数表示货币 - 即以美分计算所有金额。

IEEE双精度实际上可以表示在-2 ^ 53到+ 2 ^ 53范围内的所有整数。 (Hacker's Delight,第262页)如果你只使用加法,减法和乘法,并将所有内容保持在此范围内的整数,那么你应该看到没有精度损失。但是,我会非常警惕分裂或更复杂的操作。

答案 5 :(得分:2)

当你不知道自己在做什么时使用double是不合适的。

“double”可以代表一万亿美元的金额,错误为1/90分。因此,您将获得高度精确的结果。想要计算一个人在火星上让他活着的成本是多少? double会做得很好。

但是对于金钱,通常会有非常具体的规则,即某种计算必须给出一定的结果,而不是其他的。如果您计算的金额非常非常接近$ 98.135,那么通常会有一条规则确定结果是98.14美元还是98.13美元,并且您必须遵循该规则并获得所需的结果。

根据您居住的地方,使用64位整数代表美分或便士或kopeks或您所在国家/地区的最小单位通常可以正常工作。例如,代表美分的64位有符号整数可以表示高达92,223万亿美元的值。 32位整数通常不合适。

答案 6 :(得分:0)

没有双精灵会一直有舍入错误,如果你在.Net上使用“十进制”......

答案 7 :(得分:-4)

实际上,只要您选择合适的单位,浮点就非常适合代表金额。

请参阅http://www.idinews.com/moneyRep.html

固定点也是如此。消耗8个字节,肯定比十进制项消耗的16个字节更好。

是否有效(即产生预期和正确的结果)不是投票或个人偏好的问题。一种技术既可以使用,也可以不运行。