我总是在c#中告诉double类型的变量不适合赚钱。所有奇怪的事情都可能发生。但我似乎无法创建一个示例来演示其中的一些问题。任何人都可以提供这样的例子吗?
(编辑;此帖最初标记为C#;有些回复引用decimal
的具体详情,因此意为System.Decimal
)。
(编辑2:我特别要求提供一些c#代码,所以我不认为这只是语言无关)
答案 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个字节更好。
是否有效(即产生预期和正确的结果)不是投票或个人偏好的问题。一种技术既可以使用,也可以不运行。