簡體   English   中英

為什么Python中的浮點除法用較小的數字更快?

[英]Why is floating-point division in Python faster with smaller numbers?

在回答這個問題的過程中,我遇到了一些我無法解釋的問題。

給出以下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內部使用浮點數較小的數字和雙數字較大的數字?

它更多地與Python存儲精確整數作為Bignums。

在Python 2.7中,計算整數a / float fb ,首先將整數轉換為float。 如果整數存儲為Bignum [注1]則需要更長時間。 所以這不是具有差別成本的部門; 它是整數(可能是Bignum)到double的轉換。

Python 3對整數a / float fb執行相同的計算,但是對於整數a / integer b ,它嘗試計算最接近的可表示結果,這可能與天真float(a) / float(b)略有不同。 (這類似於經典的雙舍入問題。)

如果float(a)float(b)都是精確的(也就是說, ab都不大於53位),那么天真的解決方案就可以工作,結果只需要分割兩個雙精度浮點數。

否則,執行多精度分割以生成正確的53位尾數(指數被單獨計算),並且結果被精確地轉換為浮點數。 這種划分有兩種可能性:如果b足夠小以適合單個Bignum單位(適用於OP中的基准),則快速跟蹤;以及當b較大時,較慢的一般Bignum除法。

在上述情況中,沒有觀察到與硬件執行浮點除法的速度有關的速度差。 對於原始的Python 3.5測試,差異與是否執行浮點或Bignum除法有關; 對於Python 2.7的情況,差異與將Bignum轉換為double的必要性有關。

感謝@MarkDickinson的澄清,以及指向實現算法的源代碼(帶有長而有用的注釋)的指針。


筆記

  1. 在Python 3中,整數總是存儲為Bignums。 Python 2具有int (64位整數)和long (Bignums)的單獨類型。 實際上,由於Python 3經常使用優化算法,而Bignum只有一個“腿”,“小”和“大”整數之間的差異仍然很明顯。

正如@rici所說,它是更大的整數格式。 我將最初的10改為10.0 ......這是結果,時間沒有顯着變化。

On 10.0 1.12
On 100000.0 0.79
On 1000000000.0 0.79
On 1e+13 0.77
On 1e+17 0.78
On 1e+21 0.79
On 1e+25 0.77
On 1e+29 0.8
On 1e+33 0.77
On 1e+37 0.8
On 1e+41 0.78
On 1e+45 0.78
On 1e+49 0.78
On 1e+53 0.79
On 1e+57 0.77
On 1e+61 0.8
On 1e+65 0.77
On 1e+69 0.79
On 1e+73 0.77
On 1e+77 0.78
On 1e+81 0.78
On 1e+85 0.78
On 1e+89 0.77

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM