numpy 有没有一种快速的方法可以在Python中返回相同值的Sin和Cos?

xriantvc  于 2023-04-30  发布在  Python
关注(0)|答案(6)|浏览(170)

我需要返回一个大数组中每个元素的sin和cos值。目前我正在做:

a,b=np.sin(x),np.cos(x)

其中x是某个大数组。我需要保留每个结果的符号信息,因此:

a=np.sin(x)
b=(1-a**2)**0.5

是不可能的有没有更快的方法可以同时返回sin和cos?

nue99wik

nue99wik1#

我将建议的解决方案与perfplot进行了比较,发现没有什么比显式调用sincos更好的了。

用于重现绘图的代码:

import perfplot
import numpy as np

def sin_cos(x):
    return np.sin(x), np.cos(x)

def exp_ix(x):
    eix = np.exp(1j * x)
    return eix.imag, eix.real

def cos_from_sin(x):
    sin = np.sin(x)
    abs_cos = np.sqrt(1 - sin**2)
    sgn_cos = np.sign(((x - np.pi / 2) % (2 * np.pi)) - np.pi)
    cos = abs_cos * sgn_cos
    return sin, cos

b = perfplot.bench(
    setup=lambda n: np.linspace(0.0, 2 * np.pi, n),
    kernels=[sin_cos, exp_ix, cos_from_sin],
    n_range=[2**k for k in range(20)],
    xlabel="n",
)
b.save("out.png")
b.show()
k4aesqcs

k4aesqcs2#

你可以使用复数和 ei · φ = cos(φ)+ i · sin(φ) 的事实。

import numpy as np
from cmath import rect
nprect = np.vectorize(rect)

x = np.arange(2 * np.pi, step=0.01)

c = nprect(1, x)
a, b = c.imag, c.real

我在这里使用了https://stackoverflow.com/a/27788291/674064的技巧来制作一个cmath.rect()版本,它将接受并返回NumPy数组。
不过,这并没有在我的机器上获得任何加速:

c = nprect(1, x)
a, b = c.imag, c.real

所需时间约为

a, b = np.sin(x), np.cos(x)

在我的测量(50。4μs)。

4sup72z8

4sup72z83#

一个纯粹的numpy版本通过复数,eiφ = cosφ + i sinφ,灵感来自das-g的答案。

x = np.arange(2 * np.pi, step=0.01)

eix = np.exp(1j*x)
cosx, sinx = eix.real, eix.imag

这比nprect快,但仍然比sincos调用慢:

In [6]: timeit c = nprect(1, x); cosx, sinx = cos(x), sin(x)
1000 loops, best of 3: 242 us per loop

In [7]: timeit eix = np.exp(1j*x); cosx, sinx = eix.real, eix.imag
10000 loops, best of 3: 49.1 us per loop

In [8]: timeit cosx, sinx = cos(x), sin(x)
10000 loops, best of 3: 32.7 us per loop
p4tfgftt

p4tfgftt4#

为了完整起见,另一种将其组合为单个cos()调用的方法是准备一个Angular 数组,其中第二个半部分具有pi/2的相移。
借用Nico Schlömer的分析代码,我们得到:

import perfplot
import numpy as np

def sin_cos(x):
    return np.sin(x), np.cos(x)

def exp_ix(x):
    eix = np.exp(1j * x)
    return eix.imag, eix.real

def cos_shift(x):
    angles = x[np.newaxis, :] + np.array(((-np.pi/2,), (0,)))
    return tuple(np.cos(angles))

perfplot.save(
    "out.png",
    setup=lambda n: np.linspace(0.0, 2 * np.pi, n),
    kernels=[sin_cos, exp_ix, cos_shift],
    n_range=[2 ** k for k in range(1, 16)],
    xlabel="n",
)

所以它比单独的sin/cos调用慢,但在某些(狭义)环境中可能更方便,因为从cos()开始,它只需要处理单个数组。

lfapxunr

lfapxunr5#

你可以利用tan(x)包含sin(x)和cos(x)函数的事实。因此,您可以使用tan(x)并使用公共转换函数检索cos(x)和sin(x)。

sh7euo9m

sh7euo9m6#

def cosfromsin(x,sinx):
   cosx=absolute((1-sinx**2)**0.5)
   signx=sign(((x-pi/2)%(2*pi))-pi)
   return cosx*signx

a=sin(x)
b=cosfromsin(x,a)

我已经算好了时间,它比sin和cos快25%。

相关问题