繁体   English   中英

圆形浮动具有非精确表示

[英]Rounding floats with non-exact representation

对于某些财务计算,我们在浮点数的舍入方面存在问题。

基本上,我们希望将货币金额(如1000000000.555)舍入为2位小数。 但是,此数字的浮点表示为1000000000.5549999,因此我们将向下舍入到1000000000.55而不是正确的1000000000.56。

我们有什么方法可以安全地解决这个问题吗? 到目前为止,我们唯一想到的是始终在舍入操作之前添加最小的可表示浮点数,但我们不知道在所有情况下这是否安全。

代码是用C语言编写的,需要在windows32 / 64 / linux / solaris上运行,所以我们很遗憾无法获得像.net中的Decimal数据类型这样的好东西。

任何输入都会有所帮助。

谢谢,里卡德

最常用的表示货币的方法是使用整数。 例如,在欧元区,一种常见的方法是用微欧元(1E-6)来表示价值。 你显然会使用64位数学。 你会在整个应用程序中始终如一地使用它。 只有在人类I / O上你才能完成,你可以通过除以10000得到一个整数的分数。

这个故事的寓意永远不会用浮点数代表金钱!

货币是分散的,大多数财务和会计法规都承认这一点。 你不能以3.145217美元的身价支付账单。 虽然在17世纪,将硬币投入铁匠并让他将一块银币切成碎片是可以接受的(八块碎片有很好的披萨切片标记来帮助这个过程!)今天它是不可能的。

例如,瑞士最小的硬币是5 rappe,因此会计和账单必须表示为最接近的5美分,即您无法获得3.14瑞士法郎的账单,必须是3.15瑞士法郎,或者如果您的供应商不太可能,则为3.10瑞士法郎慷慨,因为你只能支付3.10或3.15现金。

你也有两种选择。 获取boost BigDecimal库,它可以精确指定舍入。 或者,正如另一张海报所建议的那样,使用long long表示您的金额为千分之一欧元,并且只显示四舍五入。

另一种可能性是使用半美分单位,即55欧元35美分,内部代表11070美分,然后不必担心任何标准会计交易的四舍五入。

我无法担心您没有正确地捕获您的业务要求。 在我的上一个项目中,有超过一百页的业务规则处理利率计算,至少40页涉及计算的每个阶段的小数位数或要使用的舍入算法。

我建议使用十进制数字包,例如decNumber

如果您在Windows中并且愿意编写托管C / C ++。

在大多数情况下,您只需使用十进制 来自MSDN

Decimal值类型适用于需要大量有效积分和小数位且没有舍入误差的财务计算。

如果您不能或不愿意使用托管C / C ++,请查看十进制数字包,例如decNumber

在这两种情况下,您都应该进行大量的单元和集成测试,以覆盖带有舍入的边角情况。 他们会给你最大的痛苦。 四舍五入非常善于隐藏其他错误。

但是正如其他人所说的那样,你要小心翼翼。 例如,在英国所得税软件规格中,大约一半的文本是关于在哪里以及如何(在每个地方不同)与圆形数字,因为你必须得到相同的结果,然后使用手动税表。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM