C# 十进制还是双精度

C# 十进制还是双精度,c#,.net,math,C#,.net,Math,我支持一个金融.net应用程序。对于金融数据,有很多建议使用十进制数据类型 现在我被这件事困住了: decimal price = 1.0m/12.0m; decimal quantity = 2637.18m; decimal result = price * quantity; //results in 219.76499999999999999999999991 问题是向客户收费的正确值是219.77(舍入函数,中点舍入.AwayFromZero),而不是219.76 如果我将所有内容

我支持一个金融.net应用程序。对于金融数据,有很多建议使用十进制数据类型

现在我被这件事困住了:

decimal price = 1.0m/12.0m;
decimal quantity = 2637.18m;
decimal result = price * quantity;  //results in 219.76499999999999999999999991
问题是向客户收费的正确值是219.77(舍入函数,中点舍入.AwayFromZero),而不是219.76

如果我将所有内容都更改为双倍,则它似乎有效:

double price = 1.0/12.0;
double quantity = 2637.18;
double result = price * quantity;  //results in 219.765

我要把所有东西都换成双倍的吗?分数还会有其他问题吗


我认为这个问题不同于,因为它并没有真正向我解释为什么使用更精确的数据类型decimal的结果比使用更少字节的double数据类型的结果更不准确(在上面的示例中)

建议使用十进制的原因是,所有可以表示为非重复小数的数字都可以准确地表示为十进制类型。现实世界中的货币单位总是不重复的小数。正如其他人所说,你们的问题是,出于某种原因,你们的价格不能用不重复的小数表示。也就是说它是
0.083333333…
。使用双精度实际上对精度没有帮助-双精度也不能准确表示1/12。在这种情况下,缺乏准确性不会导致问题,但在其他情况下可能会导致问题

更重要的是,选择使用双精度将意味着还有更多的数字无法完全准确地表示。例如0.01、0.02、0.03。。。是的,很多你可能关心的数字不能准确地表示为双精度

在这种情况下,价格从何而来的问题才是真正重要的问题。无论您在何处存储该价格,几乎可以肯定的是,并不是准确地存储
1/12
。要么你已经存储了一个近似值,要么这个价格实际上是一个计算的结果(或者你正在使用一个非常不寻常的数字存储系统,其中你存储的是有理数,但这似乎不太可能)

你真正想要的是一个可以用双精度表示的价格。如果这就是你所拥有的,但是你修改了它(例如,除以12,从年度成本中得到一个月成本),那么你需要尽可能晚地进行该划分。很可能你还需要计算每月的成本,作为未付余额的一部分。我最后一部分的意思是,如果你每月分期支付10美元,第一个月可能要收取0.83美元。然后在第二个月收取10-0.83美元/11美元。这又是0.83。在第五个月,你收取(10-0.83*4)/8,现在是0.84(四舍五入)。然后下个月是(10-0.83*4-0.84)/7,以此类推。这样,您可以保证总费用是正确的,不必担心复合错误


在一天结束时,你是唯一一个判断你是否可以重新设计你的系统以消除所有舍入错误的人,或者你是否必须像我建议的那样以某种方式减轻它们。不过,最好的办法是阅读有关浮点数的所有内容,包括十进制和二进制,以便充分理解选择一个浮点数而不是另一个浮点数的含义。

建议使用十进制的原因是,所有可以表示为非重复小数的数字都可以准确地表示为十进制类型。现实世界中的货币单位总是不重复的小数。正如其他人所说,你们的问题是,出于某种原因,你们的价格不能用不重复的小数表示。也就是说它是
0.083333333…
。使用双精度实际上对精度没有帮助-双精度也不能准确表示1/12。在这种情况下,缺乏准确性不会导致问题,但在其他情况下可能会导致问题

更重要的是,选择使用双精度将意味着还有更多的数字无法完全准确地表示。例如0.01、0.02、0.03。。。是的,很多你可能关心的数字不能准确地表示为双精度

在这种情况下,价格从何而来的问题才是真正重要的问题。无论您在何处存储该价格,几乎可以肯定的是,并不是准确地存储
1/12
。要么你已经存储了一个近似值,要么这个价格实际上是一个计算的结果(或者你正在使用一个非常不寻常的数字存储系统,其中你存储的是有理数,但这似乎不太可能)

你真正想要的是一个可以用双精度表示的价格。如果这就是你所拥有的,但是你修改了它(例如,除以12,从年度成本中得到一个月成本),那么你需要尽可能晚地进行该划分。很可能你还需要计算每月的成本,作为未付余额的一部分。我最后一部分的意思是,如果你每月分期支付10美元,第一个月可能要收取0.83美元。然后在第二个月收取10-0.83美元/11美元。这又是0.83。在第五个月,你收取(10-0.83*4)/8,现在是0.84(四舍五入)。然后下个月是(10-0.83*4-0.84)/7,以此类推。这样,您可以保证总费用是正确的,不必担心复合错误


在一天结束时,你是唯一一个判断你是否可以重新设计你的系统以消除所有舍入错误的人,或者你是否必须像我建议的那样以某种方式减轻它们。不过,最好的办法是阅读所有关于浮点数的内容,包括十进制和二进制,以便充分理解选择一个浮点数的含义。

通常,在金融计算中,乘法和除法都需要以某种方式四舍五入到一定的小数位数。(大多数货币系统只使用10个基数的货币;在这些系统中,非10个基数的货币很少出现,如果它们出现的话。)价格除以12而不超过12并不总是期望得到10个基数