为什么x ** 3比x * x * x慢?

这个问题在这里已经有了答案:

  • 计算能力的速度(用python)6个答案

  • 按照这个答案,这是因为幂运算的实现有一些乘法运算没有的开销。 然而,随着指数的增加,初始乘法会变得越来越慢。 经验证明:

     In [3]: x = np.random.rand(1e6)
    
     In [15]: %timeit x**2
     100 loops, best of 3: 11.9 ms per loop
    
     In [16]: %timeit x*x
     100 loops, best of 3: 12.7 ms per loop
    
     In [17]: %timeit x**3
     10 loops, best of 3: 132 ms per loop
    
     In [18]: %timeit x*x*x
     10 loops, best of 3: 27.2 ms per loop
    
     In [19]: %timeit x**4
     10 loops, best of 3: 132 ms per loop
    
     In [20]: %timeit x*x*x*x
     10 loops, best of 3: 42.4 ms per loop
    
     In [21]: %timeit x**10
     10 loops, best of 3: 132 ms per loop
    
     In [22]: %timeit x*x*x*x*x*x*x*x*x*x
     10 loops, best of 3: 137 ms per loop
    
     In [24]: %timeit x**15
     10 loops, best of 3: 132 ms per loop
    
     In [25]: %timeit x*x*x*x*x*x*x*x*x*x*x*x*x*x*x
     1 loops, best of 3: 212 ms per loop
    

    请注意指数运算时间保持不变,除了我怀疑是特例的x**2情况,乘法运算速度越来越慢。 看来你可以利用这个来获得更快的整数求幂...例如:

    In [26]: %timeit x**16
    10 loops, best of 3: 132 ms per loop
    
    In [27]: %timeit x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x
    1 loops, best of 3: 225 ms per loop
    
    In [28]: def tosixteenth(x):
       ....:     x2 = x*x
       ....:     x4 = x2*x2
       ....:     x8 = x4*x4
       ....:     x16 = x8*x8
       ....:     return x16
       ....:
    
    In [29]: %timeit tosixteenth(x)
    10 loops, best of 3: 49.5 ms per loop
    

    看来你可以应用这种技术,一般是将任意整数分成两个幂的和,然后计算两个幂的和,然后求和:

    In [93]: %paste
    def smartintexp(x, exp):
        result = np.ones(len(x))
        curexp = np.array(x)
        while True:
            if exp%2 == 1:
                result *= curexp
            exp >>= 1
            if not exp: break
            curexp *= curexp
        return result
    ## -- End pasted text --
    
    In [94]: x
    Out[94]:
    array([ 0.0163407 ,  0.57694587,  0.47336487, ...,  0.70255032,
            0.62043303,  0.0796748 ])
    
    In [99]: x**21
    Out[99]:
    array([  3.01080670e-38,   9.63466181e-06,   1.51048544e-07, ...,
             6.02873388e-04,   4.43193256e-05,   8.46721060e-24])
    
    In [100]: smartintexp(x, 21)
    Out[100]:
    array([  3.01080670e-38,   9.63466181e-06,   1.51048544e-07, ...,
             6.02873388e-04,   4.43193256e-05,   8.46721060e-24])
    
    In [101]: %timeit x**21
    10 loops, best of 3: 132 ms per loop
    
    In [102]: %timeit smartintexp(x, 21)
    10 loops, best of 3: 70.7 ms per loop
    

    对于两个小的偶数幂来说,它是快速的:

    In [106]: %timeit x**32
    10 loops, best of 3: 131 ms per loop
    
    In [107]: %timeit smartintexp(x, 32)
    10 loops, best of 3: 57.4 ms per loop
    

    但随着指数变大变慢:

    In [97]: %timeit x**63
    10 loops, best of 3: 133 ms per loop
    
    In [98]: %timeit smartintexp(x, 63)
    10 loops, best of 3: 110 ms per loop
    

    对于大型最坏情况,速度并不快:

    In [115]: %timeit x**511
    10 loops, best of 3: 135 ms per loop
    
    In [114]: %timeit smartintexp(x, 511)
    10 loops, best of 3: 192 ms per loop
    

    作为一个说明,如果你正在计算能力并担心速度:

    x = np.random.rand(5e7)
    
    %timeit x*x*x
    1 loops, best of 3: 522 ms per loop
    
    %timeit np.einsum('i,i,i->i',x,x,x)
    1 loops, best of 3: 288 ms per loop
    

    为什么Einsum更快速仍然是我的一个悬而未决的问题。 虽然它像由于einsum能够使用SSE2而numpy的的ufuncs不会到1.8。

    到位速度更快:

    def calc_power(arr):
        for x in xrange(arr.shape[0]):
            arr[x]=arr[x]*arr[x]*arr[x]
    numba_power = autojit(calc_power)
    
    %timeit numba_power(x)
    10 loops, best of 3: 51.5 ms per loop
    
    %timeit np.einsum('i,i,i->i',x,x,x,out=x)
    10 loops, best of 3: 111 ms per loop
    
    %timeit np.power(x,3,out=x)
    1 loops, best of 3: 609 ms per loop
    

    我期望这是因为x**y必须处理xy都是浮点数的一般情况。 在数学上,我们可以写x**y = exp(y*log(x)) 。 遵循你的例子,我发现

    x = np.random.rand(1e6)
    %timeit x**3
    10 loops, best of 3: 178 ms per loop
    
    %timeit np.exp(3*np.log(x))
    10 loops, best of 3: 176 ms per loop
    

    我没有检查实际的numpy代码,但它必须在内部做这样的事情。

    链接地址: http://www.djcxy.com/p/15021.html

    上一篇: Why is x**3 slower than x*x*x?

    下一篇: Add (FMA) instructions with SSE/AVX