我們,開發人員經常需要計算角度來執行旋轉。通常我們可以使用atan2()函數,但有時我們需要更高的精度。那你怎麼辦呢?在計算角度時避免atan2 - atan2精度
我知道理論上atan2是精確的,但在我的系統(iOS)中,它對於0.05弧度是不準確的,所以它有很大的不同。這不僅僅是我的問題。我見過類似的意見。
我們,開發人員經常需要計算角度來執行旋轉。通常我們可以使用atan2()函數,但有時我們需要更高的精度。那你怎麼辦呢?在計算角度時避免atan2 - atan2精度
我知道理論上atan2是精確的,但在我的系統(iOS)中,它對於0.05弧度是不準確的,所以它有很大的不同。這不僅僅是我的問題。我見過類似的意見。
如果您的系統中的long double
比double
更精確,您可以使用atan2l
。
long double atan2l(long double y, long double x);
在目前的ARM iOS設備上,'long double'只是映射到'double',所以使用它不會獲得任何精度。您將在iOS模擬器中獲得更高的精度,因爲它在Mac上運行。 – 2012-01-09 19:30:56
atan2
被用來從一個向量(x,y)
得到的角度a
。如果您使用此角度應用旋轉,則將使用cos(a)
和sin(a)
。你可以簡單地通過歸一化(x,y)來計算cos和sin,並保留它們而不是角度。精度會更高,並且可以節省三角函數中大量的週期。
編輯。如果您確實需要(x,y)的角度,則可以使用CORDIC的變體來計算所需的精度。
在iOS上,我發現標準的三角函數運算符精確到13或14位十進制數,所以聽起來很奇怪,你看到0.05弧度量級的錯誤。如果您可以生成代碼和具體的數值來證明這一點,請在行爲上提供file a bug report(並在此處發佈代碼以便我們可以記錄它)。這就是說,如果你真的需要三角算子的高精度,我已經修改了Dave DeLong爲他的DDMathParser代碼創建的一些例程。這些例程使用NSDecimal來執行數學運算,給出高達約34位的小數精度,同時避免標準浮點問題,代表基數爲10的小數。您可以從here下載這些修改的例程的代碼。的atan()
的NSDecimal版本使用下面的代碼來計算:
NSDecimal DDDecimalAtan(NSDecimal x) {
// from: http://en.wikipedia.org/wiki/Inverse_trigonometric_functions#Infinite_series
// The normal infinite series diverges if x > 1
NSDecimal one = DDDecimalOne();
NSDecimal absX = DDDecimalAbsoluteValue(x);
NSDecimal z = x;
if (NSDecimalCompare(&one, &absX) == NSOrderedAscending)
{
// y = x/(1 + sqrt(1+x^2))
// Atan(x) = 2*Atan(y)
// From: http://www.mathkb.com/Uwe/Forum.aspx/math/14680/faster-Taylor-s-series-of-Atan-x
NSDecimal interiorOfRoot;
NSDecimalMultiply(&interiorOfRoot, &x, &x, NSRoundBankers);
NSDecimalAdd(&interiorOfRoot, &one, &interiorOfRoot, NSRoundBankers);
NSDecimal denominator = DDDecimalSqrt(interiorOfRoot);
NSDecimalAdd(&denominator, &one, &denominator, NSRoundBankers);
NSDecimal y;
NSDecimalDivide(&y, &x, &denominator, NSRoundBankers);
NSDecimalMultiply(&interiorOfRoot, &y, &y, NSRoundBankers);
NSDecimalAdd(&interiorOfRoot, &one, &interiorOfRoot, NSRoundBankers);
denominator = DDDecimalSqrt(interiorOfRoot);
NSDecimalAdd(&denominator, &one, &denominator, NSRoundBankers);
NSDecimal y2;
NSDecimalDivide(&y2, &y, &denominator, NSRoundBankers);
// NSDecimal two = DDDecimalTwo();
NSDecimal four = DDDecimalFromInteger(4);
NSDecimal firstArctangent = DDDecimalAtan(y2);
NSDecimalMultiply(&z, &four, &firstArctangent, NSRoundBankers);
}
else
{
BOOL shouldSubtract = YES;
for (NSInteger n = 3; n < 150; n += 2) {
NSDecimal numerator;
if (NSDecimalPower(&numerator, &x, n, NSRoundBankers) == NSCalculationUnderflow)
{
numerator = DDDecimalZero();
n = 150;
}
NSDecimal denominator = DDDecimalFromInteger(n);
NSDecimal term;
if (NSDecimalDivide(&term, &numerator, &denominator, NSRoundBankers) == NSCalculationUnderflow)
{
term = DDDecimalZero();
n = 150;
}
if (shouldSubtract) {
NSDecimalSubtract(&z, &z, &term, NSRoundBankers);
} else {
NSDecimalAdd(&z, &z, &term, NSRoundBankers);
}
shouldSubtract = !shouldSubtract;
}
}
return z;
}
這裏使用泰勒級數逼近,一些快捷鍵的速度收斂。我相信精度可能不是完全的34位數,非常接近Pi/4弧度,所以我可能仍然需要解決這個問題。
如果您需要極高的精度,這是一個選項,但您的報告不應該與double
的值一起發生,所以這裏有些奇怪。
經常使用角度?不,你沒有。在我看到一個開發人員使用角度的10次中,有7次他應該使用線性代數來避免任何三角函數。
旋轉最好用矩陣完成,而不是用角度完成。也看到這個問題:
我希望我可以給這個答案10ooo投票!在我看來,當你使用atan2計算角度(即知道delta_x和delta_y)時,三角函數濫用的比例接近95%... – gboffi 2016-11-30 08:40:37
你需要比1E-15弧度更精確?真? – 2012-01-07 12:11:14
可能重複的[CGAffineTranformRotate atan2不準確](http://stackoverflow.com/questions/8766128/cgaffinetranformrotate-atan2-inaccuration) – jrturton 2012-01-07 13:03:47
不,它不重複。這是關於iOS和其他系統的atan2問題的一般問題。在這裏,我並沒有要求解決上述問題的解決方案(因爲我已經以不同的方式解決了問題),我只是爲了瞭解而問。我認爲其他開發者有時會遇到類似的困難,所以這是一個普遍的問題。 – wczekalski 2012-01-07 14:55:19