21

これが問題ではないと主張される可能性があることは理解していますが、私は HPC 環境用のソフトウェアを作成しているため、この 3.5 倍の速度向上は実際に違いをもたらします。

In [1]: %timeit 10 / float(98765)            
1000000 loops, best of 3: 313 ns per loop

In [2]: %timeit 10 / (98765 * 1.0)
10000000 loops, best of 3: 80.6 ns per loop

以前disはコードを見ていましたfloat()が、関数呼び出しが必要なため遅くなると思います (残念ながら、dis.dis(float)実際に何をしているのかを確認できませんでした)。

2番目の質問は、いつ使用する必要があるかfloat(n)、いつ使用する必要があるかということだと思いますn * 1.0

4

1 に答える 1

28

Peep ホール オプティマイザーは、その乗算の結果を事前に計算して最適化するため、

import dis
dis.dis(compile("10 / float(98765)", "<string>", "eval"))

  1           0 LOAD_CONST               0 (10)
              3 LOAD_NAME                0 (float)
              6 LOAD_CONST               1 (98765)
              9 CALL_FUNCTION            1
             12 BINARY_DIVIDE       
             13 RETURN_VALUE        

dis.dis(compile("10 / (98765 * 1.0)", "<string>", "eval"))

  1           0 LOAD_CONST               0 (10)
              3 LOAD_CONST               3 (98765.0)
              6 BINARY_DIVIDE       
              7 RETURN_VALUE        

の結果を98765 * 1.0バイトコードに定数値として格納します。したがって、最初のケースと同様に、関数を呼び出す必要がある場合は、それをロードして分割するだけです。

このようにさらにはっきりと見ることができます

print compile("10 / (98765 * 1.0)", "<string>", "eval").co_consts
# (10, 98765, 1.0, 98765.0)

値はコンパイル時に事前に計算されるため、2 番目の方が高速です。

編集:コメントでDavidmhが指摘したように、

また、除算を最適化していない理由は、その動作がフラグなどfrom __future__ import divisionのフラグに依存しているためです-Q

Python 2.7.9 の実際のピープホール オプティマイザ コードからのコメントを引用すると、

        /* Cannot fold this operation statically since
           the result can depend on the run-time presence
           of the -Qnew flag */
于 2014-04-10T09:27:49.267 に答える