我经常告诉别人,在C#中,double类型的变量不适合用于表示金钱。可能会发生各种奇怪的事情。但是我似乎无法创建一个示例来演示这些问题。有人能提供这样的示例吗?
(编辑:此帖最初被标记为C#;一些回复涉及到decimal
的具体细节,因此意味着System.Decimal
)。
(编辑2:我特别要求一些C#代码,所以我认为这不仅是与语言无关的)
我经常告诉别人,在C#中,double类型的变量不适合用于表示金钱。可能会发生各种奇怪的事情。但是我似乎无法创建一个示例来演示这些问题。有人能提供这样的示例吗?
(编辑:此帖最初被标记为C#;一些回复涉及到decimal
的具体细节,因此意味着System.Decimal
)。
(编辑2:我特别要求一些C#代码,所以我认为这不仅是与语言无关的)
非常不适合。请使用十进制。
double x = 3.65, y = 0.05, z = 3.7;
Console.WriteLine((x + y) == z); // false
(Jon的页面上的示例在这里 - 推荐阅读 ;-p)
由于舍入效果,您将获得奇怪的错误。此外,与精确值的比较非常棘手 - 通常需要应用某种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个数字可以用来进行单个操作,因此最大的可工作数字仍然比美国国家债务高得多。但是随着时间的推移,舍入误差将累积起来。如果您的软件运行时间很长,最终会开始损失几分钱。某些操作会使情况变得更糟。例如,将大量添加到小量将导致显着的精度损失。
您需要使用固定点数据类型进行货币运算,大多数人不介意您偶尔丢失一分钱,但会计师与大多数人不同。
编辑
根据此网站http://msdn.microsoft.com/en-us/library/678hzkk9.aspx Double实际上具有15到16个有效数字而不是17。
@ Jon Skeet由于decimal类型具有更高的精度,即28或29个有效数字,因此它比double类型更适合。这意味着积累的舍入误差变得不那么重要。正如Boojum提到的那样,固定点数据类型(例如表示美分或1/100美元的整数)实际上更适合。
x + 1 != x
总是成立。此外,它保留精度,因此您可以区分1
和1.0
。 - GabeDecimal
值可能会失去小数点右侧的精度,而不表示任何问题。 - supercatdouble
类型仅考虑整数值时具有15.9个有效十进制数字。小数点后的情况取决于数值。 - user207421double
类型则将其表示为104857 / 2 ^ 20(实际上更像是really-big-number / 2 ^ 1023)。
decimal
可以准确地表示任何带有28/29个有效数字的基数10值(如0.1),但double
不能。我的理解是大多数金融系统使用整数来表示货币,即以分为单位计算。
IEEE双精度实际上可以在范围-2^53到+2^53内准确地表示所有整数。(《黑客的乐趣》,第262页)如果您仅使用加法、减法和乘法,并将所有内容保持在此范围内的整数,则不应看到任何精度损失。但是,我会非常谨慎地处理除法或更复杂的操作。
double
,但不支持任何64位整数类型。我建议将计算作为double
进行,缩放以使任何语义所需的舍入始终是整个单位,这可能是最有效的方法。 - supercat如果你不知道在做什么的情况下使用double是不合适的。
"double"可以表示1万亿美元的金额,误差只有1/90美分。因此,您将获得高精度的结果。想要计算将一个人送上火星并使他安全返回所需的成本吗?double就可以胜任。
但是对于货币而言,通常有非常具体的规定,规定必须给出某个特定的计算结果,而不能是其他的结果。如果你计算的金额非常非常接近98.135美元,那么通常会有一个规则确定结果应该是98.14美元还是98.13美元,你必须遵循这个规则并得到所需的结果。
根据您所在的位置,使用64位整数来表示分或便士或kopeks或您所在国家的最小单位通常可以正常工作。例如,64位带符号整数表示的分可以表示价值高达92,223万亿美元的价值。32位整数通常不适用。
一个双精度浮点数总是会有舍入误差,如果你在 .Net 上,使用 "decimal" 类型。
实际上,如果选择合适的单位,浮点数double非常适合表示货币金额。
请参见http://www.idinews.com/moneyRep.html
固定点数long也是如此。两者都占用8个字节,肯定比decimal项占用的16个字节更可取。
某种技术是否有效(即产生预期和正确的结果)不是投票或个人偏好的问题。一种技术要么有效,要么无效。