3

我一直听说由于浮点数不准确,您应该使用货币类。但是,很难找到浮点不准确实际上导致错误结果的任何示例。

我选择的编程语言是 Python。为了测试结果是否与预期不同,我使用:

expected = '1.23'
result = '{:0.2f}'.format(result)
assert expected == result

因此,虽然以下是浮点不准确性的一个很好的例子,但对于大多数用例来说,它并不是一个需要使用有理数类(如 Python 分数)的货币类的例子:

a = 10.0
b = 1.2
assert a + b - a == b

我能想到的最好的事情是

result = (a + b - a) * 10**14 - b * 10**14
expected = 0

但是将与金钱相关的东西乘以10**14似乎真的是虚构的。

现在我想知道是否有任何现实的例子表明需要货币等级,或者是否所有内容都通过简单地四舍五入到两位数来“捕获”。

4

1 回答 1

11

很难找到浮点不准确实际上导致错误结果的任何示例。

我不会说这非常困难。一个著名的现实世界例子,虽然不涉及金钱,但爱国者导弹系统代码累积了每秒 0.000000095 秒的浮点舍入误差;如果系统不是每五天重新启动一次,它就会关闭几分之一秒。由于它拦截的导弹每秒可以移动数千米,所以它会错过。

由于这个浮点错误,至少有 28 人死亡。

我们可以在不危及更多生命的情况下证明爱国者的错误。这是一个小 C# 程序。假设我们将一角硬币相加;在出现重大错误之前,我们必须添加多少?

    double sum = 0.0;
    long k = 0;
    long report = 1;
    while (true) {
        k += 1;
        sum += 0.1;
        if (k == report) {
            Console.WriteLine($"{k} {k / 10.0 - sum}");
            report *= 10;
        }
    }

让它运行多久就运行多久。我机器上的输出开始了:

1 0
10 1.11022302462516E-16
100 1.95399252334028E-14
1000 1.406874616805E-12
10000 -1.58820512297098E-10
100000 -1.88483681995422E-08
1000000 -1.33288267534226E-06
10000000 0.00016102462541312
100000000 0.0188705492764711
1000000000 1.25458218157291
10000000000 -163.12445807457

在仅仅一亿次计算之后——所以,1000 万美元——我们已经减少了 2 美分。通过 100 亿次计算,我们减少了 163.12 美元。当然,这是每笔交易的一个小错误,与 10 亿美元相比,163.12 美元在宏伟的计划中可能不是很多钱,但如果我们不能正确计算 1 亿乘以 0.1,那么我们就没有理由相信任何来自这个系统的计算。

可以保证误差为零;为什么希望错误为零?

练习:您暗示您知道将四舍五入放在哪里以确保消除此错误。那么:他们去哪儿了?


受您的评论启发的一些其他想法:

虽然我认为货币类肯定需要十进制数据类型,但我认为这还不够。我认为货币类别还应该(1)防止添加非货币数字(2)防止添加两种不同的货币(3)不允许获取权力/根源。

如果您想要的是真实世界的货币错误示例,这些示例涉及不受类型系统限制的计量单位,那么有很多很多这样的示例。

我曾经在一家编写检测软件缺陷的软件的公司工作。最神奇的缺陷检查器之一是“剪切和粘贴错误”检测器,它在现实世界的代码中发现了一个缺陷,例如

dollarTot = (euros1 + euros2) * dollarEuroRate;
pesoTot = (euros3 + euros4) * pesoEuroRate;
... dozens more like this...

然后在代码中

dollarTot = (yen1 + yen2) * yenDollarRate;
pesoTot = (yen3 + yen4) * pesoEuroRate;
...

哎呀。

有这个缺陷的主要国际贸易公司打电话给我们,说下次我们在瑞士时啤酒就在他们身上。

此类示例说明了为什么金融机构对 F# 等语言如此感兴趣,因为 F# 使得在类型系统中跟踪属性变得超级容易。

几年前,我在我的博客上做了一个系列文章,内容是在实现虚拟机时使用 ML 类型系统来查找错误,其中整数可能意味着十几个不同数据结构的地址,或者这些结构的偏移量。它可以快速发现错误,并且运行时开销很小。度量单位类型很棒,即使是简单的问题,比如确保你不会把美元和日元混在一起。

于 2018-06-13T18:31:01.457 回答