我正在做一些刚体旋转动力学模拟,这意味着我必须通过小角度计算许多旋转,这在评估三角函数时具有性能瓶颈。现在我通过Taylor(McLaurin)系列来做到这一点:
class double2{
double x,y;
// Intristic full sin/cos
final void rotate ( double a){
double x_=x;
double ca=Math.cos(a); double sa=Math.sin(a);
x=ca*x_-sa*y; y=sa*x_+ca*y;
}
// Taylor 7th-order aproximation
final void rotate_d7( double a){
double x_=x;
double a2=a*a;
double a4=a2*a2;
double a6=a4*a2;
double ca= 1.0d - a2 /2.0d + a4 /24.0d - a6/720.0d;
double sa= a - a2*a/6.0d + a4*a/120.0d - a6*a/5040.0d;
x=ca*x_-sa*y; y=sa*x_+ca*y;
}
}
但是性能速度的交易并不像我预期的那么大:
error(100x dphi=Pi/100 ) time [ns pre rotation]
v.rotate_d1() : -0.010044860504615213 9.314306 ns/op
v.rotate_d3() : 3.2624666136960023E-6 16.268745 ns/op
v.rotate_d5() : -4.600003294941146E-10 35.433617 ns/op
v.rotate_d7() : 3.416711358283919E-14 49.831547 ns/op
v.rotate() : 3.469446951953614E-16 75.70213 ns/op
有没有更快的方法如何评估sin()和cos()的近似小角度(如< Pi / 100)
我想的可能是一些理性的系列,或连续的分数近似?你知道任何? (预计算表在这里没有意义)
答案 0 :(得分:3)
您可能会发现调整计算可以提高性能。 E.g:
const double c7 = -1/5040d;
const double c5 = 1/120d;
const double c3 = -1/6d;
double a2 = a * a;
double sa = (((c7 * a2 + c5) * a2 + c3) * a2 + 1) * a;
// similarly for cos
现在优化者可能正在做一些这样的事情,所以你的里程可能会有所不同。有兴趣了解结果。
答案 1 :(得分:1)
不是优化三角函数,而是看看你是否可以不用它们。刚体仿真往往非常适合矢量数学。
答案 2 :(得分:0)
两种方法:尽可能降低精度(如在视频游戏中一样,如果你的目标是表现,则使用最低的可接受精度)
您应该尝试使用列表值。每次执行一次(当游戏加载?)时,计算一个sin / cosinus /数组,然后在恒定时间内访问。
float cosAlpha = COSINUS[(int)(k*alpha)]; // e.g: k = 1000
调整k和数组大小以选择角度分辨率与内存占用量。
编辑:不要忘记使用余弦/正弦函数的奇偶校验来避免选项卡中的重复值 edit2:尝试浮动而不是双重。差异对于玩家来说是微不足道的,而性能影响方式也很有趣。测试一下!
答案 3 :(得分:0)
你可以添加一些内联汇编程序吗?针对i386'fsincos'指令可能是最快的方法:
Vector2 unit_vector ( Angle angle ) {
Vector2 r;
//now the normal processor detection
//and various platform specific vesions
# if defined (__i386__) && !defined (NO_ASM)
# if defined __GNUC__
# define ASM_SINCOS
asm ("fsincos" : "=t" (r.x), "=u" (r.y) : "0" (angle.radians()));
# elif defined _MSC_VER
# define ASM_SINCOS
double a = angle.radians();
__asm fld a
__asm fsincos
__asm fstp r.x
__asm fstp r.y
# endif
# endif
}
来自here的。 这有一个额外的好处,就是在一次通话中计算sin和cos。
编辑:它是Java。您的轮换是否适合自我包含,您可以通过JNI一次卸载数千个?否则,这种特定于硬件的方法并不好。
答案 4 :(得分:0)
对于小x(x <0.2弧度),你可以安全地假设sin(x)= x。
最大偏差为0.0013。