从 sin(a) 得到 cos(a) 的最佳方法

发布于 2024-12-17 17:02:14 字数 400 浏览 2 评论 0原文

s 作为某个(未知)角度“a”的正弦,获得“a 的余弦”的最快方法是什么?

我知道两种明显的方法:

c = cos(asin(s));

c = sqrt(1 - s*s);

但我不知道函数 cos()、asin() 和 sqrt() 的实现在速度方面如何相互比较。一个比另一个快多快?它们在现代处理器中的实现(例如 x86-64 和带有 VFP 的 ARM)之间是否存在显着差异?最后,更好的解决方案是什么?

编辑:由于现在已经有 3 个不相关的答案,让我澄清一下:我最初没有角度,我拥有的只是正弦。所以不需要告诉我将角度旋转 90 度,这样我就可以从其他函数获得相同的值......

Having s as sine of some (unknown) angle "a", what is the fastest way to get the "cosine of a"?

I know two obivious ways:

c = cos(asin(s));

and

c = sqrt(1 - s*s);

But I don't know how the implementation of the functions cos(), asin() and sqrt() compares to one another in regarding speed. How faster is one over another? Are there significant difference between their implementations in modern processors, say, between x86-64 and ARM with VFP? In the end, what is the better solution?

Edit: Since there are already 3 unrelated answers now, let me clarify: I don't initally have the angle, all I have is the sine. So there is no need to tell me to rotate the angle 90 degrees so I'll have the same value from the other function...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

梅窗月明清似水 2024-12-24 17:02:14

这是一种方法:

sin(a)^2 + cos(a)^2 = 1(毕达哥拉斯)

cos(a) = sqrt(1 - sin(a)^2))

您需要找出不同的象限(即分别 cos() 的符号)。如果您拥有的只是 sin() 值(不同角度可以具有相同的 sin() 但 cos() 符号不同),则这是不可能的。

正如其他人指出的那样,查找表实际上可能是最快的。取决于你需要什么精度。这几乎肯定会比你的 cos(asin()) 版本更快,并且 平方根也可以在实践中进行优化

  • SSE 和 ARM-NEON 有平方根指令,但没有三角函数。
  • x87 有平方根和 sin/cos,但没有反 sin/cos 函数。平方根比 sin/cos 更快。

在我的 Core i3 笔记本电脑上,使用 Visual Studio 2010,此方法的性能比基于三角函数的版本(具有快速浮点选项)快约 6 倍(每次调用约 20 纳秒)。让我们看看生成的代码:

快速浮点选项,使用平方根:

; 15   :     return sqrt(1.0 - s*s);

    movsd   xmm1, QWORD PTR __real@3ff0000000000000
    mulsd   xmm0, xmm0
    subsd   xmm1, xmm0
    sqrtsd  xmm0, xmm1

使用三角函数:

; 22   :     return cos(asin(s));
call    ___libm_sse2_asin
jmp ___libm_sse2_cos

当切换到精确浮点模式时,生成的三角代码使用不同的函数(大概是 SSE 优化版本牺牲了精度):

fld QWORD PTR _angle_sin$[esp+esi+65600]
call    __CIasin
call    __CIcos
fstp    QWORD PTR _angle_cos$[esp+esi+65600]

Here's one way:

sin(a)^2 + cos(a)^2 = 1 (pythagoras)

cos(a) = sqrt(1 - sin(a)^2))

You need to figure out the different quadrants (i.e. the sign of the cos() seperately). This is not possible if all you have is the sin() value (different angles can have the same sin() but cos() differs by sign).

As other people noted a lookup table may in practice be the fastest. Depends on what precision you require. This is almost certainly going to be faster than your cos(asin()) version and the square root can also be optimized in practice.

  • SSE and ARM-NEON have a square root instruction but no trig functions.
  • x87 has square root and sin/cos but no inverse sin/cos functions. Square root is faster than sin/cos.

Using Visual studio 2010 the performance of this method is about 6 times faster than the trig based version (with fast floating point option) on my Core i3 laptop (about 20ns per call). Let's look at the generated code:

Fast floating point option, using square root:

; 15   :     return sqrt(1.0 - s*s);

    movsd   xmm1, QWORD PTR __real@3ff0000000000000
    mulsd   xmm0, xmm0
    subsd   xmm1, xmm0
    sqrtsd  xmm0, xmm1

Using trig functions:

; 22   :     return cos(asin(s));
call    ___libm_sse2_asin
jmp ___libm_sse2_cos

When switching to precise floating point mode the generated trig code uses different functions (presumably the SSE optimized versions sacrifices accuracy):

fld QWORD PTR _angle_sin$[esp+esi+65600]
call    __CIasin
call    __CIcos
fstp    QWORD PTR _angle_cos$[esp+esi+65600]
冷…雨湿花 2024-12-24 17:02:14

最好的方法是使用 eps * sqrt(1 - s * s) ,其中 eps 是加或减 1。这是最好的方法

  • ,就准确性而言,因为 1 - s * s 保持接近于 1,因此计算平方根的误差很小。 计算 的余弦如果你处于“接近一”的情况,反正弦可能会失去精度(练习:1/为什么?提示:记住 sin 在 pi/2 处最大,其导数消失 2/ 尝试一下。) 编辑:我说得太快了,因为当s接近1时,sqrt(1 - s * s)也有同样的问题。
  • 就速度而言:平方根很容易(一些类似牛顿的方法的一些算术运算),但不清楚 asin 的作用(可能相当昂贵),cos 可能比 sqrt 慢一个数量级,因此一个平方根可能比这两个超越函数调用更快。有疑问,个人资料(但我准备赌一些钱)。

忘记查找表,直到您证明 sqrt(1 - s * s) 对您来说不够快(即使如此,您也可以找到方法来权衡一些 sqrt代码>速度的准确性)。

The best way is to use eps * sqrt(1 - s * s), where eps is plus or minus one. It is the best way

  • In term of accuracy, since 1 - s * s stays close to one and therefore the error in computing the square root is minimal. Computing the cosine of the arc sine may lose you precision if you are in the 'near one' case (exercise: 1/ why ? hint: remember that sin is maximal at pi/2 and its derivative vanishes 2/ Try it.) EDIT: I spoke too fast, since sqrt(1 - s * s) has the same problems when s is close to one.
  • In term of speed: square rooting is easy (a few arithmetical operations for some newton-like method), but it is not clear what asin does (probably quite costly), cos is likely to be one order of magnitude slower than sqrt, and thus one square root is likely to be quickier than those two transcendental function calls. In doubt, profile (but I'm ready to bet some money).

Forget about look up tables until you have proven that sqrt(1 - s * s) is not fast enough for you (and even there, you can find ways to trade off some sqrt accuracy for speed).

国粹 2024-12-24 17:02:14

用极坐标可视化单位圆。 r=1,theta =(角度)。则单位圆上 X,Y(笛卡尔)坐标中的任意点为 ( cos( theta ), sin ( theta ))。

visualize the unit circle with polar coordinates. r=1, theta = (the angle ). then any point on the unit circle in X,Y ( cartesian ) coordinates is ( cos( theta ), sin ( theta )).

情痴 2024-12-24 17:02:14

Sin 和 Cos 只是同一条曲线偏移二分之一弧度(或 90 度),因此:

sin(a) = cos(a + pi/2)
cos(a) = sin(pi/2 - a)

pi 为 3.14159...

Sin and Cos are simply the same curve offset by one-half radian (or 90 degrees), so:

sin(a) = cos(a + pi/2)
cos(a) = sin(pi/2 - a)

pi being 3.14159...

夜血缘 2024-12-24 17:02:14

如果您的 sin/cos 函数采用弧度:

cos(x) === sin(x+pi/2)

如果您的 sin/cos 函数采用度数:

cos(x) === sin(x+90)

If your sin/cos functions take radians:

cos(x) === sin(x+pi/2)

If your sin/cos functions take degrees:

cos(x) === sin(x+90)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文