C# C语言中处理货币金额的最佳实践#

C# C语言中处理货币金额的最佳实践#,c#,types,currency,C#,Types,Currency,我读过几篇关于某些数据类型被用于存储货币金额的危险的文章。不幸的是,有些概念不在我的舒适区 阅读了这些文章后,在C#中使用金钱的最佳实践和建议是什么?我是否应该对少量数据使用特定的数据类型,对较大的数据使用不同的数据类型?另外,我在英国工作,这意味着我们使用(例如4000英镑,而其他文化中的数字表示相同的金额不同)。由于舍入错误,您不应该使用浮点数。十进制类型应该适合您。我使用value对象来保存金额(作为十进制)和货币。这允许同时使用不同的货币decimal是.NET中推荐的货币数据类型。de

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


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

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

我使用value对象来保存金额(作为
十进制)和货币。这允许同时使用不同的货币
decimal
是.NET中推荐的货币数据类型。

decimal是货币金额最合理的类型

Decimal是一种以10为基数的浮点数字类型,精度为28+十进制数字。使用Decimal,您将比使用基数为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会在加减数字时对数字进行处理,但不是在所有情况下都是如此。

马丁·福勒建议使用。有关基本原理,请参见链接。他的想法有很多种实现方式,你也可以自己写。Fowler自己的实现是用Java实现的,所以他使用了一个类。我见过的C#版本使用结构,这似乎很合理。

我的建议是使用十进制,如果需要除法,其他人也建议使用十进制。对于简单的理货应用程序,我建议使用整数类型。对于这两种类型,我都会选择最低的货币面额。(即加拿大/美国的美分)


我很喜欢@dangph添加的Fowler金钱呼叫理论。

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

有一次,我花了一周的时间跟踪了一个1美分的错误,因为SQLServer和.Net使用不同的货币取整方法,而应用程序在处理某些类型的计算时并不一致——有时是在SQL中完成的,有时是在.Net中完成的。如果你感兴趣的话,就调查一下


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

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

另一个需要注意的问题是SQL Server存储日期时间的精度为3.33毫秒(0.00333秒)。我曾经被它咬了一口,因为它不足以满足我的目的。十进制的钱是好的。但货币比率仍然应该是两倍(例如利率)。我投了赞成票,只是为了抵消反对票。我认为不应该不加评论就允许投票。这个链接是404:(