我有一个相当复杂的函数,它需要几个double值,它们表示以纬度和经度为弧度的形式(大小,纬度,经度)的3维空间中的两个向量以及一个角度。函数的作用是将第一个向量绕第二个向量旋转指定的角度并返回合成向量。我已经验证该代码在逻辑上是正确的并且可行。如何计算反向触发(和sqrt)函数(C语言)的浮点运算中的舍入错误?
函数的预期用途是用于图形,所以不需要双精度;然而,在目标平台上,使用浮点数(sinf,cosf,atan2f,asinf,acosf和sqrtf)的trig(和sqrt)函数在double上的运行速度要快于浮点数(可能是因为计算这些值的指令实际上可能需要double;如果传递一个float值,则该值必须转换为double值,这要求将其复制到具有更多内存的区域 - 即开销)。因此,函数中涉及的所有变量都是双精度的。
这是问题:我试图优化我的功能,以便它可以被称为每秒更多次。因此,我将这些调用替换为sin,cos,sqrt等调用这些函数的浮点版本,因为它们导致总体速度提高3-4倍。这适用于几乎所有的输入;然而,如果输入矢量接近于与标准单位矢量(i,j或k)平行,则各种函数的舍入误差会足以导致稍后调用sqrtf或反函数trig函数(asinf,acosf, atan2f)在这些函数的域之外传递参数仅仅是。因此,我留下了这个困境:要么我只能调用双精度函数,并避免这个问题(并且每秒最多可以有大约1,300,000个向量操作),或者我可以试着想出一些东西其他。最终,我想要一种方法来消除对反向trig函数的输入以处理边缘情况(对于sqrt,这样做很简单:只需使用abs)。分支不是一种选择,因为即使是单个条件语句也会增加很多开销,以至于性能增益都会丢失。
那么,有什么想法?
编辑:有人对我使用双打和浮点操作表示困惑。如果我实际上将所有值存储在双倍大小的容器中(I.E. double-type变量),则将函数存储在浮动大小容器中的速度要快得多。但是,由于显而易见的原因,浮点精度触发操作比双精度触发操作要快。
有研究有关整个场“如何计算错误”,在所谓的近似算法[数值分析](http://en.wikipedia.org/wiki/Numerical_analysis)。 – 2010-11-13 08:30:06
事实证明,我看到的速度增加实际上是由于NaN引起的,而不是由于使用浮点运算而不是双运算。所以,这个问题有一个不正确的基础。 – Collin 2010-11-16 19:29:12
如果你的旋转算法使用先前旋转过的矢量,那么你在每次迭代/循环/帧或其他任何事情后都会失去精度。为了说明你应该计算你已经旋转了多少次,并且如果计数器达到某个阈值(任何数字),则从原始值或几何属性中校正所有向量(如果你知道它们的假定长度,或者某些向量应该是互相垂直,...),它会减慢计算曾经在一段时间,但一般不会影响性能太多(实验treshold实现速度/精度之间的折衷) – Spektre 2013-08-20 13:36:43