为什么4种不同的语言在这里给出4种不同的结果?

Why do 4 different languages give 4 different results here?

考虑这个(64 位 Arch Linux 系统上的所有命令 运行):

因此,Perl、gawkR 同意,bc 和 Pyhon 2 也同意。不过,在测试的 6 个工具中,我得到了 4 个不同的结果。我知道这与整数的舍入长度有关,但为什么不同的工具差异如此之大?我曾预计这将取决于处理器处理大量数据的能力,但它似乎取决于语言的内部特性(或错误)。

有人可以解释一下这里的幕后情况吗?每种语言的局限性是什么?为什么它们的行为如此不同?

我只能回答 python 2 和 python 3 之间的区别。 “/”在 python 2 中是整数除法,而在 python 3 中是实数除法(这是 python 3 中的 .0 的来源。输出是浮点数。

总结:

  • Python 2

    10190150730169267102/1000%10 
    

    等于

    10190150730169267%10
    

    等于

    7
    
  • Python 3

    10190150730169267102/1000%10 
    

    等于

    10190150730169267,102%10
    

    等于

    7.102 
    

但由于内部表示,它被(错误地)计算为 8.0

您可能会注意到,正确答案可能是 7 或 7.102,具体取决于我们认为除法是浮点数还是整数。所以只有 Python(2) 和 bc 有正确答案。 python 3 将有整数除法 (10190150730169267102//1000%10) 的正确答案。

Python原生支持任意整数

您看到不同的结果有两个原因:

  1. 除法步骤做两件不同的事情:在您尝试过的某些语言中,它表示 整数 除法,它会丢弃结果的小数部分并只保留整数部分。在其他情况下,它表示实际的数学除法(根据 Python 的术语,我将在下面称为 "true division"),返回接近真商的浮点结果。

  2. 在某些语言(支持任意精度的语言)中,大分子值 10190150730169267102 被精确表示;在其他情况下,它被最接近的可表示浮点值替换。

上面 1. 和 2. 中的可能性的不同组合会给你不同的结果。

详细说明:在 Perl、awk 和 R 中,我们使用浮点值和真除法。值 10190150730169267102 太大而无法存储在机器整数中,因此它以通常的 IEEE 754 二进制 64 浮点格式存储。该格式不能准确表示该特定值,因此存储的是 最接近该格式可表示的值,即 10190150730169266176.0。现在我们将该近似值除以 1000,再次给出浮点结果。确切的商 10190150730169266.176 也不能用 binary64 格式精确表示,我们得到最接近的可表示浮点数,它恰好是 10190150730169266.0。取余模 10 得到 6.

在 bc 和 Python 2 中,我们使用任意精度整数和整数除法。这两种语言都可以准确地表示分子。那么除法结果就是10190150730169267(我们做的是整数除法,不是真除法,所以舍弃小数部分),余数模 107。 (这有点过分简化了:bc 在内部使用的格式在某种程度上更接近 Python 的 Decimal 类型,而不是任意精度的整数类型,但在这种情况下,效果是相同的。 )

在 Python 3 中,我们使用任意精度整数和真除法。分子被精确表示,但除法的结果是最接近真商的浮点值。在这种情况下,确切的商是 10190150730169267.102,最接近的可表示浮点值是 10190150730169268.0。取该值的余数模 10 得到 8.

总结:

  • Perl、awk、R:浮点逼近,真除法
  • bc, Python 2: 任意精度整数,整数除法
  • Python 3:任意精度整数,真除法

在 perl6 中

➜  ~  perl6 -e 'say(10190150730169267102 div 1000 mod 10)'
7
➜  ~  perl6 -e 'say(10190150730169267102/1000%10)'
7.102

所以,如果您不确定哪种语言是正确的,请尝试询问 Perl6。 :)