为什么使用`float`函数比乘以1.0慢?

22

我知道这可能被认为是无关紧要的问题,但我写的软件是针对高性能计算环境的,所以这个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) 看它实际上在做什么)。

我猜第二个问题是何时应该使用float(n),何时应该使用n * 1.0


4
除了两个字典查找(全局和内置)和一个函数调用的区别外,第二个可能应用了常量折叠。 - user2357112
1
没有常量折叠(即当我用变量替换“98765”时),结果更接近,但是float仍然稍微慢一些。至于为什么你可能想要使用float,原因是它可以进行统一转换,比如float('1.0') - bereal
1个回答

29

因为Peep hole优化器通过预先计算该乘法的结果来进行优化。

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)

由于该值在编译时已经预先计算好了,所以第二个更快。

编辑:正如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 */

8
它没有对除法进行优化的原因是其行为取决于标志,例如 from __future__ import division - Davidmh
1
@Davidmh 谢谢 :) 我也在答案中包含了那个。 - thefourtheye
我知道float()(调用__float__魔术方法)的目的与乘以1.0有很大不同,但我经常看到Python 2整数除法被教为a/float(b)(或通过from __future__ import division),我试图弄清楚这里是否有超出float()能够处理具有__float__方法的任意类型的原因。 - Jason P
考虑到这个编译器不会优化除法,所以 OP 真的应该预先计算 0.0010125044f。 - user1196549
1
@JasonP 这个除法可以通过程序中未设置的标志位进行控制。这就是为什么它不会进行优化的原因。 - thefourtheye
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接