diff options
| author | vincent.del.medico <vincent.del.medico@gmail.com> | 2011-06-08 22:46:14 +0000 |
|---|---|---|
| committer | vincent.del.medico <vincent.del.medico@gmail.com> | 2011-06-08 22:46:14 +0000 |
| commit | 716d5fa179b7a8b6331934403692ec199b50654a (patch) | |
| tree | fb6152a2f2d8fa7d68037c7fb3fbcf84b72fb692 | |
| parent | b2e8a96e21a958aa1f022d712ed9d224acda1415 (diff) | |
| download | libfixmath-716d5fa179b7a8b6331934403692ec199b50654a.tar.gz | |
Added a new algo for sin() function, and a small error analysis to show the precision differences
| -rw-r--r-- | images/error_analysis.ods | bin | 0 -> 145939 bytes | |||
| -rw-r--r-- | libfixmath/fix16.h | 8 | ||||
| -rw-r--r-- | libfixmath/fix16_trig.c | 30 |
3 files changed, 37 insertions, 1 deletions
diff --git a/images/error_analysis.ods b/images/error_analysis.ods Binary files differnew file mode 100644 index 0000000..e410dd3 --- /dev/null +++ b/images/error_analysis.ods diff --git a/libfixmath/fix16.h b/libfixmath/fix16.h index dfb8cb7..7763389 100644 --- a/libfixmath/fix16.h +++ b/libfixmath/fix16.h @@ -10,6 +10,10 @@ extern "C" typedef int32_t fix16_t;
+static const fix16_t FOUR_DIV_PI = 0x145F3; /*!< Fix16 value of 4/PI */
+static const fix16_t _FOUR_DIV_PI2 = 0xFFFF9840; /*!< Fix16 value of -4/PI² */
+static const fix16_t X4_CORRECTION_COMPONENT = 0x399A; /*!< Fix16 value of 0.225 */
+
static const fix16_t fix16_max = 0x7FFFFFFF; /*!< the maximum value of fix16_t */
static const fix16_t fix16_min = 0x80000000; /*!< the minimum value of fix16_t */
@@ -80,7 +84,9 @@ extern fix16_t fix16_lerp16(fix16_t inArg0, fix16_t inArg1, uint16_t inFract); extern fix16_t fix16_lerp32(fix16_t inArg0, fix16_t inArg1, uint32_t inFract);
#endif
-
+/*! Returns the sine of the given fix16_t.
+*/
+extern fix16_t fix16_sin_parabola(fix16_t inAngle);
/*! Returns the sine of the given fix16_t.
*/
diff --git a/libfixmath/fix16_trig.c b/libfixmath/fix16_trig.c index a198b3d..2f92d31 100644 --- a/libfixmath/fix16_trig.c +++ b/libfixmath/fix16_trig.c @@ -1,3 +1,4 @@ +#include <limits.h>
#include "fix16.h"
#if defined(FIXMATH_SIN_LUT)
@@ -13,6 +14,35 @@ static fix16_t _fix16_atan_cache_value[4096] = { 0 }; #endif
+fix16_t fix16_sin_parabola(fix16_t inAngle)
+{
+ fix16_t abs_inAngle, abs_retval, retval;
+ fix16_t mask;
+
+ /* Absolute function */
+ mask = (inAngle >> (sizeof(fix16_t)*CHAR_BIT-1));
+ abs_inAngle = (inAngle + mask) ^ mask;
+
+ /* On 0->PI, sin looks like x² that is :
+ - centered on PI/2,
+ - equals 1 on PI/2,
+ - equals 0 on 0 and PI
+ that means : 4/PI * x - 4/PI² * x²
+ Use abs(x) to handle (-PI) -> 0 zone.
+ */
+ retval = fix16_mul(FOUR_DIV_PI, inAngle) + fix16_mul( fix16_mul(_FOUR_DIV_PI2, inAngle), abs_inAngle );
+ /* At this point, retval equals sin(inAngle) on important points ( -PI, -PI/2, 0, PI/2, PI),
+ but is not very precise between these points
+ */
+ #ifndef FIXMATH_FAST_SIN
+ /* Absolute value of retval */
+ mask = (retval >> (sizeof(fix16_t)*CHAR_BIT-1));
+ abs_retval = (retval + mask) ^ mask;
+ /* So improve its precision by adding some x^4 component to retval */
+ retval += fix16_mul(X4_CORRECTION_COMPONENT, fix16_mul(retval, abs_retval) - retval );
+ #endif
+ return retval;
+}
fix16_t fix16_sin(fix16_t inAngle) {
fix16_t tempAngle = inAngle % (fix16_pi << 1);
|
