3

对于某些财务计算,我们遇到浮点数舍入问题。

基本上,我们希望将像 1000000000.555 这样的货币金额四舍五入到小数点后两位。但是,这个数字的浮点表示是 1000000000.5549999,因此我们将向下舍入到 1000000000.55,而不是正确的 1000000000.56。

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

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

任何输入都会有所帮助。

谢谢,里卡德

4

4 回答 4

10

最常见的表示货币的正确方法是使用整数。例如,在欧元区,一种常见的方法是以微欧元 (1E-6) 表示值。您显然会为此使用 64 位数学。您将在整个应用程序中始终使用它。只有在人工 I/O 上,你才会四舍五入,你可以通过除以 10000 来获得以美分为单位的整数。

于 2009-08-25T07:56:12.797 回答
5

这个故事的寓意是,永远,永远不要使用浮点数来代表金钱!

金钱的数量是离散的,大多数财务和会计法规都承认这一点。您无法实际支付 3.145217 美元的账单。虽然在 17 世纪,将一枚硬币交给铁匠并让他将一元银元切成碎片是可以接受的(八块有很好的披萨切片标记来帮助这个过程!)今天这是不可能的。

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

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

另一种可能性是使用半美分的单位,即 55 欧元 35 美分在内部表示为 11070 半美分,那么不需要担心任何标准会计交易的四舍五入。

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

于 2009-08-25T09:33:38.467 回答
4

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

于 2009-08-25T07:57:13.077 回答
0

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

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

Decimal 值类型适用于需要大量有效整数和小数位数且无舍入错误的财务计算。

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

在这两种情况下,您都应该进行大量单元测试和集成测试,这些测试涵盖了四舍五入的极端情况。他们会给你最大的痛苦。舍入也非常擅长隐藏其他错误。

然而,正如其他人所说,在你轮到的地方要非常小心。例如,在英国所得税软件规范中,大约一半的文本是关于在何处以及如何(在每个地方不同)对整数进行舍入,因为您必须使用手动税表获得相同的结果。

于 2009-08-25T08:28:24.447 回答