对于某些财务计算,我们在浮点数的舍入方面存在问题。
基本上,我们希望将货币金额(如1000000000.555)舍入为2位小数。但是,此数字的浮点表示为1000000000.5549999,因此我们将向下舍入到1000000000.55而不是正确的1000000000.56。
我们有什么方法可以安全地解决这个问题?到目前为止我们唯一想到的是在舍入操作之前总是将最小的可表示浮点数添加到金额中,但我们不知道这在所有情况下都是安全的。
代码是用C语言编写的,需要在windows32 / 64 / linux / solaris上运行,所以我们很遗憾无法访问像.net中的Decimal数据类型这样的好东西。
任何输入都会有所帮助。
谢谢, 里卡德
答案 0 :(得分:10)
最常表示货币的正确方法是使用整数。例如,在欧元区,一种常见的方法是用微欧元(1E-6)来表示价值。你显然会使用64位数学。你会在整个应用程序中始终如一地使用它。只有在人类I / O上你才能完成,你可以通过除以10000得到一个整数的分数。
答案 1 :(得分:5)
这个故事的寓意永远不会用浮点数代表金钱!
货币是分散的,大多数财务和会计法规都承认这一点。你不能以3.145217美元的身价支付账单。虽然在17世纪,将硬币投入铁匠并让他将一块银币切成碎片是可以接受的(八块碎片有很好的披萨切片标记来帮助这个过程!)今天它是不可能的。
例如,瑞士最小的硬币是5 rappe,所以会计和账单必须用最接近的5美分表示,即你不能得到3.14瑞士法郎的账单,它必须是3.15瑞士法郎,或者在不太可能的情况下3.100瑞士法郎你的供应商是慷慨的,因为你只能支付3.10或3.15现金。
你也有两种选择。获取boost BigDecimal库,它可以精确指定舍入。或者,正如另一张海报所建议的那样,使用long long表示您的金额,以千分之一欧元表示,并且只显示四舍五入。
另一种可能性是使用半美分单位,即55欧元35美分在内部表示为11070美分,然后不必担心任何标准会计交易的四舍五入。
我无法担心您没有正确捕获业务要求。在我的上一个项目中,有超过一百页的业务规则处理利率计算,至少40页涉及计算的每个阶段的小数位数或要使用的舍入算法。
答案 2 :(得分:4)
我建议使用十进制数字包,例如decNumber。
答案 3 :(得分:0)
如果您在Windows中并且愿意编写托管C / C ++。
在大多数情况下,您只需使用decimal class即可。来自MSDN
十进制值类型是合适的 用于需要的财务计算 大量的重要积分 和小数位,没有四舍五入 错误。
如果您无法或不愿意使用托管C / C ++,请查看十进制数字包,例如decNumber。
在这两种情况下,您都应该进行大量的单元和集成测试,以覆盖带有舍入的极端情况。他们会给你最大的痛苦。舍入也非常善于隐藏其他错误。
然而正如其他人所说的那样,你要小心翼翼。例如,在英国所得税软件规范中,大约一半的文本是关于在哪里以及如何(在每个地方不同)到圆形数字,因为你必须得到相同的结果然后使用人工税表。