9

我已经阅读了几篇关于某些数据类型用于存储货币金额的危险的文章。不幸的是,有些概念不在我的舒适区。

阅读了这些文章后,在 C# 中使用金钱的最佳实践和建议是什么?我应该对少量使用某种数据类型,而对大量使用不同的数据类型吗?另外,我在英国,这意味着我们使用 ,(例如 4,000 英镑,而其他文化代表相同的金额不同)。

4

7 回答 7

16

小数是货币金额最合理的类型。

Decimal 是一种以 10 为基数的浮点数类型,具有 28+ 个十进制数字的精度。使用 Decimal,您将比使用 base 2 Double 类型的惊喜更少。

Double 使用的内存是 Decimal 的一半,Double 会更快,因为 CPU 硬件用于许多常见的浮点运算,但它不能准确表示大多数以 10 为底的分数(例如 1.05),并且 15+ 十进制数字的准确度较低精确。Double 确实具有更大范围的优势(它可以表示更大和更小的数字),这对于某些计算,尤其是一些统计计算来说非常有用。

您的问题的一个答案指出,十进制是具有 4 位十进制数字的定点。不是这种情况。如果您对此表示怀疑,请注意以下代码行产生 0.0000000001:

Console.WriteLine("number={0}", 1m / 10000000000m);

说了这么多,有趣的是,世界上使用最广泛的处理货币金额的软件 Microsoft Excel 使用双精度数。当然,他们必须跳很多圈才能使其正常工作,但仍然有一些不足之处。在 Excel 中尝试以下两个公式:

  • =1-0.9-0.1
  • =(1-0.9-0.1)

第一个产生 0,第二个产生 ~-2.77e-17。在某些情况下,Excel 实际上会在加减数字时对数字进行处理,但并非在所有情况下都如此。

于 2009-03-01T02:31:06.967 回答
8

由于舍入错误,您不应使用浮点数。十进制类型应该适合您。

于 2009-03-01T02:08:42.200 回答
6

Martin Fowler 建议使用Money 类。有关理由,请参阅链接。他的想法有很多实现,或者你可以自己编写。Fowler 自己的实现是用 Java 编写的,所以他使用了一个类。我见过的 C# 版本使用结构,这似乎是明智的。

于 2009-03-01T02:45:11.363 回答
2

我使用一个值对象来保存金额(作为 a decimal)和货币。这允许同时使用不同的货币。decimal是 .NET 中推荐的用于金钱的数据类型。

于 2009-03-01T02:08:44.930 回答
0

如果需要除法,我的建议是使用 Decimal,正如其他人所推荐的那样。对于简单的计数应用程序,我建议使用整数类型。对于这两种类型,我总是使用最低的货币面额。(即加拿大/美国的美分)

我确实喜欢 @dangph 添加的 Fowler's Money call 理论。

于 2009-03-01T03:22:53.490 回答
0

无论您做什么,请确保您了解在应用程序的每一层中如何处理货币金额。

我曾经花了一周时间追踪一个 1 美分的错误,因为 SQLServer 和 .Net 使用不同的货币舍入方式,并且应用程序在处理某些类型的计算方面并不一致——有时它们是在 SQL 中完成的,有时是在 .net 中完成的。如果您有兴趣,请查看“银行家的四舍五入”。

还有与格式化货币有关的问题——不确定您是否必须处理非英国金额、其他语言/文化等,但这会增加另一个层次的复杂性。

于 2009-03-01T03:48:13.007 回答
0

正如您在问题中指出的那样,除了使用适当的数据类型之外,您的程序处理货币转换的能力也很重要。这个问题当然不是货币独有的。Jeff Atwood做了一篇很棒的文章,总结了执行土耳其测试的优点。

于 2009-03-01T05:54:23.483 回答