我有一個相當複雜的函數,它需要幾個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