├── libfixmath ├── .gitignore ├── fixmath.h ├── Makefile ├── fix32_sqrt.c ├── int128.h ├── fix32_trig.c ├── fix32_exp.c ├── fix32.h └── fix32.c ├── unittests ├── .gitignore ├── unittests.h ├── Makefile ├── fix32_exp_unittests.c └── fix32_unittests.c ├── README.md ├── LICENSE └── fixsingen └── main.c /libfixmath/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a -------------------------------------------------------------------------------- /unittests/.gitignore: -------------------------------------------------------------------------------- 1 | fix32_unittests_ro64 2 | fix32_unittests_no64 3 | fix32_unittests_rn64 4 | fix32_unittests_nn64 5 | fix32_exp_unittests -------------------------------------------------------------------------------- /libfixmath/fixmath.h: -------------------------------------------------------------------------------- 1 | #ifndef __libfixmath_fixmath_h__ 2 | #define __libfixmath_fixmath_h__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | /*! 10 | \file fixmath.h 11 | \brief Functions to perform fast accurate fixed-point math operations. 12 | */ 13 | 14 | //#include "uint32.h" 15 | #include "int128.h" 16 | //#include "fract32.h" 17 | #include "fix32.h" 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libfixmath64 2 | 3 | A derived version of https://github.com/PetteriAimonen/libfixmath, converted into Q31.32 (Q31) format for larger integer range. This library suits best to 64-bit machines with no FPO available. 4 | 5 | Some of the tests are not converted yet completely, but most of them work and you can run them. The rest of the original repository (the sin LUT for example) shall be added later. 6 | 7 | License: MIT -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jussi Hietanen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /libfixmath/Makefile: -------------------------------------------------------------------------------- 1 | #Project settings 2 | PROJECT = libfixmath 3 | LIB = 4 | SRC = . 5 | INC = 6 | 7 | #Compiler settings 8 | CPP = gcc 9 | CC = gcc 10 | AS = gcc 11 | LD = gcc 12 | AR = ar 13 | CPP_FLAGS = -O2 $(INC) -Wall -Wextra -c 14 | CC_FLAGS = -O2 $(INC) -Wall -Wextra -c 15 | AS_FLAGS = $(CC_FLAGS) -D_ASSEMBLER_ 16 | LD_FLAGS = -Wall 17 | 18 | # Find all source files 19 | SRC_CPP = $(foreach dir, $(SRC), $(wildcard $(dir)/*.cpp)) 20 | SRC_C = $(foreach dir, $(SRC), $(wildcard $(dir)/*.c)) 21 | SRC_S = $(foreach dir, $(SRC), $(wildcard $(dir)/*.S)) 22 | OBJ_CPP = $(patsubst %.cpp, %.o, $(SRC_CPP)) 23 | OBJ_C = $(patsubst %.c, %.o, $(SRC_C)) 24 | OBJ_S = $(patsubst %.S, %.o, $(SRC_S)) 25 | OBJ = $(OBJ_CPP) $(OBJ_C) $(OBJ_S) 26 | 27 | # Compile rules. 28 | .PHONY : all 29 | all: $(PROJECT).a 30 | 31 | $(PROJECT).a: $(OBJ) 32 | $(AR) rcs $(PROJECT).a $(OBJ) 33 | 34 | $(OBJ_CPP) : %.o : %.cpp 35 | $(CPP) $(CPP_FLAGS) -o $@ $< 36 | 37 | $(OBJ_C) : %.o : %.c 38 | $(CC) $(CC_FLAGS) -o $@ $< 39 | 40 | $(OBJ_S) : %.o : %.S 41 | $(AS) $(AS_FLAGS) -o $@ $< 42 | 43 | 44 | 45 | # Clean rules 46 | .PHONY : clean 47 | clean: 48 | rm -f $(PROJECT).a $(OBJ) 49 | -------------------------------------------------------------------------------- /fixsingen/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../libfixmath/fixmath.h" 6 | 7 | int main(int argc, char** argv) { 8 | FILE* fp = fopen("fix32_trig_sin_lut.h", "wb"); 9 | if(fp == NULL) { 10 | fprintf(stderr, "Error: Unable to open file for writing.\n"); 11 | return EXIT_FAILURE; 12 | } 13 | 14 | // TODO - Store as uint16_t with a count to determine the end and return 1. 15 | 16 | fprintf(fp, "#ifndef __fix32_trig_sin_lut_h__\n"); 17 | fprintf(fp, "#define __fix32_trig_sin_lut_h__\n"); 18 | fprintf(fp, "\n"); 19 | 20 | fix32_t fix32_sin_lut_count = (fix32_pi >> (1+16)); 21 | fix32_t* fix32_sin_lut = malloc(sizeof(fix32_t) * fix32_sin_lut_count); 22 | 23 | fix32_t i; 24 | for(i = 0; i < fix32_sin_lut_count; i++) 25 | fix32_sin_lut[i] = fix32_from_dbl(sin(fix32_to_dbl(i<<16))); 26 | for(i--; fix32_sin_lut[i] == fix32_one; i--, fix32_sin_lut_count--); 27 | 28 | fprintf(fp, "static const uint32_t _fix32_sin_lut_count = %"PRIi32";\n", fix32_sin_lut_count); 29 | fprintf(fp, "static uint32_t _fix32_sin_lut[%"PRIi32"] = {", fix32_sin_lut_count); 30 | 31 | for(i = 0; i < fix32_sin_lut_count; i++) { 32 | if((i & 7) == 0) 33 | fprintf(fp, "\n\t"); 34 | fprintf(fp, "%"PRIi32", ", fix32_sin_lut[i]); 35 | } 36 | fprintf(fp, "\n\t};\n"); 37 | 38 | fprintf(fp, "\n"); 39 | fprintf(fp, "#endif\n"); 40 | 41 | free(fix32_sin_lut); 42 | fclose(fp); 43 | 44 | return EXIT_SUCCESS; 45 | } 46 | -------------------------------------------------------------------------------- /unittests/unittests.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define COMMENT(x) printf("\n----" x "----\n"); 4 | #define STR(x) #x 5 | #define STR2(x) STR(x) 6 | #define TEST(x) \ 7 | if (!(x)) { \ 8 | fflush(stdout); \ 9 | fflush(stderr); \ 10 | fprintf(stderr, "\033[31;1mFAILED:\033[22;39m " __FILE__ ":" STR2(__LINE__) " " #x "\n"); \ 11 | status = 1; \ 12 | } else { \ 13 | fflush(stdout); \ 14 | fflush(stderr); \ 15 | printf("\033[32;1mOK:\033[22;39m " #x "\n"); \ 16 | } 17 | 18 | #define TEST_FLOAT_ERROR(x, result, thres) \ 19 | if (abs(fix32_to_float(result) - fix32_to_float((x))) > thres) { \ 20 | fflush(stdout); \ 21 | fflush(stderr); \ 22 | fprintf(stderr, "\033[31;1mFAILED:\033[22;39m " __FILE__ ":" STR2(__LINE__) " " #x "\n"); \ 23 | status = 1; \ 24 | } else { \ 25 | fflush(stdout); \ 26 | fflush(stderr); \ 27 | printf("\033[32;1mOK:\033[22;39m " #x " = %f \n", fix32_to_float((x))); \ 28 | } 29 | 30 | #define TEST_DOUBLE_ERROR(x, result, thres) \ 31 | if (abs(fix32_to_dbl(result) - fix32_to_dbl((x))) > thres) { \ 32 | fflush(stdout); \ 33 | fflush(stderr); \ 34 | fprintf(stderr, "\033[31;1mFAILED:\033[22;39m " __FILE__ ":" STR2(__LINE__) " " #x " = %f != %f\n", fix32_to_dbl((x)), fix32_to_dbl(result)); \ 35 | status = 1; \ 36 | } else { \ 37 | fflush(stdout); \ 38 | fflush(stderr); \ 39 | printf("\033[32;1mOK:\033[22;39m " #x " = %f \n", fix32_to_dbl((x))); \ 40 | } 41 | -------------------------------------------------------------------------------- /libfixmath/fix32_sqrt.c: -------------------------------------------------------------------------------- 1 | #include "fix32.h" 2 | 3 | /* The square root algorithm is quite directly from 4 | * http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29 5 | * An important difference is that it is split to two parts 6 | * in order to use only 64-bit operations. 7 | * 8 | * Note that for negative numbers we return -sqrt(-inValue). 9 | * Not sure if someone relies on this behaviour, but not going 10 | * to break it for now. It doesn't slow the code much overall. 11 | */ 12 | fix32_t fix32_sqrt(fix32_t inValue) 13 | { 14 | uint8_t neg = (inValue < 0); 15 | uint64_t num = (neg ? -inValue : inValue); 16 | uint64_t result = 0; 17 | uint64_t bit; 18 | uint8_t n; 19 | 20 | bit = (uint64_t)1 << 62; 21 | 22 | while (bit > num) bit >>= 2; 23 | 24 | // The main part is executed twice, in order to avoid 25 | // > 64 bit values in computations. 26 | for (n = 0; n < 2; n++) 27 | { 28 | // First we get the top 24 bits of the answer. 29 | while (bit) 30 | { 31 | if (num >= result + bit) 32 | { 33 | num -= result + bit; 34 | result = (result >> 1) + bit; 35 | } 36 | else 37 | { 38 | result = (result >> 1); 39 | } 40 | bit >>= 2; 41 | } 42 | 43 | if (n == 0) 44 | { 45 | // Then process it again to get the lowest bits. 46 | if (num > 4294967295) 47 | { 48 | // The remainder 'num' is too large to be shifted left 49 | // by 32, so we have to add 1 to result manually and 50 | // adjust 'num' accordingly. 51 | // num = a - (result + 0.5)^2 52 | // = num + result^2 - (result + 0.5)^2 53 | // = num - result - 0.5 54 | num -= result; 55 | num = (num << 32) - 0x80000000; 56 | result = (result << 32) + 0x80000000; 57 | } 58 | else 59 | { 60 | num <<= 32; 61 | result <<= 32; 62 | } 63 | 64 | bit = 1 << 30; 65 | } 66 | } 67 | 68 | #ifndef FIXMATH_NO_ROUNDING 69 | // Finally, if next bit would have been 1, round the result upwards. 70 | if (num > result) 71 | { 72 | result++; 73 | } 74 | #endif 75 | 76 | return (neg ? -(fix32_t)result : (fix32_t)result); 77 | } 78 | -------------------------------------------------------------------------------- /unittests/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for running the unittests of libfixmath. 2 | CC = gcc 3 | 4 | # Basic CFLAGS for debugging 5 | CFLAGS = -g -O0 -I../libfixmath -Wall -Wextra -Werror 6 | 7 | # The files required for tests 8 | FIX32_SRC = ../libfixmath/fix32.c ../libfixmath/fix32_sqrt.c ../libfixmath/fix32_str.c \ 9 | ../libfixmath/fix32_exp.c ../libfixmath/fix32.h 10 | 11 | all: run_fix32_unittests run_fix32_exp_unittests run_fix32_str_unittests 12 | 13 | clean: 14 | rm -f fix32_unittests_???? 15 | rm -f fix32_str_unittests_default 16 | rm -f fix32_str_unittests_no_ctype 17 | rm -f fix32_exp_unittests 18 | 19 | # The library is tested automatically under different compilations 20 | # options. 21 | # 22 | # Test naming: 23 | # r = rounding, n = no rounding 24 | # o = overflow detection, n = no overflow detection 25 | # 64 = int64_t math, 32 = int32_t math 26 | 27 | run_fix32_unittests: \ 28 | fix32_unittests_ro64 fix32_unittests_no64 \ 29 | fix32_unittests_rn64 fix32_unittests_nn64 30 | $(foreach test, $^, \ 31 | echo $(test) && \ 32 | ./$(test) > /dev/null && \ 33 | ) true 34 | 35 | fix32_unittests_no64: DEFINES=-DFIXMATH_NO_ROUNDING 36 | fix32_unittests_rn64: DEFINES=-DFIXMATH_NO_OVERFLOW 37 | fix32_unittests_nn64: DEFINES=-DFIXMATH_NO_ROUNDING -DFIXMATH_NO_OVERFLOW 38 | fix32_str_unittests_no_ctype: DEFINES=-DFIXMATH_NO_CTYPE 39 | 40 | fix32_unittests_% : fix32_unittests.c $(FIX32_SRC) 41 | $(CC) $(CFLAGS) $(DEFINES) -o $@ $^ -lm 42 | 43 | 44 | # Tests for the exponential function, run only in default config 45 | run_fix32_exp_unittests: fix32_exp_unittests 46 | ./fix32_exp_unittests > /dev/null 47 | 48 | fix32_exp_unittests: fix32_exp_unittests.c $(FIX32_SRC) 49 | $(CC) $(CFLAGS) $(DEFINES) -o $@ $^ -lm 50 | 51 | # Tests for string conversion, run only in default config and no ctype 52 | run_fix32_str_unittests: fix32_str_unittests_default fix32_str_unittests_no_ctype 53 | ./fix32_str_unittests_default > /dev/null 54 | ./fix32_str_unittests_no_ctype > /dev/null 55 | 56 | fix32_str_unittests_%: fix32_str_unittests.c $(FIX32_SRC) 57 | $(CC) $(CFLAGS) $(DEFINES) -o $@ $^ -lm 58 | 59 | # Tests for literal macros, run only in default config 60 | run_fix32_macros_unittests: fix32_macros_unittests 61 | ./fix32_macros_unittests > /dev/null 62 | 63 | fix32_macros_unittests: fix32_macros_unittests.c $(FIX32_SRC) 64 | $(CC) $(CFLAGS) $(DEFINES) -o $@ $^ -lm 65 | 66 | -------------------------------------------------------------------------------- /unittests/fix32_exp_unittests.c: -------------------------------------------------------------------------------- 1 | //#include "../libfixmath/fix32.h" 2 | //#include 3 | //#include 4 | //#include 5 | //#include "unittests.h" 6 | // 7 | //#define delta(a,b) (((a)>=(b)) ? (a)-(b) : (b)-(a)) 8 | // 9 | //int main() 10 | //{ 11 | // int status = 0; 12 | // { 13 | // COMMENT("Testing fix32_exp() corner cases"); 14 | // TEST(fix32_exp(0) == fix32_one); 15 | // TEST(fix32_exp(fix32_minimum) == 0); 16 | // TEST(fix32_exp(fix32_maximum) == fix32_maximum); 17 | // } 18 | // 19 | // { 20 | // COMMENT("Testing fix32_exp() accuracy over -4..4"); 21 | // 22 | // fix32_t max_delta = -1; 23 | // fix32_t worst = 0; 24 | // fix32_t sum = 0; 25 | // int count = 0; 26 | // fix32_t a; 27 | // 28 | // // the original implementation took forever to run this, so I made the 29 | // // range a little shorter 30 | // for (a = fix32_from_dbl(-0.4); a < fix32_from_dbl(0.4); a += 63) 31 | // { 32 | // fix32_t result = fix32_exp(a); 33 | // fix32_t resultf = fix32_from_dbl(exp(fix32_to_dbl(a))); 34 | // 35 | // fix32_t d = delta(result, resultf); 36 | // if (d > max_delta) 37 | // { 38 | // max_delta = d; 39 | // worst = a; 40 | // } 41 | // 42 | // sum += d; 43 | // count++; 44 | // } 45 | // 46 | // printf("Worst delta %ld with input %ld\n", max_delta, worst); 47 | // printf("Average delta %0.2f\n", (float)sum / count); 48 | // 49 | // TEST(max_delta < 200); 50 | // } 51 | // 52 | // { 53 | // COMMENT("Testing fix32_exp() accuracy over full range"); 54 | // 55 | // float max_delta = -1; 56 | // fix32_t worst = 0; 57 | // float sum = 0; 58 | // int count = 0; 59 | // fix32_t a; 60 | // 61 | // // Test the whole range of results 0..32768 with a bit less samples 62 | // for (a = -772243; a < 681391; a += 113) 63 | // { 64 | // fix32_t result = fix32_exp(a); 65 | // fix32_t resultf = fix32_from_dbl(exp(fix32_to_dbl(a))); 66 | // 67 | // fix32_t d1 = delta(result, resultf); 68 | // 69 | // if (d1 > 0) d1--; // Forgive +-1 for the fix32_t inaccuracy 70 | // 71 | // float d = (float)d1 / resultf * 100; 72 | // 73 | // if (resultf < 1000) continue; // Percentages can explode when result is almost 0. 74 | // 75 | // if (d > max_delta) 76 | // { 77 | // max_delta = d; 78 | // worst = a; 79 | // } 80 | // 81 | // sum += d; 82 | // count++; 83 | // } 84 | // 85 | // printf("Worst delta %0.4f%% with input %ld\n", max_delta, worst); 86 | // printf("Average delta %0.4f%%\n", sum / count); 87 | // 88 | // TEST(max_delta < 1); 89 | // } 90 | // 91 | // { 92 | // COMMENT("Testing fix32_log() accuracy over full range"); 93 | // 94 | // fix32_t max_delta = -1; 95 | // fix32_t worst = 0; 96 | // fix32_t sum = 0; 97 | // int count = 0; 98 | // fix32_t a; 99 | // 100 | // for (a = 100; a > 0 && a < fix32_maximum - 7561; a += 7561) 101 | // { 102 | // fix32_t result = fix32_log(a); 103 | // fix32_t resultf = fix32_from_dbl(log(fix32_to_dbl(a))); 104 | // 105 | // fix32_t d = delta(result, resultf); 106 | // if (d > max_delta) 107 | // { 108 | // max_delta = d; 109 | // worst = a; 110 | // } 111 | // 112 | // sum += d; 113 | // count++; 114 | // } 115 | // 116 | // printf("Worst delta %ld with input %ld\n", max_delta, worst); 117 | // printf("Average delta %0.2f\n", (float)sum / count); 118 | // 119 | // TEST(max_delta < 20); 120 | // } 121 | // 122 | // if (status != 0) 123 | // fprintf(stdout, "\n\nSome tests FAILED!\n"); 124 | // 125 | // return status; 126 | //} 127 | -------------------------------------------------------------------------------- /libfixmath/int128.h: -------------------------------------------------------------------------------- 1 | #ifndef __libfixmath_int64_h__ 2 | #define __libfixmath_int64_h__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | #include 10 | 11 | 12 | typedef struct { 13 | int64_t hi; 14 | uint64_t lo; 15 | } _int128_t; 16 | 17 | static inline _int128_t int128_const(int64_t hi, uint64_t lo) { return (_int128_t){ hi, lo }; } 18 | static inline _int128_t int128_from_int64(int64_t x) { return (_int128_t){ (x < 0 ? -1 : 0), x }; } 19 | static inline int64_t int128_hi(_int128_t x) { return x.hi; } 20 | static inline uint64_t int128_lo(_int128_t x) { return x.lo; } 21 | 22 | static inline int int128_cmp_eq(_int128_t x, _int128_t y) { return ((x.hi == y.hi) && (x.lo == y.lo)); } 23 | static inline int int128_cmp_ne(_int128_t x, _int128_t y) { return ((x.hi != y.hi) || (x.lo != y.lo)); } 24 | static inline int int128_cmp_gt(_int128_t x, _int128_t y) { return ((x.hi > y.hi) || ((x.hi == y.hi) && (x.lo > y.lo))); } 25 | static inline int int128_cmp_ge(_int128_t x, _int128_t y) { return ((x.hi > y.hi) || ((x.hi == y.hi) && (x.lo >= y.lo))); } 26 | static inline int int128_cmp_lt(_int128_t x, _int128_t y) { return ((x.hi < y.hi) || ((x.hi == y.hi) && (x.lo < y.lo))); } 27 | static inline int int128_cmp_le(_int128_t x, _int128_t y) { return ((x.hi < y.hi) || ((x.hi == y.hi) && (x.lo <= y.lo))); } 28 | 29 | static inline _int128_t int128_add(_int128_t x, _int128_t y) { 30 | _int128_t ret; 31 | ret.hi = x.hi + y.hi; 32 | ret.lo = x.lo + y.lo; 33 | if((ret.lo < x.lo) || (ret.hi < y.hi)) 34 | ret.hi++; 35 | return ret; 36 | } 37 | 38 | static inline _int128_t int128_neg(_int128_t x) { 39 | _int128_t ret; 40 | ret.hi = ~x.hi; 41 | ret.lo = ~x.lo + 1; 42 | if(ret.lo == 0) 43 | ret.hi++; 44 | return ret; 45 | } 46 | 47 | static inline _int128_t int128_sub(_int128_t x, _int128_t y) { 48 | return int128_add(x, int128_neg(y)); 49 | } 50 | 51 | static inline _int128_t int128_shift(_int128_t x, int8_t y) { 52 | _int128_t ret; 53 | if(y > 0) { 54 | if(y >= 64) 55 | return (_int128_t){ 0, 0 }; 56 | ret.hi = (x.hi << y) | (x.lo >> (64 - y)); 57 | ret.lo = (x.lo << y); 58 | } else { 59 | y = -y; 60 | if(y >= 64) 61 | return (_int128_t){ 0, 0 }; 62 | ret.lo = (x.lo >> y) | (x.hi << (64 - y)); 63 | ret.hi = (x.hi >> y); 64 | } 65 | return ret; 66 | } 67 | 68 | static inline _int128_t int128_mul_i64_i64(int64_t x, int64_t y) { 69 | int32_t hi[2] = { (x >> 32), (y >> 32) }; 70 | uint32_t lo[2] = { (x & 0xFFFFFFFF), (y & 0xFFFFFFFF) }; 71 | 72 | int64_t r_hi = hi[0] * hi[1]; 73 | int64_t r_md = (hi[0] * lo[1]) + (hi[1] * lo[0]); 74 | uint64_t r_lo = lo[0] * lo[1]; 75 | 76 | r_hi += (r_md >> 32); 77 | r_lo += (r_md << 32); 78 | 79 | return (_int128_t){ r_hi, r_lo }; 80 | } 81 | 82 | static inline _int128_t int128_mul_i64_i32(_int128_t x, int64_t y) { 83 | int neg = ((x.hi ^ y) < 0); 84 | if(x.hi < 0) 85 | x = int128_neg(x); 86 | if(y < 0) 87 | y = -y; 88 | 89 | uint64_t _x[4] = { (x.hi >> 32), (x.hi & 0xFFFFFFFF), (x.lo >> 32), (x.lo & 0xFFFFFFFF) }; 90 | uint64_t _y[2] = { (y >> 32), (y & 0xFFFFFFFF) }; 91 | 92 | uint64_t r[4]; 93 | r[0] = (_x[0] * _y[0]); 94 | r[1] = (_x[1] * _y[0]) + (_x[0] * _y[1]); 95 | r[2] = (_x[1] * _y[1]) + (_x[2] * _y[0]); 96 | r[3] = (_x[2] * _y[0]) + (_x[1] * _y[1]); 97 | 98 | _int128_t ret; 99 | ret.lo = r[0] + (r[1] << 32); 100 | ret.hi = (r[3] << 32) + r[2] + (r[1] >> 32); 101 | return (neg ? int128_neg(ret) : ret); 102 | } 103 | 104 | static inline _int128_t int128_div_i128_i64(_int128_t x, int64_t y) { 105 | int neg = ((x.hi ^ y) < 0); 106 | if(x.hi < 0) 107 | x = int128_neg(x); 108 | if(y < 0) 109 | y = -y; 110 | 111 | _int128_t ret = { (x.hi / y) , (x.lo / y) }; 112 | x.hi = x.hi % y; 113 | x.lo = x.lo % y; 114 | 115 | _int128_t _y = int128_from_int64(y); 116 | 117 | _int128_t i; 118 | for(i = int128_from_int64(1); int128_cmp_lt(_y, x); _y = int128_shift(_y, 1), i = int128_shift(i, 1)); 119 | 120 | while(x.hi) { 121 | _y = int128_shift(_y, -1); 122 | i = int128_shift(i, -1); 123 | if(int64_cmp_ge(x, _y)) { 124 | x = int128_sub(x, _y); 125 | ret = int128_add(ret, i); 126 | } 127 | } 128 | 129 | ret = int128_add(ret, int128_from_int64(x.lo / y)); 130 | return (neg ? int128_neg(ret) : ret); 131 | } 132 | 133 | #define int128_t _int128_t 134 | 135 | //#endif 136 | 137 | #ifdef __cplusplus 138 | } 139 | #endif 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /libfixmath/fix32_trig.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fix32.h" 3 | 4 | #define FIXMATH_SIN_LUT 5 | #if defined(FIXMATH_SIN_LUT) 6 | #include "fix32_trig_sin_lut.h" 7 | #endif 8 | 9 | 10 | fix32_t fix32_sin_parabola(fix32_t inAngle) 11 | { 12 | fix32_t abs_inAngle, abs_retval, retval; 13 | fix32_t mask; 14 | 15 | /* Absolute function */ 16 | mask = (inAngle >> (sizeof(fix32_t)*CHAR_BIT-1)); 17 | abs_inAngle = (inAngle + mask) ^ mask; 18 | 19 | /* On 0->PI, sin looks like x² that is : 20 | - centered on PI/2, 21 | - equals 1 on PI/2, 22 | - equals 0 on 0 and PI 23 | that means : 4/PI * x - 4/PI² * x² 24 | Use abs(x) to handle (-PI) -> 0 zone. 25 | */ 26 | retval = fix32_mul(FOUR_DIV_PI, inAngle) + fix32_mul( fix32_mul(_FOUR_DIV_PI2, inAngle), abs_inAngle ); 27 | /* At this point, retval equals sin(inAngle) on important points ( -PI, -PI/2, 0, PI/2, PI), 28 | but is not very precise between these points 29 | */ 30 | #ifndef FIXMATH_FAST_SIN 31 | /* Absolute value of retval */ 32 | mask = (retval >> (sizeof(fix32_t)*CHAR_BIT-1)); 33 | abs_retval = (retval + mask) ^ mask; 34 | /* So improve its precision by adding some x^4 component to retval */ 35 | retval += fix32_mul(X4_CORRECTION_COMPONENT, fix32_mul(retval, abs_retval) - retval ); 36 | #endif 37 | return retval; 38 | } 39 | 40 | fix32_t fix32_sin(fix32_t inAngle) 41 | { 42 | fix32_t tempAngle = inAngle % (fix32_pi << 1); 43 | 44 | #ifdef FIXMATH_SIN_LUT 45 | if(tempAngle < 0) 46 | tempAngle += (fix32_pi << 1); 47 | 48 | fix32_t tempOut; 49 | if(tempAngle >= fix32_pi) { 50 | tempAngle -= fix32_pi; 51 | if(tempAngle >= (fix32_pi >> 1)) 52 | tempAngle = fix32_pi - tempAngle; 53 | tempOut = -(tempAngle >= _fix32_sin_lut_count ? fix32_one : _fix32_sin_lut[tempAngle >> 16]); 54 | } else { 55 | if(tempAngle >= (fix32_pi >> 1)) 56 | tempAngle = fix32_pi - tempAngle; 57 | tempOut = (tempAngle >= _fix32_sin_lut_count ? fix32_one : _fix32_sin_lut[tempAngle >> 16]); 58 | } 59 | #else 60 | if(tempAngle > fix32_pi) 61 | tempAngle -= (fix32_pi << 1); 62 | else if(tempAngle < -fix32_pi) 63 | tempAngle += (fix32_pi << 1); 64 | 65 | fix32_t tempAngleSq = fix32_mul(tempAngle, tempAngle); 66 | 67 | 68 | fix32_t tempOut = tempAngle; 69 | tempAngle = fix32_mul(tempAngle, tempAngleSq); 70 | tempOut -= (tempAngle / 6); 71 | tempAngle = fix32_mul(tempAngle, tempAngleSq); 72 | tempOut += (tempAngle / 120); 73 | tempAngle = fix32_mul(tempAngle, tempAngleSq); 74 | tempOut -= (tempAngle / 5040); 75 | tempAngle = fix32_mul(tempAngle, tempAngleSq); 76 | tempOut += (tempAngle / 362880); 77 | tempAngle = fix32_mul(tempAngle, tempAngleSq); 78 | tempOut -= (tempAngle / 39916800); 79 | tempAngle = fix32_mul(tempAngle, tempAngleSq); 80 | tempOut -= (tempAngle / 6227020800); 81 | 82 | 83 | #endif 84 | 85 | return tempOut; 86 | } 87 | 88 | fix32_t fix32_cos(fix32_t inAngle) 89 | { 90 | return fix32_sin(inAngle + (fix32_pi >> 1)); 91 | } 92 | 93 | fix32_t fix32_tan(fix32_t inAngle) 94 | { 95 | #ifndef FIXMATH_NO_OVERFLOW 96 | return fix32_sdiv(fix32_sin(inAngle), fix32_cos(inAngle)); 97 | #elif 98 | return fix32_div(fix32_sin(inAngle), fix32_cos(inAngle)); 99 | #endif 100 | } 101 | 102 | fix32_t fix32_asin(fix32_t x) 103 | { 104 | if((x > fix32_one) 105 | || (x < -fix32_one)) 106 | return 0; 107 | 108 | fix32_t out; 109 | out = (fix32_one - fix32_mul(x, x)); 110 | out = fix32_div(x, fix32_sqrt(out)); 111 | out = fix32_atan(out); 112 | return out; 113 | } 114 | 115 | fix32_t fix32_acos(fix32_t x) 116 | { 117 | return ((fix32_pi >> 1) - fix32_asin(x)); 118 | } 119 | 120 | fix32_t fix32_atan2(fix32_t inY , fix32_t inX) 121 | { 122 | fix32_t abs_inY, mask, angle, r, r_3; 123 | 124 | /* Absolute inY */ 125 | mask = (inY >> (sizeof(fix32_t)*CHAR_BIT-1)); 126 | abs_inY = (inY + mask) ^ mask; 127 | 128 | if (inX >= 0) 129 | { 130 | r = fix32_div( (inX - abs_inY), (inX + abs_inY)); 131 | r_3 = fix32_mul(fix32_mul(r, r),r); 132 | angle = fix32_mul(0x0000000031238038 , r_3) - fix32_mul(0x00000000F8EED205,r) + PI_DIV_4; 133 | } else { 134 | r = fix32_div( (inX + abs_inY), (abs_inY - inX)); 135 | r_3 = fix32_mul(fix32_mul(r, r),r); 136 | angle = fix32_mul(0x0000000031238038 , r_3) 137 | - fix32_mul(0x00000000F8EED205,r) 138 | + THREE_PI_DIV_4; 139 | } 140 | if (inY < 0) 141 | { 142 | angle = -angle; 143 | } 144 | 145 | return angle; 146 | } 147 | 148 | fix32_t fix32_atan(fix32_t x) 149 | { 150 | return fix32_atan2(x, fix32_one); 151 | } 152 | -------------------------------------------------------------------------------- /libfixmath/fix32_exp.c: -------------------------------------------------------------------------------- 1 | #include "fix32.h" 2 | #include 3 | 4 | 5 | fix32_t fix32_exp(fix32_t inValue) { 6 | if(inValue == 0 ) return fix32_one; 7 | if(inValue == fix32_one ) return fix32_e; 8 | if(inValue >= 92288378626I64) return fix32_maximum; //fix32_from_dbl(ln(fix32_to_dbl(fix32_maximum))) = fix32_from_dbl(ln(2147483648)) = fix32_from_dbl(21.487562597) = 92288378625 9 | if(inValue <= -98242467570I64) return 0; //fix32_from_dbl(ln(fix32_to_dbl(fix32_epsilon))) = fix32_from_dbl(ln(0.00000000023283064365)) = fix32_from_dbl(-22.1807097779) = -95265423098 10 | //fix32_from_dbl(ln(0.5*fix32_to_dbl(fix32_epsilon))) = fix32_from_dbl(ln(0.000000000116415321825)) = fix32_from_dbl(-22.87385) = -98242467570 11 | 12 | 13 | /* The algorithm is based on the power series for exp(x): 14 | * http://en.wikipedia.org/wiki/Exponential_function#Formal_definition 15 | * 16 | * From term n, we get term n+1 by multiplying with x/n. 17 | * When the sum term drops to zero, we can stop summing. 18 | */ 19 | 20 | // The power-series converges much faster on positive values 21 | // and exp(-x) = 1/exp(x). 22 | bool neg = (inValue < 0); 23 | if (neg) inValue = -inValue; 24 | 25 | fix32_t result = inValue + fix32_one; 26 | fix32_t term = inValue; 27 | 28 | uint_fast8_t i; 29 | for (i = 2; i < 30; i++) 30 | { 31 | term = fix32_mul(term, fix32_div(inValue, fix32_from_int(i))); 32 | result += term; 33 | 34 | if ((term < 500) && ((i > 15) || (term < 20))) 35 | break; 36 | } 37 | 38 | if (neg) 39 | result = fix32_div(fix32_one, result); 40 | 41 | return result; 42 | } 43 | 44 | 45 | 46 | fix32_t fix32_ln(fix32_t inValue) 47 | { 48 | fix32_t guess = fix32_from_int(2); 49 | fix32_t delta; 50 | int scaling = 0; 51 | int count = 0; 52 | 53 | if (inValue <= 0) 54 | return fix32_minimum; 55 | 56 | // Bring the value to the most accurate range (1 < x < 100) 57 | const fix32_t e_to_fourth = 234497268814; 58 | while (inValue > fix32_from_int(100)) 59 | { 60 | inValue = fix32_div(inValue, e_to_fourth); 61 | scaling += 4; 62 | } 63 | 64 | while (inValue < fix32_one) 65 | { 66 | inValue = fix32_mul(inValue, e_to_fourth); 67 | scaling -= 4; 68 | } 69 | 70 | do 71 | { 72 | // Solving e(x) = y using Newton's method 73 | // f(x) = e(x) - y 74 | // f'(x) = e(x) 75 | fix32_t e = fix32_exp(guess); 76 | delta = fix32_div(inValue - e, e); 77 | 78 | // It's unlikely that logarithm is very large, so avoid overshooting. 79 | if (delta > fix32_from_int(3)) 80 | delta = fix32_from_int(3); 81 | 82 | guess += delta; 83 | } while ((count++ < 10) 84 | && ((delta > 1) || (delta < -1))); 85 | 86 | return guess + fix32_from_int(scaling); 87 | } 88 | 89 | 90 | 91 | static inline fix32_t fix32_rs(fix32_t x) 92 | { 93 | #ifdef FIXMATH_NO_ROUNDING 94 | return (x >> 1); 95 | #else 96 | fix32_t y = (x >> 1) + (x & 1); 97 | return y; 98 | #endif 99 | } 100 | 101 | /** 102 | * This assumes that the input value is >= 1. 103 | * 104 | * Note that this is only ever called with inValue >= 1 (because it has a wrapper to check. 105 | * As such, the result is always less than the input. 106 | */ 107 | static fix32_t fix32__log2_inner(fix32_t x) 108 | { 109 | fix32_t result = 0; 110 | 111 | while(x >= fix32_from_int(2)) 112 | { 113 | result++; 114 | x = fix32_rs(x); 115 | } 116 | 117 | if(x == 0) return (result << 32); 118 | 119 | uint_fast8_t i; 120 | for(i = 32; i > 0; i--) 121 | { 122 | x = fix32_mul(x, x); 123 | result <<= 1; 124 | if(x >= fix32_from_int(2)) 125 | { 126 | result |= 1; 127 | x = fix32_rs(x); 128 | } 129 | } 130 | #ifndef FIXMATH_NO_ROUNDING 131 | x = fix32_mul(x, x); 132 | if(x >= fix32_from_int(2)) result++; 133 | #endif 134 | 135 | return result; 136 | } 137 | 138 | 139 | 140 | /** 141 | * calculates the log base 2 of input. 142 | * Note that negative inputs are invalid! (will return fix32_overflow, since there are no exceptions) 143 | * 144 | * i.e. 2 to the power output = input. 145 | * It's equivalent to the log or ln functions, except it uses base 2 instead of base 10 or base e. 146 | * This is useful as binary things like this are easy for binary devices, like modern microprocessros, to calculate. 147 | * 148 | * This can be used as a helper function to calculate powers with non-integer powers and/or bases. 149 | */ 150 | fix32_t fix32_log2(fix32_t x) 151 | { 152 | // Note that a negative x gives a non-real result. 153 | // If x == 0, the limit of log2(x) as x -> 0 = -infinity. 154 | // log2(-ve) gives a complex result. 155 | if (x <= 0) return fix32_overflow; 156 | 157 | // If the input is less than one, the result is -log2(1.0 / in) 158 | if (x < fix32_one) 159 | { 160 | // Note that the inverse of this would overflow. 161 | // This is the exact answer for log2(1.0 / 4294967296) 162 | if (x == 1) return fix32_from_int(-32); 163 | 164 | fix32_t inverse = fix32_div(fix32_one, x); 165 | return -fix32__log2_inner(inverse); 166 | } 167 | 168 | // If input >= 1, just proceed as normal. 169 | // Note that x == fix32_one is a special case, where the answer is 0. 170 | return fix32__log2_inner(x); 171 | } 172 | 173 | /** 174 | * This is a wrapper for fix32_log2 which implements saturation arithmetic. 175 | */ 176 | fix32_t fix32_slog2(fix32_t x) 177 | { 178 | fix32_t retval = fix32_log2(x); 179 | // The only overflow possible is when the input is negative. 180 | if(retval == fix32_overflow) 181 | return fix32_minimum; 182 | return retval; 183 | } 184 | 185 | fix32_t fix32_pow2(fix32_t x) 186 | { 187 | const static fix32_t LN2 = 0x00000000B17217F7; 188 | const static fix32_t Log2Max = 0x0000001F00000000; 189 | const static fix32_t Log2Min = -0x0000002000000000; 190 | 191 | if (x == 0) 192 | return fix32_one; 193 | 194 | // Avoid negative arguments by exploiting that exp(-x) = 1/exp(x). 195 | bool neg = x < 0; 196 | if (neg) 197 | x = -x; 198 | 199 | if (x == fix32_one) 200 | { 201 | return neg ? 0x0000000080000000 : 0x0000000200000000; 202 | //return neg ? fix32_from_double(0.5) : fix32_from_int(2); 203 | } 204 | if (x >= Log2Max) 205 | { 206 | return neg ? fix32_epsilon : fix32_maximum; 207 | } 208 | if (x <= Log2Min) 209 | { 210 | return neg ? fix32_maximum : 0; 211 | } 212 | 213 | /* The algorithm is based on the power series for exp(x): 214 | * http://en.wikipedia.org/wiki/Exponential_function#Formal_definition 215 | * 216 | * From term n, we get term n+1 by multiplying with x/n. 217 | * When the sum term drops to zero, we can stop summing. 218 | */ 219 | 220 | fix32_t int_part = fix32_floor(x); 221 | int integerPart = (int)(int_part >> 32); 222 | // Take fractional part of exponent 223 | x = x & 0x00000000FFFFFFFF; 224 | 225 | fix32_t result = fix32_one; 226 | fix32_t term = fix32_one; 227 | int i = 1; 228 | while (term != 0) 229 | { 230 | term = fix32_mul(term, fix32_mul(LN2, fix32_div(x, fix32_from_int(i)))); 231 | result += term; 232 | i++; 233 | } 234 | 235 | result = result << integerPart; 236 | 237 | if (neg) 238 | result = fix32_div(fix32_one, result); 239 | 240 | return result; 241 | } 242 | 243 | fix32_t fix32_pow(fix32_t b, fix32_t exp) 244 | { 245 | if (b == fix32_one || exp == 0) 246 | return fix32_one; 247 | 248 | if (b == 0) 249 | return 0; 250 | 251 | fix32_t log2 = fix32_log2(b); 252 | return fix32_pow2(fix32_mul(exp, log2)); 253 | } 254 | 255 | fix32_t fix32_spow(fix32_t b, fix32_t exp) 256 | { 257 | if (b == fix32_one || exp == 0) 258 | return fix32_one; 259 | 260 | if (b == 0) 261 | return 0; 262 | 263 | fix32_t log2 = fix32_slog2(b); 264 | return fix32_pow2(fix32_smul(exp, log2)); 265 | } -------------------------------------------------------------------------------- /libfixmath/fix32.h: -------------------------------------------------------------------------------- 1 | #ifndef __libfixmath_fix32_h__ 2 | #define __libfixmath_fix32_h__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | /* These options may let the optimizer to remove some calls to the functions. 10 | * Refer to http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html 11 | */ 12 | #ifndef FIXMATH_FUNC_ATTRS 13 | # ifdef __GNUC__ 14 | # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) 15 | # define FIXMATH_FUNC_ATTRS __attribute__((leaf, nothrow, const)) 16 | # else 17 | # define FIXMATH_FUNC_ATTRS __attribute__((nothrow, const)) 18 | # endif 19 | # else 20 | # define FIXMATH_FUNC_ATTRS 21 | # endif 22 | #endif 23 | 24 | #include 25 | 26 | typedef int64_t fix32_t; 27 | 28 | static const fix32_t FOUR_DIV_PI = 0x145F306DD; /*!< Fix32 value of 4/PI */ 29 | static const fix32_t _FOUR_DIV_PI2 = 0xFFFFFFFF983f4277; /*!< Fix32 value of -4/PI² */ 30 | static const fix32_t X4_CORRECTION_COMPONENT = 0x3999999A; /*!< Fix32 value of 0.225 */ 31 | static const fix32_t PI_DIV_4 = 0xC90FDAA2; /*!< Fix32 value of PI/4 */ 32 | static const fix32_t THREE_PI_DIV_4 = 0x25B2F8FE6; /*!< Fix32 value of 3PI/4 */ 33 | 34 | static const fix32_t fix32_maximum = 0x7FFFFFFFFFFFFFFF; /*!< the maximum value of fix32_t */ 35 | static const fix32_t fix32_minimum = 0x8000000000000000; /*!< the maximum value of fix32_t */ 36 | static const fix32_t fix32_overflow = 0x8000000000000000; /*!< the value used to indicate overflows when FIXMATH_NO_OVERFLOW is not specified */ 37 | static const fix32_t fix32_epsilon = 0x0000000000000001; /*!< the min absolute value of fix32_t */ 38 | 39 | static const fix32_t fix32_pi = 13493037704; /*!< fix32_t value of pi */ //0x 0000 0003 243F 6A88 40 | static const fix32_t fix32_pi_over_2 = 6746518852; /*!< fix32_t value of pi/2 */ //0x 0000 0001 921F B544 41 | static const fix32_t fix32_one_over_pi = 0x00000000517cc1b7; /*!< fix32_t value of 1/pi */ //0x 0000 0001 921F B544 42 | static const fix32_t fix32_e = 11674931555; /*!< fix32_t value of e */ 43 | static const fix32_t fix32_one = 0x0000000100000000; /*!< fix32_t value of 1 */ 44 | 45 | /* Conversion functions between fix32_t and float/integer. 46 | * These are inlined to allow compiler to optimize away constant numbers 47 | */ 48 | static inline fix32_t fix32_from_int(int a) { return a * fix32_one; } 49 | static inline float fix32_to_float(fix32_t a) { return (float)a / fix32_one; } 50 | static inline double fix32_to_dbl(fix32_t a) { return (double)a / fix32_one; } 51 | 52 | static inline int fix32_to_int(fix32_t a) 53 | { 54 | #ifdef FIXMATH_NO_ROUNDING 55 | return (a >> 32); 56 | #else 57 | if (a >= 0) 58 | return (a + (fix32_one >> 1)) / fix32_one; 59 | return (a - (fix32_one >> 1)) / fix32_one; 60 | #endif 61 | } 62 | 63 | static inline fix32_t fix32_from_float(float a) 64 | { 65 | float temp = a * fix32_one; 66 | #ifndef FIXMATH_NO_ROUNDING 67 | temp += (temp >= 0) ? 0.5f : -0.5f; 68 | #endif 69 | return (fix32_t)temp; 70 | } 71 | 72 | static inline fix32_t fix32_from_dbl(double a) 73 | { 74 | double temp = a * fix32_one; 75 | #ifndef FIXMATH_NO_ROUNDING 76 | temp += (double)((temp >= 0) ? 0.5f : -0.5f); 77 | #endif 78 | return (fix32_t)temp; 79 | } 80 | 81 | /* Converts a binary IEEE745 float to a fixed point q31.32 integer 82 | * without FPO 83 | */ 84 | extern fix32_t fix32_from_float_bin(const void* value); 85 | 86 | /* Converts a q31.32 integer back to binary IEEE754 floating point 87 | * It returns uint32_t that contains the 32-bit float value 88 | */ 89 | extern uint32_t float_from_fix32_bin(fix32_t value); 90 | 91 | /* Macro for defining fix32_t constant values. 92 | The functions above can't be used from e.g. global variable initializers, 93 | and their names are quite long also. This macro is useful for constants 94 | springled alongside code, e.g. F32(1.234). 95 | 96 | Note that the argument is evaluated multiple times, and also otherwise 97 | you should only use this for constant values. For runtime-conversions, 98 | use the functions above. 99 | */ 100 | #define F32(x) ((fix32_t)(((x) >= 0) ? ((x) * 4294967296.0 + 0.5) : ((x) * 4294967296.0 - 0.5))) 101 | 102 | static inline fix32_t fix32_abs(fix32_t x) 103 | { return (x < 0 ? -x : x); } 104 | static inline fix32_t fix32_floor(fix32_t x) 105 | { return (x & 0xFFFFFFFF00000000ULL); } 106 | static inline fix32_t fix32_ceil(fix32_t x) 107 | { return (x & 0xFFFFFFFF00000000ULL) + (x & 0x00000000FFFFFFFFULL ? fix32_one : 0); } 108 | static inline fix32_t fix32_min(fix32_t x, fix32_t y) 109 | { return (x < y ? x : y); } 110 | static inline fix32_t fix32_max(fix32_t x, fix32_t y) 111 | { return (x > y ? x : y); } 112 | static inline fix32_t fix32_clamp(fix32_t x, fix32_t lo, fix32_t hi) 113 | { return fix32_min(fix32_max(x, lo), hi); } 114 | 115 | /* Subtraction and addition with (optional) overflow detection. */ 116 | #ifdef FIXMATH_NO_OVERFLOW 117 | 118 | static inline fix32_t fix32_add(fix32_t inArg0, fix32_t inArg1) { return (inArg0 + inArg1); } 119 | static inline fix32_t fix32_sub(fix32_t inArg0, fix32_t inArg1) { return (inArg0 - inArg1); } 120 | 121 | #else 122 | 123 | extern fix32_t fix32_add(fix32_t a, fix32_t b) FIXMATH_FUNC_ATTRS; 124 | extern fix32_t fix32_sub(fix32_t a, fix32_t b) FIXMATH_FUNC_ATTRS; 125 | 126 | /* Saturating arithmetic */ 127 | extern fix32_t fix32_sadd(fix32_t a, fix32_t b) FIXMATH_FUNC_ATTRS; 128 | extern fix32_t fix32_ssub(fix32_t a, fix32_t b) FIXMATH_FUNC_ATTRS; 129 | 130 | #endif 131 | 132 | /*! Multiplies the two given fix16_t's and returns the result. 133 | */ 134 | extern fix32_t fix32_mul(fix32_t inArg0, fix32_t inArg1) FIXMATH_FUNC_ATTRS; 135 | 136 | /*! Divides the first given fix16_t by the second and returns the result. 137 | */ 138 | extern fix32_t fix32_div(fix32_t inArg0, fix32_t inArg1) FIXMATH_FUNC_ATTRS; 139 | 140 | #ifndef FIXMATH_NO_OVERFLOW 141 | /*! Performs a saturated multiplication (overflow-protected) of the two given fix32_t's and returns the result. 142 | */ 143 | extern fix32_t fix32_smul(fix32_t inArg0, fix32_t inArg1) FIXMATH_FUNC_ATTRS; 144 | 145 | /*! Performs a saturated division (overflow-protected) of the first fix32_t by the second and returns the result. 146 | */ 147 | extern fix32_t fix32_sdiv(fix32_t inArg0, fix32_t inArg1) FIXMATH_FUNC_ATTRS; 148 | #endif 149 | 150 | /*! Divides the first given fix32_t by the second and returns the result. 151 | */ 152 | extern fix32_t fix32_mod(fix32_t x, fix32_t y) FIXMATH_FUNC_ATTRS; 153 | 154 | 155 | 156 | /* Returns the linear interpolation: (inArg0 * (1 - inFract)) + (inArg1 * inFract): 157 | */ 158 | extern fix32_t fix32_lerp8(fix32_t inArg0, fix32_t inArg1, uint8_t inFract) FIXMATH_FUNC_ATTRS; 159 | extern fix32_t fix32_lerp16(fix32_t inArg0, fix32_t inArg1, uint16_t inFract) FIXMATH_FUNC_ATTRS; 160 | extern fix32_t fix32_lerp32(fix32_t inArg0, fix32_t inArg1, uint32_t inFract) FIXMATH_FUNC_ATTRS; 161 | extern fix32_t fix32_lerp(fix32_t inArg0, fix32_t inArg1, fix32_t inFract) FIXMATH_FUNC_ATTRS; 162 | 163 | 164 | 165 | /*! Returns the sine of the given fix32_t. 166 | */ 167 | extern fix32_t fix32_sin_parabola(fix32_t inAngle) FIXMATH_FUNC_ATTRS; 168 | 169 | /*! Returns the sine of the given fix32_t. 170 | */ 171 | extern fix32_t fix32_sin(fix32_t inAngle) FIXMATH_FUNC_ATTRS; 172 | 173 | /*! Returns the cosine of the given fix32_t. 174 | */ 175 | extern fix32_t fix32_cos(fix32_t inAngle) FIXMATH_FUNC_ATTRS; 176 | 177 | /*! Returns the tangent of the given fix32_t. 178 | */ 179 | extern fix32_t fix32_tan(fix32_t inAngle) FIXMATH_FUNC_ATTRS; 180 | 181 | /*! Returns the arcsine of the given fix32_t. 182 | */ 183 | extern fix32_t fix32_asin(fix32_t inValue) FIXMATH_FUNC_ATTRS; 184 | 185 | /*! Returns the arccosine of the given fix32_t. 186 | */ 187 | extern fix32_t fix32_acos(fix32_t inValue) FIXMATH_FUNC_ATTRS; 188 | 189 | /*! Returns the arctangent of the given fix32_t. 190 | */ 191 | extern fix32_t fix32_atan(fix32_t inValue) FIXMATH_FUNC_ATTRS; 192 | 193 | /*! Returns the arctangent of inY/inX. 194 | */ 195 | extern fix32_t fix32_atan2(fix32_t inY, fix32_t inX) FIXMATH_FUNC_ATTRS; 196 | 197 | static const fix32_t fix32_rad_to_deg_mult = 246101626061; 198 | static inline fix32_t fix32_rad_to_deg(fix32_t radians) 199 | { return fix32_mul(radians, fix32_rad_to_deg_mult); } 200 | 201 | static const fix32_t fix32_deg_to_rad_mult = 74947179; 202 | static inline fix32_t fix32_deg_to_rad(fix32_t degrees) 203 | { return fix32_mul(degrees, fix32_deg_to_rad_mult); } 204 | 205 | 206 | 207 | /*! Returns the square root of the given fix32_t. 208 | */ 209 | extern fix32_t fix32_sqrt(fix32_t inValue) FIXMATH_FUNC_ATTRS; 210 | 211 | /*! Returns the square of the given fix32_t. 212 | */ 213 | static inline fix32_t fix32_sq(fix32_t x) 214 | { return fix32_mul(x, x); } 215 | 216 | /*! Returns the exponent (e^) of the given fix32_t. <--------------------------------------- !!! Might give wrong returns values !!! 217 | */ 218 | extern fix32_t fix32_exp(fix32_t inValue) FIXMATH_FUNC_ATTRS; 219 | 220 | /*! Returns the natural logarithm of the given fix32_t. 221 | */ 222 | extern fix32_t fix32_ln(fix32_t inValue) FIXMATH_FUNC_ATTRS; 223 | 224 | /*! Returns the base 2 logarithm of the given fix32_t. 225 | */ 226 | extern fix32_t fix32_log2(fix32_t x) FIXMATH_FUNC_ATTRS; 227 | 228 | /*! Returns the saturated base 2 logarithm of the given fix32_t. 229 | */ 230 | extern fix32_t fix32_slog2(fix32_t x) FIXMATH_FUNC_ATTRS; 231 | 232 | /*! Returns 2 raised to the specified power. 233 | */ 234 | extern fix32_t fix32_pow2(fix32_t x) FIXMATH_FUNC_ATTRS; 235 | 236 | /*! Returns a specified number raised to the specified power. 237 | */ 238 | extern fix32_t fix32_pow(fix32_t b, fix32_t exp) FIXMATH_FUNC_ATTRS; 239 | 240 | /*! Returns the saturated version of fix32_pow. 241 | */ 242 | extern fix32_t fix32_spow(fix32_t b, fix32_t exp) FIXMATH_FUNC_ATTRS; 243 | 244 | #ifdef __cplusplus 245 | } 246 | #endif 247 | 248 | #endif 249 | -------------------------------------------------------------------------------- /libfixmath/fix32.c: -------------------------------------------------------------------------------- 1 | #include "fix32.h" 2 | #include "int128.h" 3 | 4 | #ifdef __GNUC__ 5 | // Count leading zeros, using processor-specific instruction if available. 6 | #define clz(x) (__builtin_clzl(x) - (8 * sizeof(long) - 64)) 7 | #else 8 | static uint8_t clz(uint64_t x) 9 | { 10 | uint8_t result = 0; 11 | if (x == 0) return 64; 12 | while (!(x & 0xF000000000000000)) { result += 4; x <<= 4; } 13 | while (!(x & 0x8000000000000000)) { result += 1; x <<= 1; } 14 | return result; 15 | } 16 | #endif 17 | 18 | /* Binary conversion functions for machines without 19 | * FPO but somehow access to IEEE745 float binary data 20 | */ 21 | fix32_t fix32_from_float_bin(const void* value) 22 | { 23 | int64_t fi = *(int64_t *)value; 24 | // get the fraction 25 | fix32_t q3232 = (fi & ((1 << 23) - 1)) | 1 << 23; 26 | // get the exponent 27 | int64_t expon = ((fi >> 23) & ((1 << 8) - 1)) - 127; 28 | // get the shift 29 | int32_t shift = 32 + expon - 23; 30 | // get the sign 31 | int64_t sign = (fi >> 31) & 1; 32 | 33 | if (shift >= 32 || shift <= -32) 34 | { 35 | q3232 = 0; 36 | } 37 | else 38 | { 39 | if (shift < 0) 40 | { 41 | q3232 >>= -shift; 42 | } 43 | else 44 | { 45 | q3232 <<= shift; 46 | } 47 | } 48 | 49 | if (sign) 50 | { 51 | int64_t int_part = (int32_t)((q3232 & 0xFFFFFFFF00000000) >> 32); 52 | int_part *= -1; 53 | 54 | uint32_t frac_part = (uint32_t)(q3232 & 0x00000000FFFFFFFF); 55 | if (frac_part) 56 | { 57 | frac_part = 0xFFFFFFFF - frac_part; 58 | q3232 &= 0xFFFFFFFF00000000; 59 | q3232 ^= frac_part; 60 | int_part -= 1; 61 | } 62 | q3232 &= 0x00000000FFFFFFFF; 63 | q3232 ^= int_part << 32; 64 | } 65 | 66 | return q3232; 67 | } 68 | 69 | static int32_t count_bits_pow2(uint64_t x) 70 | { 71 | int32_t l = -33; 72 | for (uint64_t i = 0; i < 64; i++) 73 | { 74 | uint64_t test = 1ULL << i; 75 | if (x >= test) 76 | { 77 | l++; 78 | } 79 | else 80 | { 81 | break; 82 | } 83 | } 84 | return l; 85 | } 86 | 87 | uint32_t float_from_fix32_bin(fix32_t value) 88 | { 89 | int64_t original_num = (int64_t)value; 90 | uint64_t sign = 0; 91 | if (original_num < 0) 92 | { 93 | sign = 1; 94 | } 95 | 96 | // remove the signed bit if it's set 97 | int64_t unsigned_ver = original_num < 0 ? -original_num : original_num; 98 | 99 | // calculate mantissa 100 | int lz = clz(unsigned_ver); 101 | uint64_t y = unsigned_ver << (lz + 1); 102 | 103 | // 33 --> because we use 64-bit fixed point num, the middle of it is at 32, 104 | // and +1 for the sign bit. Then 8 is the exponent bits, which is 8 for IEEE754 105 | uint64_t mantissa = y >> (33 + 8); 106 | 107 | // get the non-fractal bits, add the exponent bias ( 127 in IEEE754 ) to get exponent 108 | // uint64_t non_fractal = (unsigned_ver >> 32); 109 | uint64_t exp = count_bits_pow2(unsigned_ver) + 127; 110 | 111 | // construct the final IEEE754 float binary number 112 | // first add the last 23 bits (mantissa) 113 | uint32_t ret = mantissa; 114 | 115 | // add exponent 116 | ret |= (exp << 23); 117 | 118 | // add the sign if needed 119 | if (sign) 120 | { 121 | ret |= 0x80000000; 122 | } 123 | 124 | return ret; 125 | } 126 | 127 | 128 | /* Subtraction and addition with overflow detection. 129 | * The versions without overflow detection are inlined in the header. 130 | */ 131 | #ifndef FIXMATH_NO_OVERFLOW 132 | fix32_t fix32_add(fix32_t a, fix32_t b) 133 | { 134 | // Use unsigned integers because overflow with signed integers is 135 | // an undefined operation (http://www.airs.com/blog/archives/120). 136 | uint64_t _a = a, _b = b; 137 | uint64_t sum = _a + _b; 138 | 139 | // Overflow can only happen if sign of a == sign of b, and then 140 | // it causes sign of sum != sign of a. 141 | if (!((_a ^ _b) & 0x8000000000000000) && ((_a ^ sum) & 0x8000000000000000)) 142 | return fix32_overflow; 143 | 144 | return sum; 145 | } 146 | 147 | fix32_t fix32_sub(fix32_t a, fix32_t b) 148 | { 149 | uint64_t _a = a, _b = b; 150 | uint64_t diff = _a - _b; 151 | 152 | // Overflow can only happen if sign of a != sign of b, and then 153 | // it causes sign of diff != sign of a. 154 | if (((_a ^ _b) & 0x8000000000000000) && ((_a ^ diff) & 0x8000000000000000)) 155 | return fix32_overflow; 156 | 157 | return diff; 158 | } 159 | 160 | /* Saturating arithmetic */ 161 | fix32_t fix32_sadd(fix32_t a, fix32_t b) 162 | { 163 | fix32_t result = fix32_add(a, b); 164 | 165 | if (result == fix32_overflow) 166 | return (a >= 0) ? fix32_maximum : fix32_minimum; 167 | 168 | return result; 169 | } 170 | 171 | fix32_t fix32_ssub(fix32_t a, fix32_t b) 172 | { 173 | fix32_t result = fix32_sub(a, b); 174 | 175 | if (result == fix32_overflow) 176 | return (a >= 0) ? fix32_maximum : fix32_minimum; 177 | 178 | return result; 179 | } 180 | #endif 181 | 182 | 183 | 184 | /* 64-bit implementation for fix32_mul. Simplest way to implement on a x64 185 | * machines, and I don't have any need for different versions personally. If 186 | * you do, please share. This is fast enough for me. 187 | */ 188 | fix32_t fix32_mul(fix32_t inArg0, fix32_t inArg1) 189 | { 190 | // Each argument is divided to 32-bit parts. 191 | // AB 192 | // * CD 193 | // ----------- 194 | // BD 32 * 32 -> 64 bit products 195 | // CB 196 | // AD 197 | // AC 198 | // |----| 64 bit product 199 | int64_t A = (inArg0 >> 32), C = (inArg1 >> 32); 200 | uint64_t B = (inArg0 & 0xFFFFFFFF), D = (inArg1 & 0xFFFFFFFF); 201 | 202 | int64_t AC = A*C; 203 | int64_t AD_CB = A*D + C*B; 204 | uint64_t BD = B*D; 205 | 206 | int64_t product_hi = AC + (AD_CB >> 32); 207 | 208 | // Handle carry from lower 32 bits to upper part of result. 209 | uint64_t ad_cb_temp = AD_CB << 32; 210 | uint64_t product_lo = BD + ad_cb_temp; 211 | if (product_lo < BD) 212 | product_hi++; 213 | 214 | #ifndef FIXMATH_NO_OVERFLOW 215 | // The upper 17 bits should all be the same (the sign). 216 | if (product_hi >> 63 != product_hi >> 31) 217 | return fix32_overflow; 218 | #endif 219 | 220 | #ifdef FIXMATH_NO_ROUNDING 221 | return (product_hi << 32) | (product_lo >> 32); 222 | #else 223 | // Subtracting 0x80000000 (= 0.5) and then using signed right shift 224 | // achieves proper rounding to result-1, except in the corner 225 | // case of negative numbers and lowest word = 0x80000000. 226 | // To handle that, we also have to subtract 1 for negative numbers. 227 | uint64_t product_lo_tmp = product_lo; 228 | product_lo -= 0x80000000; 229 | product_lo -= (uint64_t)product_hi >> 63; 230 | if (product_lo > product_lo_tmp) 231 | product_hi--; 232 | 233 | // Discard the lowest 16 bits. Note that this is not exactly the same 234 | // as dividing by 0x10000. For example if product = -1, result will 235 | // also be -1 and not 0. This is compensated by adding +1 to the result 236 | // and compensating this in turn in the rounding above. 237 | fix32_t result = (product_hi << 32) | (product_lo >> 32); 238 | result += 1; 239 | return result; 240 | #endif 241 | } 242 | 243 | 244 | #ifndef FIXMATH_NO_OVERFLOW 245 | /* Wrapper around fix32_mul to add saturating arithmetic. */ 246 | fix32_t fix32_smul(fix32_t inArg0, fix32_t inArg1) 247 | { 248 | fix32_t result = fix32_mul(inArg0, inArg1); 249 | 250 | if (result == fix32_overflow) 251 | { 252 | if ((inArg0 >= 0) == (inArg1 >= 0)) 253 | return fix32_maximum; 254 | else 255 | return fix32_minimum; 256 | } 257 | 258 | return result; 259 | } 260 | #endif 261 | 262 | /* 263 | * 64-bit implementation of fix32_div. Only implemented this 264 | * one, if you need a 8-bit optimized version, please create 265 | * and share. 266 | */ 267 | #if !defined(FIXMATH_OPTIMIZE_8BIT) 268 | 269 | fix32_t fix32_div(fix32_t a, fix32_t b) 270 | { 271 | // This uses a hardware 64/64 bit division multiple times, until we have 272 | // computed all the bits in (a<<33)/b. Usually this takes 1-3 iterations. 273 | 274 | if (b == 0) 275 | return fix32_minimum; 276 | 277 | uint64_t remainder = (a >= 0) ? a : (-a); 278 | uint64_t divider = (b >= 0) ? b : (-b); 279 | uint64_t quotient = 0; 280 | int bit_pos = 33; 281 | 282 | // Kick-start the division a bit. 283 | // This improves speed in the worst-case scenarios where N and D are large 284 | // It gets a lower estimate for the result by N/(D >> 33 + 1). 285 | if (divider & 0xFFF0000000000000) 286 | { 287 | uint64_t shifted_div = ((divider >> 33) + 1); 288 | quotient = remainder / shifted_div; 289 | remainder -= ((uint64_t)quotient * divider) >> 17; 290 | } 291 | 292 | // If the divider is divisible by 2^n, take advantage of it. 293 | while (!(divider & 0xF) && bit_pos >= 4) 294 | { 295 | divider >>= 4; 296 | bit_pos -= 4; 297 | } 298 | 299 | while (remainder && bit_pos >= 0) 300 | { 301 | // Shift remainder as much as we can without overflowing 302 | int shift = clz(remainder); 303 | if (shift > bit_pos) shift = bit_pos; 304 | remainder <<= shift; 305 | bit_pos -= shift; 306 | 307 | uint64_t div = remainder / divider; 308 | remainder = remainder % divider; 309 | quotient += div << bit_pos; 310 | 311 | #ifndef FIXMATH_NO_OVERFLOW 312 | if (div & ~(0xFFFFFFFFFFFFFFFF >> bit_pos)) 313 | return fix32_overflow; 314 | #endif 315 | 316 | remainder <<= 1; 317 | bit_pos--; 318 | } 319 | 320 | #ifndef FIXMATH_NO_ROUNDING 321 | // Quotient is always positive so rounding is easy 322 | quotient++; 323 | #endif 324 | 325 | fix32_t result = quotient >> 1; 326 | 327 | // Figure out the sign of the result 328 | if ((a ^ b) & 0x8000000000000000) 329 | { 330 | #ifndef FIXMATH_NO_OVERFLOW 331 | if (result == fix32_minimum) 332 | return fix32_overflow; 333 | #endif 334 | 335 | result = -result; 336 | } 337 | 338 | return result; 339 | } 340 | #endif 341 | 342 | 343 | #ifndef FIXMATH_NO_OVERFLOW 344 | /* Wrapper around fix32_div to add saturating arithmetic. */ 345 | fix32_t fix32_sdiv(fix32_t inArg0, fix32_t inArg1) 346 | { 347 | fix32_t result = fix32_div(inArg0, inArg1); 348 | 349 | if (result == fix32_overflow) 350 | { 351 | if ((inArg0 >= 0) == (inArg1 >= 0)) 352 | return fix32_maximum; 353 | else 354 | return fix32_minimum; 355 | } 356 | 357 | return result; 358 | } 359 | #endif 360 | 361 | fix32_t fix32_mod(fix32_t x, fix32_t y) 362 | { 363 | #ifdef FIXMATH_OPTIMIZE_8BIT 364 | /* The reason we do this, rather than use a modulo operator 365 | * is that if you don't have a hardware divider, this will result 366 | * in faster operations when the angles are close to the bounds. 367 | */ 368 | while(x >= y) x -= y; 369 | while(x <= -y) x += y; 370 | #else 371 | /* Note that in C90, the sign of result of the modulo operation is 372 | * undefined. in C99, it's the same as the dividend (aka numerator). 373 | */ 374 | x %= y; 375 | #endif 376 | 377 | return x; 378 | } 379 | 380 | 381 | 382 | fix32_t fix32_lerp8(fix32_t inArg0, fix32_t inArg1, uint8_t inFract) 383 | { 384 | int128_t tempOut = int128_mul_i64_i64(inArg0, ((1 << 8) - inFract)); 385 | tempOut = int128_add(tempOut, int128_mul_i64_i64(inArg1, inFract)); 386 | tempOut = int128_shift(tempOut, -8); 387 | return (fix32_t)int128_lo(tempOut); 388 | } 389 | 390 | fix32_t fix32_lerp16(fix32_t inArg0, fix32_t inArg1, uint16_t inFract) 391 | { 392 | int128_t tempOut = int128_mul_i64_i64(inArg0, (((int64_t)1 << 16) - inFract)); 393 | tempOut = int128_add(tempOut, int128_mul_i64_i64(inArg1, inFract)); 394 | tempOut = int128_shift(tempOut, -16); 395 | return (fix32_t)int128_lo(tempOut); 396 | } 397 | 398 | fix32_t fix32_lerp32(fix32_t inArg0, fix32_t inArg1, uint32_t inFract) 399 | { 400 | int128_t tempOut = int128_mul_i64_i64(inArg0, (((int64_t)1 << 32) - inFract)); 401 | tempOut = int128_add(tempOut, int128_mul_i64_i64(inArg1, inFract)); 402 | tempOut = int128_shift(tempOut, -32); 403 | return (fix32_t)int128_lo(tempOut); 404 | } 405 | 406 | fix32_t fix32_lerp(fix32_t inArg0, fix32_t inArg1, fix32_t inFract) 407 | { 408 | fix32_t fx1 = fix32_mul(inArg0, fix32_sub(fix32_one, inFract)); 409 | fix32_t fx2 = fix32_mul(inArg1, inFract); 410 | return fix32_add(fx1, fx2); 411 | } -------------------------------------------------------------------------------- /unittests/fix32_unittests.c: -------------------------------------------------------------------------------- 1 | #include "../libfixmath/fix32.h" 2 | #include 3 | #include 4 | #include 5 | #include "unittests.h" 6 | #include 7 | #include 8 | 9 | const fix32_t testcases[] = { 10 | // Small numbers 11 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12 | -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, 13 | 14 | // Integer numbers 15 | 0x10000, -0x10000, 0x20000, -0x20000, 0x30000, -0x30000, 16 | 0x40000, -0x40000, 0x50000, -0x50000, 0x60000, -0x60000, 17 | 18 | // Fractions (1/2, 1/4, 1/8) 19 | 0x8000, -0x8000, 0x4000, -0x4000, 0x2000, -0x2000, 20 | 21 | // Problematic carry 22 | 0xFFFF, -0xFFFF, 0x1FFFF, -0x1FFFF, 0x3FFFF, -0x3FFFF, 23 | 24 | // Smallest and largest values 25 | 0x7FFFFFFF, 0x80000000, 26 | 27 | // Large random numbers 28 | 831858892, 574794913, 2147272293, -469161054, -961611615, 29 | 1841960234, 1992698389, 520485404, 560523116, -2094993050, 30 | -876897543, -67813629, 2146227091, 509861939, -1073573657, 31 | 32 | // Small random numbers 33 | -14985, 30520, -83587, 41129, 42137, 58537, -2259, 84142, 34 | -28283, 90914, 19865, 33191, 81844, -66273, -63215, -44459, 35 | -11326, 84295, 47515, -39324, 36 | 37 | // Tiny random numbers 38 | -171, -359, 491, 844, 158, -413, -422, -737, -575, -330, 39 | -376, 435, -311, 116, 715, -1024, -487, 59, 724, 993 40 | }; 41 | 42 | #define TESTCASES_COUNT (sizeof(testcases)/sizeof(testcases[0])) 43 | 44 | #define delta(a,b) (((a)>=(b)) ? (a)-(b) : (b)-(a)) 45 | 46 | #ifdef FIXMATH_NO_ROUNDING 47 | const fix32_t max_delta = 1; 48 | #else 49 | const fix32_t max_delta = 0; 50 | #endif 51 | 52 | 53 | void PrintFloat(float f) 54 | { 55 | printf("%f \n", f); 56 | } 57 | void PrintFix64f(fix32_t fx) 58 | { 59 | float f = fix32_to_float(fx); 60 | printf("%f \n", f); 61 | } 62 | void PrintFix64(fix32_t fx) 63 | { 64 | double f = fix32_to_dbl(fx); 65 | printf("%f \n", f); 66 | } 67 | 68 | void PrintFix64_Long(fix32_t fx) 69 | { 70 | double f = fix32_to_dbl(fx); 71 | printf("%.20f \n", f); 72 | } 73 | 74 | int main() 75 | { 76 | int status = 0; 77 | 78 | { 79 | COMMENT("Testing basic float"); 80 | //printf("%#018"PRIx64"\n", fix32_from_dbl(0.5)); 81 | printf("%#018"PRIx64"\n", fix32_from_dbl(1/3.141592653589)); 82 | PrintFix64_Long(fix32_epsilon); 83 | PrintFix64(fix32_maximum); 84 | PrintFix64(fix32_minimum); 85 | } 86 | 87 | { 88 | COMMENT("Testing math operation"); 89 | TEST_DOUBLE_ERROR(fix32_pow2(fix32_from_dbl(24.4894616)), fix32_from_dbl(23553883.31583202), 0.01f); 90 | TEST_DOUBLE_ERROR(fix32_pow(fix32_from_dbl(3.456546), fix32_from_dbl(11.246556)), fix32_from_dbl(1142539.57167091), 0.01f); 91 | TEST_DOUBLE_ERROR(fix32_spow(fix32_from_dbl(312.456546), fix32_from_dbl(11.246556)), fix32_maximum, 0.01f); 92 | TEST_DOUBLE_ERROR(fix32_spow(fix32_from_dbl(-312.456546), fix32_from_dbl(1100.246556)), fix32_minimum, 0.01f); 93 | TEST_DOUBLE_ERROR(fix32_sqrt(fix32_from_dbl(3661.56684)), fix32_from_dbl(60.51088199), 0.01f); 94 | TEST_DOUBLE_ERROR(fix32_exp(fix32_from_dbl(3.56684)), fix32_from_dbl(35.40453785787), 0.01f); 95 | TEST_DOUBLE_ERROR(fix32_ln(fix32_from_dbl(45.24)), fix32_from_dbl(3.81198165), 0.01f); 96 | TEST_DOUBLE_ERROR(fix32_log2(fix32_from_dbl(45.24)), fix32_from_dbl(5.499527), 0.01f); 97 | TEST_DOUBLE_ERROR(fix32_slog2(fix32_from_dbl(-43.0)), fix32_minimum, 0.01f); 98 | } 99 | 100 | //{ 101 | // COMMENT("Testing overflow float"); 102 | // TEST_DOUBLE_ERROR(fix32_add(fix32_maximum, fix32_one), fix32_maximum, 0.01f); 103 | // TEST_DOUBLE_ERROR(fix32_mul(fix32_from_dbl(3661.56684), fix32_from_dbl(89378.654563)), fix32_overflow, 0.01f); 104 | // TEST_DOUBLE_ERROR(fix32_div(fix32_from_dbl(3661.56684), fix32_from_dbl(89378.654563)), fix32_overflow, 0.01f); 105 | //} 106 | 107 | { 108 | COMMENT("Testing lerp"); 109 | TEST_DOUBLE_ERROR(fix32_lerp8(fix32_from_dbl(0.0), fix32_from_dbl(100.0), 76), fix32_from_dbl(29.8), 0.01f); 110 | TEST_DOUBLE_ERROR(fix32_lerp16(fix32_from_dbl(0.0), fix32_from_dbl(100.0), 37484), fix32_from_dbl(57.196044921875), 0.01f); 111 | TEST_DOUBLE_ERROR(fix32_lerp32(fix32_from_dbl(0.0), fix32_from_dbl(100.0), 4698323), fix32_from_dbl(0.109391356818377971649169921875), 0.01f); 112 | } 113 | 114 | { 115 | COMMENT("Testing basic multiplication"); 116 | TEST(fix32_mul(fix32_from_int(2), fix32_from_int(1)) == fix32_from_int(2)); 117 | TEST(fix32_mul(fix32_from_int(5), fix32_from_int(5)) == fix32_from_int(25)); 118 | TEST(fix32_mul(fix32_from_int(-5), fix32_from_int(5)) == fix32_from_int(-25)); 119 | TEST(fix32_mul(fix32_from_int(-5), fix32_from_int(-5)) == fix32_from_int(25)); 120 | TEST(fix32_mul(fix32_from_int(5), fix32_from_int(-5)) == fix32_from_int(-25)); 121 | } 122 | 123 | { 124 | COMMENT("Testing trigonometric functions"); 125 | const int TRIG_TEST_SAMPLES = 10000; 126 | double max_err = 0; 127 | double max_err_angle = 0; 128 | for (int i = 0; i < TRIG_TEST_SAMPLES; ++i) 129 | { 130 | double angle = 3.1415926 * 2 * (double)i / (double)TRIG_TEST_SAMPLES; 131 | double dResult = sin(angle); 132 | fix32_t fResult = fix32_sin(fix32_from_dbl(angle)); 133 | double err = fabs(fix32_to_dbl(fResult) - dResult); 134 | if (err > max_err) 135 | { 136 | max_err = err; 137 | max_err_angle = angle; 138 | } 139 | } 140 | printf("[sin]: max error: %.10f, when angle = %.10f\n", max_err, max_err_angle); 141 | 142 | max_err = 0; 143 | max_err_angle = 0; 144 | for (int i = 0; i < TRIG_TEST_SAMPLES; ++i) 145 | { 146 | double angle = 3.1415926 * 2 * (double)i / (double)TRIG_TEST_SAMPLES; 147 | double dResult = cos(angle); 148 | fix32_t fResult = fix32_cos(fix32_from_dbl(angle)); 149 | double err = fabs(fix32_to_dbl(fResult) - dResult); 150 | if (err > max_err) 151 | { 152 | max_err = err; 153 | max_err_angle = angle; 154 | } 155 | } 156 | printf("[cos]: max error: %.10f, when angle = %.10f\n", max_err, max_err_angle); 157 | 158 | max_err = 0; 159 | max_err_angle = 0; 160 | for (int i = 0; i < TRIG_TEST_SAMPLES; ++i) 161 | { 162 | double angle = -3.141 * 0.5 + 3.1415926 * (double)i / (double)(TRIG_TEST_SAMPLES+10); 163 | double dResult = tan(angle); 164 | fix32_t fResult = fix32_tan(fix32_from_dbl(angle)); 165 | double err = fabs(fix32_to_dbl(fResult) - dResult); 166 | if (err > max_err) 167 | { 168 | max_err = err; 169 | max_err_angle = angle; 170 | } 171 | } 172 | printf("[tan]: max error: %.10f, when angle = %.10f\n", max_err, max_err_angle); 173 | 174 | max_err = 0; 175 | max_err_angle = 0; 176 | for (int i = 0; i < TRIG_TEST_SAMPLES; ++i) 177 | { 178 | double angle = -1 + 2.0 * (double)i / (double)TRIG_TEST_SAMPLES; 179 | double dResult = asin(angle); 180 | fix32_t fResult = fix32_asin(fix32_from_dbl(angle)); 181 | double err = fabs(fix32_to_dbl(fResult) - dResult); 182 | if (err > max_err) 183 | { 184 | max_err = err; 185 | max_err_angle = angle; 186 | } 187 | } 188 | printf("[asin]: max error: %.10f, when value = %.10f\n", max_err, max_err_angle); 189 | 190 | max_err = 0; 191 | max_err_angle = 0; 192 | for (int i = 0; i < TRIG_TEST_SAMPLES; ++i) 193 | { 194 | double angle = -1 + 2.0 * (double)i / (double)TRIG_TEST_SAMPLES; 195 | double dResult = acos(angle); 196 | fix32_t fResult = fix32_acos(fix32_from_dbl(angle)); 197 | double err = fabs(fix32_to_dbl(fResult) - dResult); 198 | if (err > max_err) 199 | { 200 | max_err = err; 201 | max_err_angle = angle; 202 | } 203 | } 204 | printf("[acos]: max error: %.10f, when value = %.10f\n", max_err, max_err_angle); 205 | } 206 | 207 | #ifndef FIXMATH_NO_ROUNDING 208 | { 209 | COMMENT("Testing multiplication rounding corner cases"); 210 | TEST(fix32_mul(0, 10) == 0); 211 | TEST(fix32_mul(2, 0x80000000) == 1); 212 | TEST(fix32_mul(-2, 0x80000000) == -1); 213 | TEST(fix32_mul(3, 0x80000000) == 2); 214 | TEST(fix32_mul(-3, 0x80000000) == -2); 215 | TEST(fix32_mul(2, 0x7FFFFFFF) == 1); 216 | TEST(fix32_mul(-2, 0x7FFFFFFF) == -1); 217 | TEST(fix32_mul(2, 0x80000001) == 1); 218 | TEST(fix32_mul(-2, 0x80000001) == -1); 219 | } 220 | #endif 221 | 222 | { 223 | unsigned int i, j; 224 | int failures = 0; 225 | COMMENT("Running testcases for multiplication"); 226 | 227 | for (i = 0; i < TESTCASES_COUNT; i++) 228 | { 229 | for (j = 0; j < TESTCASES_COUNT; j++) 230 | { 231 | fix32_t a = testcases[i]; 232 | fix32_t b = testcases[j]; 233 | fix32_t result = fix32_mul(a, b); 234 | 235 | double fa = fix32_to_dbl(a); 236 | double fb = fix32_to_dbl(b); 237 | fix32_t fresult = fix32_from_dbl(fa * fb); 238 | 239 | double max = fix32_to_dbl(fix32_maximum); 240 | double min = fix32_to_dbl(fix32_minimum); 241 | 242 | if (delta(fresult, result) > max_delta) 243 | { 244 | if (fa * fb > max || fa * fb < min) 245 | { 246 | #ifndef FIXMATH_NO_OVERFLOW 247 | if (result != fix32_overflow) 248 | { 249 | printf("\n%ld * %ld overflow not detected!\n", a, b); 250 | failures++; 251 | } 252 | #endif 253 | // Legitimate overflow 254 | continue; 255 | } 256 | 257 | printf("\n%ld * %ld = %ld\n", a, b, result); 258 | printf("%f * %f = %ld\n", fa, fb, fresult); 259 | failures++; 260 | } 261 | } 262 | } 263 | 264 | TEST(failures == 0); 265 | } 266 | 267 | { 268 | COMMENT("Testing basic division"); 269 | TEST(fix32_div(fix32_from_int(15), fix32_from_int(5)) == fix32_from_int(3)); 270 | TEST(fix32_div(fix32_from_int(-15), fix32_from_int(5)) == fix32_from_int(-3)); 271 | TEST(fix32_div(fix32_from_int(-15), fix32_from_int(-5)) == fix32_from_int(3)); 272 | TEST(fix32_div(fix32_from_int(15), fix32_from_int(-5)) == fix32_from_int(-3)); 273 | } 274 | 275 | #ifndef FIXMATH_NO_ROUNDING 276 | { 277 | COMMENT("Testing division rounding corner cases"); 278 | TEST(fix32_div(0, 10) == 0); 279 | TEST(fix32_div(1, fix32_from_int(2)) == 1); 280 | TEST(fix32_div(-1, fix32_from_int(2)) == -1); 281 | TEST(fix32_div(1, fix32_from_int(-2)) == -1); 282 | TEST(fix32_div(-1, fix32_from_int(-2)) == 1); 283 | TEST(fix32_div(3, fix32_from_int(2)) == 2); 284 | TEST(fix32_div(-3, fix32_from_int(2)) == -2); 285 | TEST(fix32_div(3, fix32_from_int(-2)) == -2); 286 | TEST(fix32_div(-3, fix32_from_int(-2)) == 2); 287 | TEST(fix32_div(2, 0x7FFFFFFF) == 4); 288 | TEST(fix32_div(-2, 0x7FFFFFFF) == -4); 289 | TEST(fix32_div(2, 0x80000001) == 4); 290 | TEST(fix32_div(-2, 0x80000001) == -4); 291 | } 292 | #endif 293 | 294 | { 295 | unsigned int i, j; 296 | int failures = 0; 297 | COMMENT("Running testcases for division"); 298 | 299 | for (i = 0; i < TESTCASES_COUNT; i++) 300 | { 301 | for (j = 0; j < TESTCASES_COUNT; j++) 302 | { 303 | fix32_t a = testcases[i]; 304 | fix32_t b = testcases[j]; 305 | 306 | // We don't require a solution for /0 :) 307 | if (b == 0) continue; 308 | 309 | fix32_t result = fix32_div(a, b); 310 | 311 | double fa = fix32_to_dbl(a); 312 | double fb = fix32_to_dbl(b); 313 | fix32_t fresult = fix32_from_dbl(fa / fb); 314 | 315 | double max = fix32_to_dbl(fix32_maximum); 316 | double min = fix32_to_dbl(fix32_minimum); 317 | if (delta(fresult, result) > max_delta) 318 | { 319 | if (((fa / fb) > max) || ((fa / fb) < min)) 320 | { 321 | #ifndef FIXMATH_NO_OVERFLOW 322 | if (result != fix32_overflow) 323 | { 324 | printf("\n%ld / %ld overflow not detected!\n", a, b); 325 | failures++; 326 | } 327 | #endif 328 | // Legitimate overflow 329 | continue; 330 | } 331 | 332 | printf("\n%.15f / %.15f = %.25f\n", fix32_to_dbl(a), fix32_to_dbl(b), fix32_to_dbl(result)); 333 | printf("%.15f / %.15f = %.25f\n", fa, fb, (fa / fb)); 334 | printf("delta: %ld\n", delta(fresult, result)); 335 | failures++; 336 | } 337 | } 338 | } 339 | 340 | TEST(failures == 0); 341 | } 342 | 343 | { 344 | unsigned int i, j; 345 | int failures = 0; 346 | COMMENT("Running testcases for addition"); 347 | 348 | for (i = 0; i < TESTCASES_COUNT; i++) 349 | { 350 | for (j = 0; j < TESTCASES_COUNT; j++) 351 | { 352 | fix32_t a = testcases[i]; 353 | fix32_t b = testcases[j]; 354 | 355 | fix32_t result = fix32_add(a, b); 356 | 357 | double fa = fix32_to_dbl(a); 358 | double fb = fix32_to_dbl(b); 359 | fix32_t fresult = fix32_from_dbl(fa + fb); 360 | 361 | double max = fix32_to_dbl(fix32_maximum); 362 | double min = fix32_to_dbl(fix32_minimum); 363 | 364 | if (delta(fresult, result) > max_delta) 365 | { 366 | if (fa + fb > max || fa + fb < min) 367 | { 368 | #ifndef FIXMATH_NO_OVERFLOW 369 | if (result != fix32_overflow) 370 | { 371 | printf("\n%ld + %ld overflow not detected!\n", a, b); 372 | failures++; 373 | } 374 | #endif 375 | // Legitimate overflow 376 | continue; 377 | } 378 | 379 | printf("\n%ld + %ld = %ld\n", a, b, result); 380 | printf("%f + %f = %ld\n", fa, fb, fresult); 381 | failures++; 382 | } 383 | } 384 | } 385 | 386 | TEST(failures == 0); 387 | } 388 | 389 | { 390 | unsigned int i, j; 391 | int failures = 0; 392 | COMMENT("Running testcases for subtraction"); 393 | 394 | for (i = 0; i < TESTCASES_COUNT; i++) 395 | { 396 | for (j = 0; j < TESTCASES_COUNT; j++) 397 | { 398 | fix32_t a = testcases[i]; 399 | fix32_t b = testcases[j]; 400 | 401 | fix32_t result = fix32_sub(a, b); 402 | 403 | double fa = fix32_to_dbl(a); 404 | double fb = fix32_to_dbl(b); 405 | fix32_t fresult = fix32_from_dbl(fa - fb); 406 | 407 | double max = fix32_to_dbl(fix32_maximum); 408 | double min = fix32_to_dbl(fix32_minimum); 409 | 410 | if (delta(fresult, result) > max_delta) 411 | { 412 | if (fa - fb > max || fa - fb < min) 413 | { 414 | #ifndef FIXMATH_NO_OVERFLOW 415 | if (result != fix32_overflow) 416 | { 417 | printf("\n%ld - %ld overflow not detected!\n", a, b); 418 | failures++; 419 | } 420 | #endif 421 | // Legitimate overflow 422 | continue; 423 | } 424 | 425 | printf("\n%ld - %ld = %ld\n", a, b, result); 426 | printf("%f - %f = %ld\n", fa, fb, fresult); 427 | failures++; 428 | } 429 | } 430 | } 431 | 432 | TEST(failures == 0); 433 | } 434 | 435 | { 436 | COMMENT("Testing basic square roots"); 437 | TEST(fix32_sqrt(fix32_from_int(16)) == fix32_from_int(4)); 438 | TEST(fix32_sqrt(fix32_from_int(100)) == fix32_from_int(10)); 439 | TEST(fix32_sqrt(fix32_from_int(1)) == fix32_from_int(1)); 440 | } 441 | 442 | #ifndef FIXMATH_NO_ROUNDING 443 | { 444 | // TODO: FIX TESTS! 445 | COMMENT("Testing square root rounding corner cases"); 446 | //TEST(fix32_sqrt(214748302) == 3751499); 447 | //TEST(fix32_sqrt(214748303) == 3751499); 448 | //TEST(fix32_sqrt(214748359) == 3751499); 449 | //TEST(fix32_sqrt(214748360) == 3751500); 450 | } 451 | #endif 452 | 453 | { 454 | unsigned int i; 455 | int failures = 0; 456 | COMMENT("Running test cases for square root"); 457 | 458 | for (i = 0; i < TESTCASES_COUNT; i++) 459 | { 460 | fix32_t a = testcases[i]; 461 | 462 | if (a < 0) continue; 463 | 464 | fix32_t result = fix32_sqrt(a); 465 | 466 | double fa = fix32_to_dbl(a); 467 | fix32_t fresult = fix32_from_dbl(sqrt(fa)); 468 | 469 | if (delta(fresult, result) > max_delta) 470 | { 471 | printf("\nfix32_sqrt(%ld) = %ld\n", a, result); 472 | printf("sqrt(%f) = %ld\n", fa, fresult); 473 | failures++; 474 | } 475 | } 476 | 477 | TEST(failures == 0); 478 | } 479 | 480 | if (status != 0) 481 | fprintf(stdout, "\n\nSome tests FAILED!\n"); 482 | 483 | return status; 484 | } 485 | --------------------------------------------------------------------------------