aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorflatmush <flatmush@d3e1167c-abe1-51d5-8199-f9061ebe54e4>2011-02-23 17:07:17 +0000
committerflatmush <flatmush@d3e1167c-abe1-51d5-8199-f9061ebe54e4>2011-02-23 17:07:17 +0000
commitf5cb74ab2ea15ce8f4217ed5c92e349071dc73ca (patch)
tree593b8883d99f49f8448b8a9fce08cd6df49e09c1
parent5d939700e8a1ed33903067c641b7ca93abedab96 (diff)
downloadlibfixmath-f5cb74ab2ea15ce8f4217ed5c92e349071dc73ca.tar.gz
Added an optimized and improved implementation of joe's fixed point atan2 algorithm so that it now works correctly over the full range of fixed point numbers and should be much faster too.
-rw-r--r--libfixmath/fix16_trig.c105
1 files changed, 56 insertions, 49 deletions
diff --git a/libfixmath/fix16_trig.c b/libfixmath/fix16_trig.c
index c162b61..2e0ec5a 100644
--- a/libfixmath/fix16_trig.c
+++ b/libfixmath/fix16_trig.c
@@ -5,7 +5,7 @@
#ifndef FIXMATH_NO_CACHE
static fix16_t _fix16_sin_cache_index[4096] = { 0 };
static fix16_t _fix16_sin_cache_value[4096] = { 0 };
-static fix16_t _fix16_atan_cache_index[4096] = { 0 };
+static fix16_t _fix16_atan_cache_index[2][4096] = { { 0 }, { 0 } };
static fix16_t _fix16_atan_cache_value[4096] = { 0 };
#endif
@@ -68,58 +68,65 @@ fix16_t fix16_acos(fix16_t inValue) {
return ((fix16_pi >> 1) - fix16_asin(inValue));
}
-static fix16_t _fix16_atan(fix16_t inValue) {
- fix16_t tempOut;
- if(inValue > 29736) {
- tempOut = (fix16_one + fix16_mul(inValue, inValue));
- tempOut = (fix16_one + fix16_sqrt(tempOut));
- tempOut = fix16_div(inValue, tempOut);
- tempOut = _fix16_atan(tempOut);
- return (tempOut << 1);
- }
-
- fix16_t tempValue = inValue;
- fix16_t tempValSq = fix16_mul(inValue, inValue);
- tempOut = inValue;
- tempValue = fix16_mul(tempValue, tempValSq);
- tempOut += (tempValue / 3);
- tempValue = fix16_mul(tempValue, tempValSq);
- tempOut += (tempValue / 5);
- tempValue = fix16_mul(tempValue, tempValSq);
- tempOut += (tempValue / 7);
- tempValue = fix16_mul(tempValue, tempValSq);
- tempOut += (tempValue / 9);
- tempValue = fix16_mul(tempValue, tempValSq);
- tempOut += (tempValue / 11);
-
- return tempOut;
-}
-
-fix16_t fix16_atan(fix16_t inValue) {
+fix16_t fix16_atan2(fix16_t inY , fix16_t inX) {
#ifndef FIXMATH_NO_CACHE
- fix16_t tempIndex = (((inValue >> 16) ^ (inValue >> 4)) & 0x00000FFF);
- if(_fix16_atan_cache_index[tempIndex] == inValue)
- return _fix16_atan_cache_value[tempIndex];
+ uintptr_t hash = (inX ^ inY);
+ hash ^= hash >> 20;
+ hash &= 0x0FFF;
+ if((_fix16_atan_cache_index[0][hash] == inX) && (_fix16_atan_cache_index[1][hash] == inY))
+ return _fix16_atan_cache_value[hash];
#endif
- fix16_t tempOut = _fix16_atan(inValue);
+
+ fix16_t absy = (inY < 0 ? -inY : inY);
+ int64_t i = inX + (inX >= 0 ? -absy : absy);
+ int64_t j = (inX >= 0 ? inX : -inX) + absy;
+ if(j == 0)
+ return (inY < 0 ? (-fix16_pi >> 1) : (fix16_pi >> 1));
+
+ int64_t is, js;
+ int64_t angle;
+ angle = (4216574283LL * -i) / j;
+ is = (i * i);
+ is = (is + (1LL << 15)) >> 16;
+ js = (j * j);
+ js = (js + (1LL << 15)) >> 16;
+ if((is | js) >> 32) {
+ if((is | js) >> 40) {
+ is >>= 16;
+ js >>= 16;
+ } else {
+ is >>= 8;
+ js >>= 8;
+ }
+ }
+ is = (is * i);
+ is = (is + (1LL << 15)) >> 16;
+ js = (js * j);
+ js = (js + (1LL << 15)) >> 16;
+ if((is | js) >> 50) {
+ if((is | js) >> 57) {
+ is >>= 14;
+ js >>= 14;
+ } else {
+ is >>= 7;
+ js >>= 7;
+ }
+ }
+ is = is * 51472LL;
+ angle += (is / js) << 14;
+ angle += (inX >= 0 ? 3373259426LL : 10119778278LL);
+ angle = (angle + (1LL << 15)) >> 16;
+ angle = (inY < 0 ? -angle : angle);
+
#ifndef FIXMATH_NO_CACHE
- _fix16_atan_cache_index[tempIndex] = inValue;
- _fix16_atan_cache_value[tempIndex] = tempOut;
+ _fix16_atan_cache_index[0][hash] = inX;
+ _fix16_atan_cache_index[1][hash] = inY;
+ _fix16_atan_cache_value[hash] = angle;
#endif
- return tempOut;
+
+ return angle;
}
-fix16_t fix16_atan2(fix16_t inY, fix16_t inX) {
- if(inX == 0) {
- if(inY == 0)
- return 0;
- if(inY > 0)
- return (fix16_pi >> 1);
- return -(fix16_pi >> 1);
- }
- if(inY > 0)
- return fix16_atan(fix16_div(inY, inX));
- if(inY >= 0)
- return (fix16_pi + fix16_atan(fix16_div(inY, inX)));
- return (-fix16_pi + fix16_atan(fix16_div(inY, inX)));
+fix16_t fix16_atan(fix16_t inValue) {
+ return fix16_atan2(inValue, fix16_one);
}