python - 为什么 Python 中的浮点除法用较小的数字更快?

标签 python performance math floating-point division

答题过程中this question ,我遇到了一些我无法解释的事情。

给定以下 Python 3.5 代码:

import time

def di(n):
    for i in range(10000000): n / 101

i = 10
while i < 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:
    start = time.clock()
    di(i)
    end = time.clock()
    print("On " + str(i) + " " + str(end-start))
    i *= 10000

输出是:

On 10 0.546889
On 100000 0.545004
On 1000000000 0.5454929999999998
On 10000000000000 0.5519709999999998
On 100000000000000000 1.330797
On 1000000000000000000000 1.31053
On 10000000000000000000000000 1.3393129999999998
On 100000000000000000000000000000 1.3524339999999997
On 1000000000000000000000000000000000 1.3817269999999997
On 10000000000000000000000000000000000000 1.3412670000000002
On 100000000000000000000000000000000000000000 1.3358929999999987
On 1000000000000000000000000000000000000000000000 1.3773859999999996
On 10000000000000000000000000000000000000000000000000 1.3326890000000002
On 100000000000000000000000000000000000000000000000000000 1.3704769999999993
On 1000000000000000000000000000000000000000000000000000000000 1.3235019999999995
On 10000000000000000000000000000000000000000000000000000000000000 1.357647
On 100000000000000000000000000000000000000000000000000000000000000000 1.3341190000000012
On 1000000000000000000000000000000000000000000000000000000000000000000000 1.326544000000002
On 10000000000000000000000000000000000000000000000000000000000000000000000000 1.3671139999999973
On 100000000000000000000000000000000000000000000000000000000000000000000000000000 1.3630120000000012
On 1000000000000000000000000000000000000000000000000000000000000000000000000000000000 1.3600200000000022
On 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1.3189189999999975
On 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1.3503469999999993

如您所见,大致有两种:一种用于较小的数字,一种用于较大的数字。

使用以下函数来保留语义的 Python 2.7 会出现相同的结果:

def di(n):
    for i in xrange(10000000): n / 101.0

在同一台机器上,我得到:

On 10 0.617427
On 100000 0.61805
On 1000000000 0.6366
On 10000000000000 0.620919
On 100000000000000000 0.616695
On 1000000000000000000000 0.927353
On 10000000000000000000000000 1.007156
On 100000000000000000000000000000 0.98597
On 1000000000000000000000000000000000 0.99258
On 10000000000000000000000000000000000000 0.966753
On 100000000000000000000000000000000000000000 0.992684
On 1000000000000000000000000000000000000000000000 0.991711
On 10000000000000000000000000000000000000000000000000 0.994703
On 100000000000000000000000000000000000000000000000000000 0.978877
On 1000000000000000000000000000000000000000000000000000000000 0.982035
On 10000000000000000000000000000000000000000000000000000000000000 0.973266
On 100000000000000000000000000000000000000000000000000000000000000000 0.977911
On 1000000000000000000000000000000000000000000000000000000000000000000000 0.996857
On 10000000000000000000000000000000000000000000000000000000000000000000000000 0.972555
On 100000000000000000000000000000000000000000000000000000000000000000000000000000 0.985676
On 1000000000000000000000000000000000000000000000000000000000000000000000000000000000 0.987412
On 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0.997207
On 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0.970129

为什么小数与大数的浮点除法之间存在这种一致的差异?这是否与 Python 在内部对较小的数字使用 float 而对较大的数字使用 double 有关?

最佳答案

它更多地与 Python 将精确整数存储为 Bignums 有关。

在 Python 2.7 中,integer a/float fb 的计算首先将整数转换为 a漂浮。如果整数存储为 Bignum [注 1],则需要更长的时间。因此,成本差异不在于部门,而在于部门。它是整数(可能是 Bignum)到 double 的转换。

Python 3 对 integer a/float fb 进行相同的计算,但是 integer a/整数 b,它会尝试计算最接近的可表示结果,这可能与朴素的 float 略有不同(a)/ float (b)。 (这类似于经典的双舍入问题。)

如果 float(a)float(b) 都是精确的(即 ab code> 不大于 53 位),那么朴素的解决方案有效,结果只需要两个 double float 相除。

否则,进行多精度除法生成正确的53位尾数(指数单独计算),并将结果精确转换为 float 。这种划分有两种可能性:如果 b 足够小以适合单个 Bignum 单元(适用于 OP 中的基准测试),则采用快速 channel ;当b 更大。

在上述任何情况下,观察到的速度差异都与硬件执行浮点除法的速度有关。对于原始的 Python 3.5 测试,差异涉及是否执行浮点或 Bignum 除法;对于 Python 2.7 的情况,差异与将 Bignum 转换为 double 的必要性有关。

感谢@MarkDickinson 的澄清,以及指向 the source code (with a long and useful comment) 的指针实现算法。


注意事项

  1. 在 Python 3 中,整数总是存储为 Bignums。 Python 2 为 int(64 位整数)和 long(Bignums)提供了不同的类型。在实践中,由于 Python 3 在 Bignum 只有一条“腿”时经常使用优化算法,因此“小”和“大”整数之间的差异仍然很明显。

关于python - 为什么 Python 中的浮点除法用较小的数字更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35418974/

相关文章:

python - 我将如何编写一个机器人,每当目标用户更改其自定义状态时,它都会向其所有者发送直接消息?

Python 游戏 "an integer is required"

python - 通过python删除mysql中的行

c# - 为什么这个算法在 Ruby 中比在 Parallel'd C# 中运行得更快?

java 。我怎样才能提高性能?

algorithm - O(n) 运行时算法

java - 将对象移动到椭圆的边缘

java - 矩阵求幂方法JAVA

python - Tensorflow - autodiff 是否让我们从 back-prop 实现中重生?

javascript - javascript中的圆形让我陷入困境