diff options
| author | flatmush <flatmush@d3e1167c-abe1-51d5-8199-f9061ebe54e4> | 2011-02-28 15:04:50 +0000 |
|---|---|---|
| committer | flatmush <flatmush@d3e1167c-abe1-51d5-8199-f9061ebe54e4> | 2011-02-28 15:04:50 +0000 |
| commit | 047ab9fba06906cd520c9a2c07faf741f703ec30 (patch) | |
| tree | 88bf6311236a2f7b6b6f476b11834a71936cf4fd | |
| parent | ae58c98283e883898692c9484b62cc1a9ee749e5 (diff) | |
| download | libfixmath-047ab9fba06906cd520c9a2c07faf741f703ec30.tar.gz | |
Updated 32-bit divide, gained 1600% speed increase and an accuracy of 0.00065% (rather than 0.0035%) by multiplying by the reciprocal rather than using a divide algorithm.
| -rw-r--r-- | libfixmath/fix16.c | 46 |
1 files changed, 42 insertions, 4 deletions
diff --git a/libfixmath/fix16.c b/libfixmath/fix16.c index 88131d8..a40f3c8 100644 --- a/libfixmath/fix16.c +++ b/libfixmath/fix16.c @@ -97,7 +97,24 @@ fix16_t fix16_div(fix16_t inArg0, fix16_t inArg1) { tempResult /= inArg1;
return tempResult;
#else
- int32_t res = (inArg0 / inArg1) << 16;
+ int32_t rcp = (0xFFFFFFFF / inArg1);
+ int32_t rcp_hi = rcp >> 16;
+
+ uint32_t rcp_lo = rcp & 0xFFFF;
+ int32_t arg_hi = (inArg0 >> 16);
+ uint32_t arg_lo = (inArg0 & 0xFFFF);
+
+ int32_t res_hi = rcp_hi * arg_hi;
+ int32_t res_md = (rcp_hi * arg_lo) + (rcp_lo * arg_hi);
+ uint32_t res_lo = rcp_lo * arg_lo;
+
+ int32_t res = (res_hi << 16) + res_md + (res_lo >> 16);
+ #ifndef FIXMATH_NO_ROUNDING
+ res += ((res_lo >> 15) & 1);
+ #endif
+ return res;
+
+ /*int32_t res = (inArg0 / inArg1) << 16;
int32_t mod = inArg0 % inArg1;
uintptr_t i;
for(i = 0; i < 16; i++) {
@@ -109,7 +126,7 @@ fix16_t fix16_div(fix16_t inArg0, fix16_t inArg1) { if((mod << 1) / inArg1)
res++;
#endif
- return res;
+ return res;*/
#endif
}
@@ -132,7 +149,28 @@ fix16_t fix16_sdiv(fix16_t inArg0, fix16_t inArg1) { return fix16_MAX;
return tempResult;
#else
- int32_t res = (inArg0 / inArg1);
+ int32_t rcp = (0xFFFFFFFF / inArg1);
+ int32_t rcp_hi = rcp >> 16;
+ if(rcp_hi >= 32768)
+ return fix16_MAX;
+ if(rcp_hi < -32768)
+ return fix16_MIN;
+
+ uint32_t rcp_lo = rcp & 0xFFFF;
+ int32_t arg_hi = (inArg0 >> 16);
+ uint32_t arg_lo = (inArg0 & 0xFFFF);
+
+ int32_t res_hi = rcp_hi * arg_hi;
+ int32_t res_md = (rcp_hi * arg_lo) + (rcp_lo * arg_hi);
+ uint32_t res_lo = rcp_lo * arg_lo;
+
+ int32_t res = (res_hi << 16) + res_md + (res_lo >> 16);
+ #ifndef FIXMATH_NO_ROUNDING
+ res += ((res_lo >> 15) & 1);
+ #endif
+ return res;
+
+ /*int32_t res = (inArg0 / inArg1);
if((res < -32768) || (res >= 32768))
return (res < 0 ? fix16_MIN : fix16_MAX);
res <<= 16;
@@ -147,7 +185,7 @@ fix16_t fix16_sdiv(fix16_t inArg0, fix16_t inArg1) { if((mod << 1) / inArg1)
res++;
#endif
- return res;
+ return res;*/
#endif
}
|
