什么是最快,最有效和最Python方式执行数学西格玛和的方式?

I_D*_*ode 3 python math loops numpy sum

假设我要进行数学求和,例如Madhava–Leibniz公式表示?,在Python中:

                                                               由latex.codecogs.com/gif.latex?%5Cfrac%7B%5Cpi%7D%7B4%7D%5Capprox%20%5Csum_%7Bk%3D0%7D%5E%7Bn%7D%20%5Cfrac%7B%28生成-1%29%5Ek%7D%7B2k + 1%7D

在一个名为Leibniz_pi()的函数中,我可以创建一个循环来计算第n 部分和,例如:

def Leibniz_pi(n):
    nth_partial_sum = 0       #initialize the variable
    for i in range(n+1):
        nth_partial_sum += ((-1)**i)/(2*i + 1)
    return nth_partial_sum
Run Code Online (Sandbox Code Playgroud)

我假设使用xrange()代替range()会更快。使用numpy及其内置的numpy.sum()方法会更快吗?这样的例子是什么样的?

max*_*111 5

我猜大多数人会使用@num定义最快的解决方案,而仅使用numpy作为最大的pythonic,但这肯定不是最快的。通过一些其他优化,您可以将已经快的numpy实现击败50倍。

仅使用Numpy(@zero)

import numpy as np
import numexpr as ne
import numba as nb

def Leibniz_point(n):
    val = (-1)**n / (2*n + 1)
    return val

%timeit Leibniz_point(np.arange(1000)).sum()
33.8 µs ± 203 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Run Code Online (Sandbox Code Playgroud)

利用numexpr

n=np.arange(1000)
%timeit ne.evaluate("sum((-1)**n / (2*n + 1))")
21 µs ± 354 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Run Code Online (Sandbox Code Playgroud)

使用Numba编译函数

# with error_model="numpy", turns off division-by-zero checks 
@nb.njit(error_model="numpy",cache=True)
def Leibniz_pi(n):
  nth_partial_sum = 0.       #initialize the variable as float64
  for i in range(n+1):
      nth_partial_sum += ((-1)**i)/(2*i + 1)
  return nth_partial_sum

%timeit Leibniz_pi(999)
6.48 µs ± 38.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Run Code Online (Sandbox Code Playgroud)

编辑,优化代价高昂的(-1)** n

import numba as nb
import numpy as np

#replacement for the much more costly (-1)**n
@nb.njit()
def sgn(i):
    if i%2>0:
        return -1.
    else:
        return 1.

# with error_model="numpy", turns off the division-by-zero checks
#
# fastmath=True makes SIMD-vectorization in this case possible
# floating point math is in general not commutative
# e.g. calculating four times sgn(i)/(2*i + 1) at once and then the sum 
# is not exactly the same as doing this sequentially, therefore you have to
# explicitly allow the compiler to make the optimizations

@nb.njit(fastmath=True,error_model="numpy",cache=True)
def Leibniz_pi(n):
    nth_partial_sum = 0.       #initialize the variable
    for i in range(n+1):
        nth_partial_sum += sgn(i)/(2*i + 1)
    return nth_partial_sum

%timeit Leibniz_pi(999)
777 ns ± 5.36 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Run Code Online (Sandbox Code Playgroud)