为什么4种不同的语言会给出4种不同的结果?

时间:2016-08-23 11:54:06

标签: python perl awk rounding long-integer

考虑这一点(所有命令都在64位Arch Linux系统上运行):

  • Perl(v5.24.0)

    $ perl -le 'print 10190150730169267102/1000%10'
    6
    
  • awk(GNU Awk 4.1.3)

    $ awk 'BEGIN{print 10190150730169267102/1000%10}'
    6
    
  • R(3.3.1)

    > (10190150730169267102/1000)%%10
    [1] 6
    
  • bc

    $ echo 10190150730169267102/1000%10 | bc
    7
    
  • Python 2(2.7.12)

    >>> print(10190150730169267102/1000%10)
    7
    
  • Python 3(3.5.2)

    >>> print(10190150730169267102/1000%10)
    8.0
    

所以,Perl,gawkR同意,bc和Pyhon 2.然而,在测试的6个工具之间,我得到了4个不同的结果。我知道这与整数很长的整数有什么关系,但为什么不同的工具差别很大?我曾预料到这取决于处理器处理大数字的能力,但它似乎取决于语言的内部特征(或错误)。

有人可以解释幕后发生的事情吗?每种语言有哪些限制,为什么它们的表现如此不同?

3 个答案:

答案 0 :(得分:9)

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

  1. 除法步骤有两个不同的地方:在你尝试过的某些语言中,它表示整数除法,它会丢弃结果的小数部分,只保留整数部分。在其他人中,它表示实际的数学划分(遵循Python的术语我将调用"真正的划分"在下面),返回接近真实商的浮点结果。

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

  3. 上面1.和2.中可能性的不同组合给出了不同的结果。

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

    在bc和Python 2中,我们正在处理任意精度整数和整数除法。这两种语言都可以完全代表分子。然后,除法结果为10190150730169267(我们正在执行整数除法,而不是真正的除法,因此丢弃小数部分),其余为模数107。 (这有点过于简单化了:bc在内部使用的格式比Python Decimal类型更接近于任意精度整数类型,但在这种情况下效果是相同的。)< / p>

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

    要点:

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

答案 1 :(得分:3)

我只能回答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原生支持任意整数

答案 2 :(得分:1)

in perl6

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

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