Ano*_*sse 15 java math optimization trigonometry
在很多情况下,我不仅需要正弦,还需要相同参数的余弦.
对于C,sincos
公共unix m
数学库中有一个函数.实际上,至少在i386上,这应该是一个汇编指令fsincos
.
sincos,sincosf,sincosl - 同时计算sin和cos
我想这些好处是存在的,因为计算正弦和余弦有明显的重叠:sin(x)^2 + cos(x)^2 = 1
.但AFAIK并没有因为尝试将其缩短而付出代价cos = Math.sqrt(1 - sin*sin)
,因为该sqrt
功能的成本相似.
有没有办法在Java中获得相同的好处?我想我要为double[]
当时付出代价; 由于添加了垃圾收集,这可能使所有的努力都没有实际意义.
或者Hotspot编译器是否足够智能以识别我需要两者,并将其编译为sincos
命令?我可以测试它是否识别它,我可以帮助它识别这一点,例如通过确保Math.sin
和Math.cos
命令在我的代码中直接连续吗?从Java语言的角度来看,这实际上是最有意义的:让编译器优化它以使用fsincos
汇编调用.
从一些汇编文档中收集:
Variations 8087 287 387 486 Pentium
fsin - - 122-771 257-354 16-126 NP
fsincos - - 194-809 292-365 17-137 NP
Additional cycles required if operand > pi/4 (~3.141/4 = ~.785)
sqrt 180-186 180-186 122-129 83-87 70 NP
Run Code Online (Sandbox Code Playgroud)
fsincos
应该需要一个额外的弹出,但这应该在1个时钟周期.假设CPU也没有优化它,sincos
应该几乎是调用sin
两次的速度的两倍(第二次计算余弦;所以我认为它需要做一次加法).sqrt
在某些情况下可能更快,但正弦可以更快.
更新:我在C中做了一些实验,但它们没有定论.有趣的是,sincos
似乎甚至比稍快sin
(无cos
),以及GCC编译器将使用fsincos
,当你同时计算sin
并cos
-因此它希望做什么,我热点做(或做热点,太?).我还不能阻止编译器通过使用fsincos
除非不使用cos
.然后它会回落到C sin
,而不是fsin
.
Eri*_*ert 11
我用卡尺执行了一些微基准测试.在-4*pi ... 4*pi范围内的(预先计算的)随机数阵列上进行10000000次迭代.我尽力获得最快的JNI解决方案 - 我很难预测你是否会实际获得fsincos
或者模拟一些sincos
.报告的数字是10个卡尺试验中最好的(其中包括3-10个试验,其中报告的平均值).所以粗略地说,每个内循环运行30-100次.
我已经对几种变体进行了基准测试:
Math.sin
只(参考)Math.cos
只(参考)Math.sin
+ Math.cos
sincos
通过JNIMath.sin
+ cos通过Math.sqrt( (1+sin) * (1-sin) )
+符号重建Math.cos
+通过Math.sqrt( (1+cos) * (1-cos) )
+符号重建罪(1+sin)*(1-sin)=1-sin*sin
数学上,但如果罪恶接近1,它应该更精确?运行时差异很小,您可以保存一个添加项.
通过签名重建x %= TWOPI; if (x<0) x+=TWOPI;
,然后检查象限.如果你知道如何用更少的CPU来做到这一点,我会很高兴听到.
数值损失sqrt
似乎没问题,至少对于常见角度而言.在粗糙实验的1e-10范围内.
Sin 1,30 ==============
Cos 1,29 ==============
Sin, Cos 2,52 ============================
JNI sincos 1,77 ===================
SinSqrt 1,49 ================
CosSqrt 1,51 ================
Run Code Online (Sandbox Code Playgroud)
在sqrt(1-s*s)
主场迎战sqrt((1+s)*(1-s))
使得约0.01差别.正如您所看到的,sqrt
基于方法的方法胜过任何其他方法(因为我们目前无法sincos
在纯Java中访问).该JNI sincos
是不是计算好sin
和cos
,但sqrt
方法仍然较快.cos
本身似乎始终是一个更好的刻度(0,01)sin
,但重建标志的情况区别有一个额外的>
测试.我不认为我的研究结果支持,要么sin+sqrt
或cos+sqrt
明显preferrable,但他们并节省约40%时相比sin
则cos
.
如果我们将Java扩展为具有内在优化的sincos,那么这可能会更好.恕我直言,这是一个常见的用例,例如图形.当在AWT,Batik等中使用时,许多应用程序都可以从中受益.
如果我再次运行它,我还会添加JNI sin
和a noop
来估算JNI的成本.也许还sqrt
通过JNI 对这个技巧进行基准测试.只是为了确保sincos
从长远来看我们确实想要一个内在的东西.
归档时间: |
|
查看次数: |
2070 次 |
最近记录: |