什么是显示需要Money类的现实示例?

Mar*_*oma 3 currency floating-accuracy rational-numbers

我一直听说你应该使用钱类,因为浮点不准确.然而,令人惊讶的是,很难找到浮点不准确实际导致错误结果的任何示例.

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

expected = '1.23'
result = '{:0.2f}'.format(result)
assert expected == result
Run Code Online (Sandbox Code Playgroud)

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

a = 10.0
b = 1.2
assert a + b - a == b
Run Code Online (Sandbox Code Playgroud)

我能想到的最好的事情是

result = (a + b - a) * 10**14 - b * 10**14
expected = 0
Run Code Online (Sandbox Code Playgroud)

但是与货币相关的东西相乘10**14似乎真的已经弥补了.

现在我想知道是否有任何现实的例子表明需要一个金钱类或者如果通过简单地四舍五入到两位来"捕获"所有东西.

Eri*_*ert 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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

只要你愿意,就让它运行.我机器上的输出开始了:

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
Run Code Online (Sandbox Code Playgroud)

经过一亿次计算 - 所以,1000万美元 - 我们已经下了2美分.通过100亿次计算,我们的票价为163.12美元.当然,每次交易都是一个微小的错误,在宏观计划中可能只有163.12美元并不是很多钱,相比之下只有10亿美元,但如果我们无法正确计算1亿次0.1,那么我们就没有理由相信任何来自这个系统的计算.

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

练习:您暗示您知道将舍入放在何处以确保消除此错误.那么:他们去哪了?


一些额外的想法,受到你的评论的启发:

虽然我认为金钱类肯定需要十进制数据类型,但我认为这还不够.我认为金钱类也应该(1)防止增加非货币数量(2)防止增加两种不同的货币(3)不允许取得权力/根源.

如果你想要的是涉及计量单位不被类型系统困住的货币错误的现实例子,那么有许多这样的例子.

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

dollarTot = (euros1 + euros2) * dollarEuroRate;
pesoTot = (euros3 + euros4) * pesoEuroRate;
... dozens more like this...
Run Code Online (Sandbox Code Playgroud)

然后在代码中

dollarTot = (yen1 + yen2) * yenDollarRate;
pesoTot = (yen3 + yen4) * pesoEuroRate;
...
Run Code Online (Sandbox Code Playgroud)

哎呀.

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

这些例子说明了为什么金融机构对F#等语言如此感兴趣,这使得在类型系统中跟踪属性非常容易.

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