diff options
| author | Mattias Andrée <m@maandree.se> | 2025-12-27 11:29:31 +0100 |
|---|---|---|
| committer | Mattias Andrée <m@maandree.se> | 2025-12-27 11:29:31 +0100 |
| commit | a72264006b738c8aa3d49d7835a86bcce130d20d (patch) | |
| tree | e29423bcaaa1341b19ce9febd3f8de9fc0f95983 /libj2_ji_add_ji_to_j2i.c | |
| parent | Fix libj2_j2u_add_j2u_overflow_p (diff) | |
| download | libj2-a72264006b738c8aa3d49d7835a86bcce130d20d.tar.gz libj2-a72264006b738c8aa3d49d7835a86bcce130d20d.tar.bz2 libj2-a72264006b738c8aa3d49d7835a86bcce130d20d.tar.xz | |
Add signed arithmetics
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to 'libj2_ji_add_ji_to_j2i.c')
| -rw-r--r-- | libj2_ji_add_ji_to_j2i.c | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/libj2_ji_add_ji_to_j2i.c b/libj2_ji_add_ji_to_j2i.c new file mode 100644 index 0000000..08bf2e1 --- /dev/null +++ b/libj2_ji_add_ji_to_j2i.c @@ -0,0 +1,153 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ji_add_ji_to_j2i(intmax_t a, intmax_t b, struct libj2_j2i *res); +/* TODO Add man page */ + + +#else + +static intmax_t +random_ji(void) +{ + size_t n = LIBJ2_JU_BIT - 1U; + intmax_t r = 0; + while (n--) + if (rand() < rand()) + r |= (intmax_t)1 << n; + if (rand() < rand()) { + r = -r; +#if INTMAX_MIN + 1 == -INTMAX_MAX + r -= 1; +#endif + } + return r; +} + + +static void +get_expected(intmax_t a, intmax_t b, uintmax_t *expected_high, uintmax_t *expected_low) +{ + uintmax_t pos, neg; + if (a >= 0 && b >= 0) { + *expected_high = 0; + *expected_low = (uintmax_t)a + (uintmax_t)b; + } else if (a <= 0 && b <= 0) { + *expected_high = UINTMAX_MAX; + *expected_low = (uintmax_t)a + (uintmax_t)b; + } else if (a < 0) { + pos = (uintmax_t)b; + neg = (uintmax_t)-(a + 1) + 1U; + goto pos_neg; + } else { + pos = (uintmax_t)a; + neg = (uintmax_t)-(b + 1) + 1U; + pos_neg: + if (pos >= neg) + *expected_high = 0; + else + *expected_high = UINTMAX_MAX; + *expected_low = pos - neg; + } +} + + +static void +check(intmax_t a, intmax_t b) +{ + struct libj2_j2i r; + uintmax_t expected_high, expected_low; + + get_expected(a, b, &expected_high, &expected_low); + + r = (struct libj2_j2i){111, 222}; + libj2_ji_add_ji_to_j2i(a, b, &r); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); + +#if INTMAX_MIN + 1 == -INTMAX_MAX + if (a == INTMAX_MIN || b == INTMAX_MIN) + return; +#endif + + r = (struct libj2_j2i){111, 222}; + libj2_ji_add_ji_to_j2i(-a, -b, &r); + libj2_minus_j2i(&r); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); +} + + +static void +check_manual(intmax_t a, intmax_t b, uintmax_t expected_high, uintmax_t expected_low) +{ + struct libj2_j2i r; + + r = (struct libj2_j2i){111, 222}; + libj2_ji_add_ji_to_j2i(a, b, &r); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); + +#if INTMAX_MIN + 1 == -INTMAX_MAX + if (a == INTMAX_MIN || b == INTMAX_MIN) + goto check; +#endif + + r = (struct libj2_j2i){111, 222}; + libj2_ji_add_ji_to_j2i(-a, -b, &r); + libj2_minus_j2i(&r); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); + +check: + check(a, b); +} + + +int +main(void) +{ + unsigned i; + + srand((unsigned)time(NULL)); + + check_manual(0, 0, 0, 0); + check_manual(0, INTMAX_MAX, 0, (uintmax_t)INTMAX_MAX); + check_manual(INTMAX_MAX, 0, 0, (uintmax_t)INTMAX_MAX); + check_manual(INTMAX_MAX, 1, 0, UINTMAX_MAX ^ (UINTMAX_MAX >> 1)); + check_manual(1, INTMAX_MAX, 0, UINTMAX_MAX ^ (UINTMAX_MAX >> 1)); + check_manual(INTMAX_MAX, INTMAX_MAX, 0, (uintmax_t)INTMAX_MAX << 1); + + check_manual(0, -INTMAX_MAX, UINTMAX_MAX, (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)) + 1U); + check_manual(-INTMAX_MAX, 0, UINTMAX_MAX, (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)) + 1U); + check_manual(INTMAX_MAX, -1, 0, (uintmax_t)INTMAX_MAX - 1U); + check_manual(-1, INTMAX_MAX, 0, (uintmax_t)INTMAX_MAX - 1U); + check_manual(-INTMAX_MAX, 1, UINTMAX_MAX, (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)) + 2U); + check_manual(1, -INTMAX_MAX, UINTMAX_MAX, (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)) + 2U); + check_manual(INTMAX_MAX, -INTMAX_MAX, 0, 0); + +#if INTMAX_MIN + 1 == -INTMAX_MAX + check_manual(0, INTMAX_MIN, UINTMAX_MAX, UINTMAX_MAX ^ (UINTMAX_MAX >> 1)); + check_manual(INTMAX_MIN, 0, UINTMAX_MAX, UINTMAX_MAX ^ (UINTMAX_MAX >> 1)); + check_manual(INTMAX_MIN, 1, UINTMAX_MAX, (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)) + 1U); + check_manual(1, INTMAX_MIN, UINTMAX_MAX, (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)) + 1U); + check_manual(INTMAX_MIN, INTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX); + check_manual(INTMAX_MIN, -INTMAX_MAX, UINTMAX_MAX, 1); + check_manual(INTMAX_MIN, INTMAX_MIN, UINTMAX_MAX, 0); +#endif + + for (i = 0; i < 256; i++) { + check(0, random_ji()); + check(1, random_ji()); + check(random_ji(), 0); + check(random_ji(), 1); + check(random_ji(), random_ji()); + check(random_ji(), INTMAX_MAX); + check(INTMAX_MAX, random_ji()); + } + + return 0; +} + +#endif |
