aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvincent.del.medico <vincent.del.medico@gmail.com>2011-06-08 22:46:14 +0000
committervincent.del.medico <vincent.del.medico@gmail.com>2011-06-08 22:46:14 +0000
commit716d5fa179b7a8b6331934403692ec199b50654a (patch)
treefb6152a2f2d8fa7d68037c7fb3fbcf84b72fb692
parentb2e8a96e21a958aa1f022d712ed9d224acda1415 (diff)
downloadlibfixmath-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.odsbin0 -> 145939 bytes
-rw-r--r--libfixmath/fix16.h8
-rw-r--r--libfixmath/fix16_trig.c30
3 files changed, 37 insertions, 1 deletions
diff --git a/images/error_analysis.ods b/images/error_analysis.ods
new file mode 100644
index 0000000..e410dd3
--- /dev/null
+++ b/images/error_analysis.ods
Binary files differ
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);