diff --git a/include/ucore/saturating_math.h b/include/ucore/saturating_math.h new file mode 100644 index 0000000..7b05905 --- /dev/null +++ b/include/ucore/saturating_math.h @@ -0,0 +1,78 @@ +#include + +/** Implementation of saturated operation on uintaa_t. + * Opaerations are clamped betweehn 0 and UINTaa_MAa instead of + * wrapping around*/ + +#define UC_SAT_ADD(a, b, type, max_val)\ +((type)((a) + (b)) >= (a) ? (a) + (b) : (max_val)) + +#define UC_SAT_SUB(a, b)\ +(a >= b ? (a) - (b) : 0) + +#define UC_SAT_MULT(a, b, type, max_val)\ +((b) == 0 ? 0 :\ +(a) <= (max_val) / (b) ? (type) (a) * (type) (b) \ + : (max_val)) + + +static inline uint8_t uc_sat_addu8(uint8_t a, uint8_t b) +{ + return UC_SAT_ADD(a, b, uint8_t, UINT8_MAX); +} + +static inline uint8_t uc_sat_subu8(uint8_t a, uint8_t b) +{ + return UC_SAT_SUB(a, b); +} + +static inline uint8_t uc_sat_multu8(uint8_t a, uint8_t b) +{ + return UC_SAT_MULT(a, b, uint8_t, UINT8_MAX); +} + +static inline uint16_t uc_sat_addu16(uint16_t a, uint16_t b) +{ + return UC_SAT_ADD(a, b, uint16_t, UINT16_MAX); +} + +static inline uint16_t uc_sat_subu16(uint16_t a, uint16_t b) +{ + return UC_SAT_SUB(a, b); +} + +static inline uint16_t uc_sat_multu16(uint16_t a, uint16_t b) +{ + return UC_SAT_MULT(a, b, uint16_t, UINT16_MAX); +} + +static inline uint32_t uc_sat_addu32(uint32_t a, uint32_t b) +{ + return UC_SAT_ADD(a, b, uint32_t, UINT32_MAX); +} + +static inline uint32_t uc_sat_subu32(uint32_t a, uint32_t b) +{ + return UC_SAT_SUB(a, b); +} + +static inline uint32_t uc_sat_multu32(uint32_t a, uint32_t b) +{ + return UC_SAT_MULT(a, b, uint32_t, UINT32_MAX); +} + +static inline uint64_t uc_sat_addu64(uint64_t a, uint64_t b) +{ + return UC_SAT_ADD(a, b, uint64_t, UINT64_MAX); +} + +static inline uint64_t uc_sat_subu64(uint64_t a, uint64_t b) +{ + return UC_SAT_SUB(a, b); +} + +static inline uint64_t uc_sat_multu64(uint64_t a, uint64_t b) +{ + return UC_SAT_MULT(a, b, uint64_t, UINT64_MAX); +} + diff --git a/test/test_runner.c b/test/test_runner.c index ea0faa2..7799fc2 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -17,6 +17,7 @@ extern Suite *threadqueue_suite(void); extern Suite *buffer_suite(void); extern Suite *clock_suite(void); extern Suite *seq_suite(void); +extern Suite *sat_math_suite(void); static suite_func suites[] = { bitvec_suite, @@ -30,6 +31,7 @@ static suite_func suites[] = { buffer_suite, clock_suite, seq_suite, + sat_math_suite }; int diff --git a/test/test_sat_math.c b/test/test_sat_math.c new file mode 100644 index 0000000..1fcaa67 --- /dev/null +++ b/test/test_sat_math.c @@ -0,0 +1,509 @@ +#include +#include + + +START_TEST (test_sat_uc_addu8) + uint8_t a; + uint8_t b; + + a = UINT8_MAX; + b = 1; + fail_if(uc_sat_addu8(a,b) != UINT8_MAX); + + a = 1; + b = UINT8_MAX; + fail_if(uc_sat_addu8(a,b) != UINT8_MAX); + + a = UINT8_MAX; + b = UINT8_MAX; + fail_if(uc_sat_addu8(a,b) != UINT8_MAX); + + a = UINT8_MAX - 2; + b = 2; + fail_if(uc_sat_addu8(a,b) != UINT8_MAX); + + a = 2; + b = UINT8_MAX - 2; + fail_if(uc_sat_addu8(a,b) != UINT8_MAX); + + a = UINT8_MAX - 3; + b = 2; + fail_if(uc_sat_addu8(a,b) != UINT8_MAX - 1); + + a = 2; + b = UINT8_MAX - 3; + fail_if(uc_sat_addu8(a,b) != UINT8_MAX - 1); + + a = 0; + b = UINT8_MAX; + fail_if(uc_sat_addu8(a,b) != UINT8_MAX); + + a = UINT8_MAX; + b = 0; + fail_if(uc_sat_addu8(a,b) != UINT8_MAX); + + a = 0; + b = 0; + fail_if(uc_sat_addu8(a,b) != 0); + + a = 100; + b = 100; + fail_if(uc_sat_addu8(a,b) != 200); +END_TEST + +START_TEST (test_sat_uc_subu8) + uint8_t a; + uint8_t b; + + a = UINT8_MAX; + b = 0; + fail_if(uc_sat_subu8(a,b) != UINT8_MAX); + + a = 0; + b = UINT8_MAX; + fail_if(uc_sat_subu8(a,b) != 0); + + a = UINT8_MAX; + b = UINT8_MAX; + fail_if(uc_sat_subu8(a,b) != 0); + + a = 0; + b = 1; + fail_if(uc_sat_subu8(a,b) != 0); + + a = 1; + b = UINT8_MAX - 1; + fail_if(uc_sat_subu8(a,b) != 0); + + a = UINT8_MAX; + b = 100; + fail_if(uc_sat_subu8(a,b) != UINT8_MAX - 100); + + a = 100; + b = 100; + fail_if(uc_sat_subu8(a,b) != 0); +END_TEST + +START_TEST (test_sat_uc_multu8) + uint8_t a; + uint8_t b; + + a = UINT8_MAX; + b = 0; + fail_if(uc_sat_multu8(a,b) != 0); + + a = 0; + b = UINT8_MAX; + fail_if(uc_sat_multu8(a,b) != 0); + + a = UINT8_MAX; + b = UINT8_MAX; + fail_if(uc_sat_multu8(a,b) != UINT8_MAX); + + a = UINT8_MAX; + b = 2; + fail_if(uc_sat_multu8(a,b) != UINT8_MAX); + + a = 2; + b = UINT8_MAX; + fail_if(uc_sat_multu8(a,b) != UINT8_MAX); + + a = UINT8_MAX; + b = UINT8_MAX/2 - 1; + fail_if(uc_sat_multu8(a,b) != UINT8_MAX); + + a = UINT8_MAX/2 - 1; + b = UINT8_MAX; + fail_if(uc_sat_multu8(a,b) != UINT8_MAX); + + a = 10; + b = 10; + fail_if(uc_sat_multu8(a,b) != 100); + +END_TEST + + +START_TEST (test_sat_uc_addu16) + uint16_t a; + uint16_t b; + + a = UINT16_MAX; + b = 1; + fail_if(uc_sat_addu16(a,b) != UINT16_MAX); + + a = 1; + b = UINT16_MAX; + fail_if(uc_sat_addu16(a,b) != UINT16_MAX); + + a = UINT16_MAX; + b = UINT16_MAX; + fail_if(uc_sat_addu16(a,b) != UINT16_MAX); + + a = UINT16_MAX - 2; + b = 2; + fail_if(uc_sat_addu16(a,b) != UINT16_MAX); + + a = 2; + b = UINT16_MAX - 2; + fail_if(uc_sat_addu16(a,b) != UINT16_MAX); + + a = UINT16_MAX - 3; + b = 2; + fail_if(uc_sat_addu16(a,b) != UINT16_MAX - 1); + + a = 2; + b = UINT16_MAX - 3; + fail_if(uc_sat_addu16(a,b) != UINT16_MAX - 1); + + a = 0; + b = UINT16_MAX; + fail_if(uc_sat_addu16(a,b) != UINT16_MAX); + + a = UINT16_MAX; + b = 0; + fail_if(uc_sat_addu16(a,b) != UINT16_MAX); + + a = 0; + b = 0; + fail_if(uc_sat_addu16(a,b) != 0); + + a = 100; + b = 100; + fail_if(uc_sat_addu16(a,b) != 200); +END_TEST + +START_TEST (test_sat_uc_subu16) + uint16_t a; + uint16_t b; + + a = UINT16_MAX; + b = 0; + fail_if(uc_sat_subu16(a,b) != UINT16_MAX); + + a = 0; + b = UINT16_MAX; + fail_if(uc_sat_subu16(a,b) != 0); + + a = UINT16_MAX; + b = UINT16_MAX; + fail_if(uc_sat_subu16(a,b) != 0); + + a = 0; + b = 1; + fail_if(uc_sat_subu16(a,b) != 0); + + a = 1; + b = UINT16_MAX - 1; + fail_if(uc_sat_subu16(a,b) != 0); + + a = UINT16_MAX; + b = 100; + fail_if(uc_sat_subu16(a,b) != UINT16_MAX - 100); + + a = 100; + b = 100; + fail_if(uc_sat_subu16(a,b) != 0); +END_TEST + +START_TEST (test_sat_uc_multu16) + uint16_t a; + uint16_t b; + + a = UINT16_MAX; + b = 0; + fail_if(uc_sat_multu16(a,b) != 0); + + a = 0; + b = UINT16_MAX; + fail_if(uc_sat_multu16(a,b) != 0); + + a = UINT16_MAX; + b = UINT16_MAX; + fail_if(uc_sat_multu16(a,b) != UINT16_MAX); + + a = UINT16_MAX; + b = 2; + fail_if(uc_sat_multu16(a,b) != UINT16_MAX); + + a = 2; + b = UINT16_MAX; + fail_if(uc_sat_multu16(a,b) != UINT16_MAX); + + a = UINT16_MAX; + b = UINT16_MAX/2 - 1; + fail_if(uc_sat_multu16(a,b) != UINT16_MAX); + + a = UINT16_MAX/2 - 1; + b = UINT16_MAX; + fail_if(uc_sat_multu16(a,b) != UINT16_MAX); + + a = 10; + b = 10; + fail_if(uc_sat_multu16(a,b) != 100); + +END_TEST + +START_TEST (test_sat_uc_addu32) + uint32_t a; + uint32_t b; + + a = UINT32_MAX; + b = 1; + fail_if(uc_sat_addu32(a,b) != UINT32_MAX); + + a = 1; + b = UINT32_MAX; + fail_if(uc_sat_addu32(a,b) != UINT32_MAX); + + a = UINT32_MAX; + b = UINT32_MAX; + fail_if(uc_sat_addu32(a,b) != UINT32_MAX); + + a = UINT32_MAX - 2; + b = 2; + fail_if(uc_sat_addu32(a,b) != UINT32_MAX); + + a = 2; + b = UINT32_MAX - 2; + fail_if(uc_sat_addu32(a,b) != UINT32_MAX); + + a = UINT32_MAX - 3; + b = 2; + fail_if(uc_sat_addu32(a,b) != UINT32_MAX - 1); + + a = 2; + b = UINT32_MAX - 3; + fail_if(uc_sat_addu32(a,b) != UINT32_MAX - 1); + + a = 0; + b = UINT32_MAX; + fail_if(uc_sat_addu32(a,b) != UINT32_MAX); + + a = UINT32_MAX; + b = 0; + fail_if(uc_sat_addu32(a,b) != UINT32_MAX); + + a = 0; + b = 0; + fail_if(uc_sat_addu32(a,b) != 0); + + a = 0x1fffffff; + b = 0x80000000; + fail_if(uc_sat_addu32(a,b) != 0x9fffffff); +END_TEST + +START_TEST (test_sat_uc_subu32) + uint32_t a; + uint32_t b; + + a = UINT32_MAX; + b = 0; + fail_if(uc_sat_subu32(a,b) != UINT32_MAX); + + a = 0; + b = UINT32_MAX; + fail_if(uc_sat_subu32(a,b) != 0); + + a = UINT32_MAX; + b = UINT32_MAX; + fail_if(uc_sat_subu32(a,b) != 0); + + a = 0; + b = 1; + fail_if(uc_sat_subu32(a,b) != 0); + + a = 1; + b = UINT32_MAX - 1; + fail_if(uc_sat_subu32(a,b) != 0); + + a = UINT32_MAX; + b = 100; + fail_if(uc_sat_subu32(a,b) != UINT32_MAX - 100); + + a = 100; + b = 100; + fail_if(uc_sat_subu32(a,b) != 0); +END_TEST + +START_TEST (test_sat_uc_multu32) + uint32_t a; + uint32_t b; + + a = UINT32_MAX; + b = 0; + fail_if(uc_sat_multu32(a,b) != 0); + + a = 0; + b = UINT32_MAX; + fail_if(uc_sat_multu32(a,b) != 0); + + a = UINT32_MAX; + b = UINT32_MAX; + fail_if(uc_sat_multu32(a,b) != UINT32_MAX); + + a = UINT32_MAX; + b = 2; + fail_if(uc_sat_multu32(a,b) != UINT32_MAX); + + a = 2; + b = UINT32_MAX; + fail_if(uc_sat_multu32(a,b) != UINT32_MAX); + + a = UINT32_MAX; + b = UINT32_MAX/2 - 1; + fail_if(uc_sat_multu32(a,b) != UINT32_MAX); + + a = UINT32_MAX/2 - 1; + b = UINT32_MAX; + fail_if(uc_sat_multu32(a,b) != UINT32_MAX); + + a = 10; + b = 10; + fail_if(uc_sat_multu32(a,b) != 100); + +END_TEST +START_TEST (test_sat_uc_addu64) + uint64_t a; + uint64_t b; + + a = UINT64_MAX; + b = 1; + fail_if(uc_sat_addu64(a,b) != UINT64_MAX); + + a = 1; + b = UINT64_MAX; + fail_if(uc_sat_addu64(a,b) != UINT64_MAX); + + a = UINT64_MAX; + b = UINT64_MAX; + fail_if(uc_sat_addu64(a,b) != UINT64_MAX); + + a = UINT64_MAX - 2; + b = 2; + fail_if(uc_sat_addu64(a,b) != UINT64_MAX); + + a = 2; + b = UINT64_MAX - 2; + fail_if(uc_sat_addu64(a,b) != UINT64_MAX); + + a = UINT64_MAX - 3; + b = 2; + fail_if(uc_sat_addu64(a,b) != UINT64_MAX - 1); + + a = 2; + b = UINT64_MAX - 3; + fail_if(uc_sat_addu64(a,b) != UINT64_MAX - 1); + + a = 0; + b = UINT64_MAX; + fail_if(uc_sat_addu64(a,b) != UINT64_MAX); + + a = UINT64_MAX; + b = 0; + fail_if(uc_sat_addu64(a,b) != UINT64_MAX); + + a = 0; + b = 0; + fail_if(uc_sat_addu64(a,b) != 0); + + a = 0x1fffffffffffffffULL; + b = 0x8000000000000000ULL; + fail_if(uc_sat_addu64(a,b) != 0x9fffffffffffffffULL); +END_TEST + +START_TEST (test_sat_uc_subu64) + uint64_t a; + uint64_t b; + + a = UINT64_MAX; + b = 0; + fail_if(uc_sat_subu64(a,b) != UINT64_MAX); + + a = 0; + b = UINT64_MAX; + fail_if(uc_sat_subu64(a,b) != 0); + + a = UINT64_MAX; + b = UINT64_MAX; + fail_if(uc_sat_subu64(a,b) != 0); + + a = 0; + b = 1; + fail_if(uc_sat_subu64(a,b) != 0); + + a = 1; + b = UINT64_MAX - 1; + fail_if(uc_sat_subu64(a,b) != 0); + + a = UINT64_MAX; + b = 100; + fail_if(uc_sat_subu64(a,b) != UINT64_MAX - 100); + + a = 100; + b = 100; + fail_if(uc_sat_subu64(a,b) != 0); +END_TEST + +START_TEST (test_sat_uc_multu64) + uint64_t a; + uint64_t b; + + a = UINT64_MAX; + b = 0; + fail_if(uc_sat_multu64(a,b) != 0); + + a = 0; + b = UINT64_MAX; + fail_if(uc_sat_multu64(a,b) != 0); + + a = UINT64_MAX; + b = UINT64_MAX; + fail_if(uc_sat_multu64(a,b) != UINT64_MAX); + + a = UINT64_MAX; + b = 2; + fail_if(uc_sat_multu64(a,b) != UINT64_MAX); + + a = 2; + b = UINT64_MAX; + fail_if(uc_sat_multu64(a,b) != UINT64_MAX); + + a = UINT64_MAX; + b = UINT64_MAX/2 - 1; + fail_if(uc_sat_multu64(a,b) != UINT64_MAX); + + a = UINT64_MAX/2 - 1; + b = UINT64_MAX; + fail_if(uc_sat_multu64(a,b) != UINT64_MAX); + + a = 10; + b = 10; + fail_if(uc_sat_multu64(a,b) != 100); + +END_TEST +Suite *sat_math_suite(void) +{ + Suite *s = suite_create("saturating_math"); + TCase *tc = tcase_create("saturating_math tests"); + + tcase_add_test(tc, test_sat_uc_addu8); + tcase_add_test(tc, test_sat_uc_subu8); + tcase_add_test(tc, test_sat_uc_multu8); + + tcase_add_test(tc, test_sat_uc_addu16); + tcase_add_test(tc, test_sat_uc_subu16); + tcase_add_test(tc, test_sat_uc_multu16); + + tcase_add_test(tc, test_sat_uc_addu32); + tcase_add_test(tc, test_sat_uc_subu32); + tcase_add_test(tc, test_sat_uc_multu32); + + tcase_add_test(tc, test_sat_uc_addu64); + tcase_add_test(tc, test_sat_uc_subu64); + tcase_add_test(tc, test_sat_uc_multu64); + + suite_add_tcase(s, tc); + + return s; +} +