C/C++中双重快速反平方
最近我正在剖析一个程序,其中热点绝对是这样的
double d = somevalue(); double d2=d*d; double c = 1.0/d2 // HOT SPOT 因为我只需要值c,所以不使用值d2.前段时间我已经阅读了关于快速反平方根的Carmack方法,显然不是这样,但是我想知道一个类似的算法是否可以帮助我计算1 / x ^ 2. 我需要相当准确的精度,我检查过我的程序没有使用gcc -ffast-math选项给出正确的结果. (g -4.5) 解决方法
快速平方根等的技巧通过牺牲精度得到他们的表现. (嗯,大多数.)
您确定需要双重精度吗?您可以轻松地牺牲精度: double d = somevalue(); float c = 1.0f / ((float) d * (float) d); 在这种情况下,1.0f绝对是强制性的,如果使用1.0,那么您将获得双精度. 我发现一篇博客文章(source)讨论了您正在经历的确切问题,作者的结论是,像Carmack方法这样的技术与RCPSS指令(GCC使用的-mrecip标志)不具竞争力. 分区可能如此缓慢的原因是因为处理器通常只有一个分割单元,而且通常不是流水线的.因此,您可以在管道中同时执行几个乘法运算,但是在上一个分区完成之前不能分配. 不工作的技巧 > Carmack的方法:在现代处理器上已经过时了,它们具有相互的估计操作码.对于倒数,我看到的最好的版本只能提供一点精度 – 与RCPSS的12位相比,没有什么.我认为这是巧合,这个伎俩对于相互平方根有好的效果;巧合不大可能重复. 更新 以下是双精度浮点值的反平方的牛顿 – 拉夫逊逼近的例子. static double invsq(double x) { double y; int i; __asm__ ( "cvtpd2ps %1,%0nt" "rcpss %0,%0nt" "cvtps2pd %0,%0" : "=x"(y) : "x"(x)); for (i = 0; i < RECIP_ITER; ++i) y *= 2 - x * y; return y * y; } 不幸的是,在我的电脑上使用RECIP_ITER = 1的基准测试,它比简单版本1.0 /(x * x)略慢(约5%).它的速度更快(2x快),但是只有12位的精度.我不知道12位是否足够你. 我认为这里的一个问题是这个微型优化太小了;在这个规模上,编译器作者与装配黑客几乎相同.也许如果我们有更大的图景,我们可以看到一种方法来加快速度. 例如,你说过 – 数学造成了不合理的精度损失;这可能表示您正在使用的算法中的数值稳定性问题.利用算法的正确选择,可以通过float而不是double来解决许多问题. (当然,你可能只需要24位以上,我不知道.) 如果要并行计算其中的几个,我怀疑RCPSS方法是否发光. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |