Removed 64-bit restriction on linear interpolation functions. Added more test cases and fixed several bugs in the 64-bit arithmetic functions.
Also added script to run all unit tests.
This commit is contained in:
parent
2859cbf31d
commit
18a9ad00de
|
@ -480,9 +480,6 @@ fix16_t fix16_mod(fix16_t x, fix16_t y)
|
|||
return x;
|
||||
}
|
||||
|
||||
|
||||
#ifndef FIXMATH_NO_64BIT
|
||||
|
||||
fix16_t fix16_lerp8(fix16_t inArg0, fix16_t inArg1, uint8_t inFract)
|
||||
{
|
||||
int64_t tempOut = int64_mul_i32_i32(inArg0, (((int32_t)1 << 8) - inFract));
|
||||
|
@ -501,10 +498,11 @@ fix16_t fix16_lerp16(fix16_t inArg0, fix16_t inArg1, uint16_t inFract)
|
|||
|
||||
fix16_t fix16_lerp32(fix16_t inArg0, fix16_t inArg1, uint32_t inFract)
|
||||
{
|
||||
int64_t tempOut;
|
||||
tempOut = ((int64_t)inArg0 * (((int64_t)1<<32) - inFract));
|
||||
tempOut += ((int64_t)inArg1 * inFract);
|
||||
tempOut >>= 32;
|
||||
return (fix16_t)tempOut;
|
||||
if(inFract == 0)
|
||||
return inArg0;
|
||||
int64_t inFract64 = int64_const(0, inFract);
|
||||
int64_t subbed = int64_sub(int64_const(1,0), inFract64);
|
||||
int64_t tempOut = int64_mul_i64_i32(subbed, inArg0);
|
||||
tempOut = int64_add(tempOut, int64_mul_i64_i32(inFract64, inArg1));
|
||||
return int64_hi(tempOut);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -144,9 +144,7 @@ extern fix16_t fix16_mod(fix16_t x, fix16_t y) FIXMATH_FUNC_ATTRS;
|
|||
*/
|
||||
extern fix16_t fix16_lerp8(fix16_t inArg0, fix16_t inArg1, uint8_t inFract) FIXMATH_FUNC_ATTRS;
|
||||
extern fix16_t fix16_lerp16(fix16_t inArg0, fix16_t inArg1, uint16_t inFract) FIXMATH_FUNC_ATTRS;
|
||||
#ifndef FIXMATH_NO_64BIT
|
||||
extern fix16_t fix16_lerp32(fix16_t inArg0, fix16_t inArg1, uint32_t inFract) FIXMATH_FUNC_ATTRS;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ static inline _int64_t int64_add(_int64_t x, _int64_t y) {
|
|||
_int64_t ret;
|
||||
ret.hi = x.hi + y.hi;
|
||||
ret.lo = x.lo + y.lo;
|
||||
if((ret.lo < x.lo) || (ret.hi < y.hi))
|
||||
if((ret.lo < x.lo) || (ret.lo < y.lo))
|
||||
ret.hi++;
|
||||
return ret;
|
||||
}
|
||||
|
@ -72,18 +72,25 @@ static inline _int64_t int64_sub(_int64_t x, _int64_t y) {
|
|||
}
|
||||
|
||||
static inline _int64_t int64_shift(_int64_t x, int8_t y) {
|
||||
_int64_t ret;
|
||||
if(y > 0) {
|
||||
if(y >= 32)
|
||||
return (_int64_t){ 0, 0 };
|
||||
_int64_t ret = {0,0};
|
||||
if(y >= 64 || y <= -64)
|
||||
return (_int64_t){ 0, 0 };
|
||||
if(y >= 32) {
|
||||
ret.hi = (x.lo << (y - 32));
|
||||
}
|
||||
else if(y > 0) {
|
||||
ret.hi = (x.hi << y) | (x.lo >> (32 - y));
|
||||
ret.lo = (x.lo << y);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
y = -y;
|
||||
if(y >= 32)
|
||||
return (_int64_t){ 0, 0 };
|
||||
ret.lo = (x.lo >> y) | (x.hi << (32 - y));
|
||||
ret.hi = (x.hi >> y);
|
||||
if(y >= 32){
|
||||
ret.lo = (x.hi >> (y - 32));
|
||||
ret.hi = (x.hi < 0) ? -1 : 0;
|
||||
} else {
|
||||
ret.lo = (x.lo >> y) | (x.hi << (32 - y));
|
||||
ret.hi = (x.hi >> y);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -96,31 +103,37 @@ static inline _int64_t int64_mul_i32_i32(int32_t x, int32_t y) {
|
|||
int32_t r_md = (hi[0] * lo[1]) + (hi[1] * lo[0]);
|
||||
uint32_t r_lo = lo[0] * lo[1];
|
||||
|
||||
r_hi += (r_md >> 16);
|
||||
r_lo += (r_md << 16);
|
||||
_int64_t r_hilo64 = (_int64_t){ r_hi, r_lo };
|
||||
_int64_t r_md64 = int64_shift(int64_from_int32(r_md), 16);
|
||||
|
||||
return (_int64_t){ r_hi, r_lo };
|
||||
return int64_add(r_hilo64, r_md64);
|
||||
}
|
||||
|
||||
static inline _int64_t int64_mul_i64_i32(_int64_t x, int32_t y) {
|
||||
int neg = ((x.hi ^ y) < 0);
|
||||
if(x.hi < 0)
|
||||
x = int64_neg(x);
|
||||
if(y < 0)
|
||||
y = -y;
|
||||
uint32_t ypos = (y < 0)? (-y) : (y);
|
||||
|
||||
uint32_t _x[4] = { (x.hi >> 16), (x.hi & 0xFFFF), (x.lo >> 16), (x.lo & 0xFFFF) };
|
||||
uint32_t _y[2] = { (y >> 16), (y & 0xFFFF) };
|
||||
uint32_t _x[4] = { (x.lo & 0xFFFF), (x.lo >> 16), (x.hi & 0xFFFF), (x.hi >> 16) };
|
||||
uint32_t _y[2] = { (ypos & 0xFFFF), (ypos >> 16) };
|
||||
|
||||
uint32_t r[4];
|
||||
r[0] = (_x[0] * _y[0]);
|
||||
r[1] = (_x[1] * _y[0]) + (_x[0] * _y[1]);
|
||||
r[2] = (_x[1] * _y[1]) + (_x[2] * _y[0]);
|
||||
r[3] = (_x[2] * _y[0]) + (_x[1] * _y[1]);
|
||||
r[1] = (_x[1] * _y[0]);
|
||||
uint32_t temp_r1 = r[1];
|
||||
r[1] += (_x[0] * _y[1]);
|
||||
r[2] = (_x[2] * _y[0]) + (_x[1] * _y[1]);
|
||||
r[3] = (_x[3] * _y[0]) + (_x[2] * _y[1]);
|
||||
// Detect carry bit in r[1]. r[0] can't carry, and r[2]/r[3] don't matter.
|
||||
if(r[1] < temp_r1)
|
||||
r[3] ++;
|
||||
|
||||
_int64_t middle = int64_shift(int64_const(0, r[1]), 16);
|
||||
_int64_t ret;
|
||||
ret.lo = r[0] + (r[1] << 16);
|
||||
ret.hi = (r[3] << 16) + r[2] + (r[1] >> 16);
|
||||
ret.lo = r[0];
|
||||
ret.hi = (r[3] << 16) + r[2];
|
||||
ret = int64_add(ret, middle);
|
||||
return (neg ? int64_neg(ret) : ret);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include "int64.h"
|
||||
#include "unittests.h"
|
||||
|
||||
const fix16_t testcases[] = {
|
||||
|
@ -330,7 +331,31 @@ int main()
|
|||
TEST(failures == 0);
|
||||
}
|
||||
|
||||
#ifndef FIXMATH_NO_64BIT
|
||||
{
|
||||
COMMENT("Running int64 test cases");
|
||||
TEST(int64_cmp_eq(int64_const(0,1), int64_from_int32(1)));
|
||||
TEST(int64_cmp_eq(int64_const(0xffffffff,0xfffffffe), int64_from_int32(-2)));
|
||||
TEST(int64_cmp_eq(int64_const(1,0), int64_shift(int64_from_int32(1),32)));
|
||||
TEST(int64_cmp_eq(int64_const(1,0), int64_shift(int64_from_int32(2),31)));
|
||||
TEST(int64_cmp_eq(int64_const(0,(1<<31)), int64_shift(int64_from_int32(1),31)));
|
||||
TEST(int64_cmp_eq(int64_const(-2,0), int64_shift(int64_from_int32(-1),33)));
|
||||
TEST(int64_cmp_eq(int64_const(0,1), int64_shift(int64_const(0,2),-1)));
|
||||
TEST(int64_cmp_eq(int64_const(2,1), int64_shift(int64_const(4,2),-1)));
|
||||
TEST(int64_cmp_eq(int64_const(0,(1<<31)), int64_shift(int64_const(1,0),-1)));
|
||||
TEST(int64_cmp_eq(int64_const(0,4), int64_shift(int64_const(2,0),-31)));
|
||||
TEST(int64_cmp_eq(int64_const(0,2), int64_shift(int64_const(2,0),-32)));
|
||||
TEST(int64_cmp_eq(int64_const(0,1), int64_shift(int64_const(2,0),-33)));
|
||||
int64_t bit31 = int64_const(0, 0x80000000);
|
||||
int64_t negbit31 = int64_const(-1, 0x80000000);
|
||||
TEST(int64_cmp_eq(negbit31, int64_neg(bit31)));
|
||||
TEST(int64_cmp_eq(int64_const(1,0), int64_mul_i64_i32(bit31, 2)));
|
||||
TEST(int64_cmp_eq(int64_const(-1,(1<<31)), int64_mul_i64_i32(bit31, -1)));
|
||||
TEST(int64_cmp_eq(int64_mul_i64_i32(int64_const(0,-1), fix16_maximum),
|
||||
int64_const(0x7ffffffe, 0x80000001)));
|
||||
TEST(int64_cmp_eq(int64_mul_i64_i32(int64_const(0,1), fix16_minimum),
|
||||
int64_const(-1, fix16_minimum)));
|
||||
}
|
||||
|
||||
{
|
||||
COMMENT("Running linear interpolation test cases");
|
||||
|
||||
|
@ -358,7 +383,6 @@ int main()
|
|||
TEST(fix16_lerp32(fix16_minimum, fix16_maximum, 0xffffffff) == (fix16_maximum - 1));
|
||||
TEST(fix16_lerp32(-fix16_maximum, fix16_maximum, 0x80000000) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (status != 0)
|
||||
fprintf(stdout, "\n\nSome tests FAILED!\n");
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
fail=0
|
||||
pass=0
|
||||
|
||||
for f in fix16_unittests_* fix16_exp_unittests fix16_macros_unittests fix16_str_unittests_*
|
||||
do
|
||||
if ! ./$f >> /dev/null; then
|
||||
echo "./$f failed!"
|
||||
((fail=fail+1))
|
||||
else
|
||||
((pass=pass+1))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "$fail tests failed, $pass tests passed."
|
Loading…
Reference in New Issue