aboutsummaryrefslogtreecommitdiffstats
path: root/libj2_j2i_add_j2i.c
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2026-02-12 13:45:48 +0100
committerMattias Andrée <m@maandree.se>2026-02-12 13:45:48 +0100
commit8b1e9c4dd1fd12e3b85750a5c0044b54ced216c7 (patch)
treefbf6b79555576e9005eeb84c0b605985a27fa714 /libj2_j2i_add_j2i.c
parentlibj2_j2i_divmod_j2i_to_j2i: test overflow edge case (diff)
downloadlibj2-1.2.tar.gz
libj2-1.2.tar.bz2
libj2-1.2.tar.xz
Add subtraction and addition with carry/borrow and add abs_diff1.2
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to '')
-rw-r--r--libj2_j2i_add_j2i.c207
1 files changed, 206 insertions, 1 deletions
diff --git a/libj2_j2i_add_j2i.c b/libj2_j2i_add_j2i.c
index 2d0acf5..f1b015b 100644
--- a/libj2_j2i_add_j2i.c
+++ b/libj2_j2i_add_j2i.c
@@ -23,12 +23,16 @@ static void
check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low,
uintmax_t r_high, uintmax_t r_low, int r_overflow)
{
- struct libj2_j2i a, b, r, a_saved, b_saved, expected;
+ struct libj2_j2i a, b, r, a_saved, b_saved, expected, expected_plus_one, expected_minus_one;
+ int carry;
a_saved = (struct libj2_j2i){.high = a_high, .low = a_low};
b_saved = (struct libj2_j2i){.high = b_high, .low = b_low};
expected = (struct libj2_j2i){.high = r_high, .low = r_low};
+ libj2_j2i_add_ji_to_j2i(&expected, +1, &expected_plus_one);
+ libj2_j2i_add_ji_to_j2i(&expected, -1, &expected_minus_one);
+
a = a_saved;
b = b_saved;
libj2_j2i_add_j2i(&a, &b);
@@ -116,6 +120,108 @@ check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low,
EXPECT(r_overflow > 0 ? libj2_j2i_is_max(&b) :
r_overflow ? libj2_j2i_is_min(&b) : libj2_j2i_eq_j2i(&b, &expected));
EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ carry = 0;
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_carry(&a, &b, &carry);
+ EXPECT(carry == r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ carry = 0;
+ r = (struct libj2_j2i){111, 222};
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &b, &r, &carry);
+ EXPECT(carry == r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ carry = 0;
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &b, &a, &carry);
+ EXPECT(carry == r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ carry = 0;
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &b, &b, &carry);
+ EXPECT(carry == r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&b, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ carry = +1;
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_carry(&a, &b, &carry);
+ EXPECT(carry >= r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected_plus_one));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ carry = +1;
+ r = (struct libj2_j2i){111, 222};
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &b, &r, &carry);
+ EXPECT(carry >= r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected_plus_one));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ carry = +1;
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &b, &a, &carry);
+ EXPECT(carry >= r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected_plus_one));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ carry = +1;
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &b, &b, &carry);
+ EXPECT(carry >= r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&b, &expected_plus_one));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ carry = -1;
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_carry(&a, &b, &carry);
+ EXPECT(carry <= r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected_minus_one));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ carry = -1;
+ r = (struct libj2_j2i){111, 222};
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &b, &r, &carry);
+ EXPECT(carry <= r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected_minus_one));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ carry = -1;
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &b, &a, &carry);
+ EXPECT(carry <= r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected_minus_one));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ carry = -1;
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &b, &b, &carry);
+ EXPECT(carry <= r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&b, &expected_minus_one));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
}
@@ -177,6 +283,8 @@ check_double(uintmax_t high, uintmax_t low)
uintmax_t expected_high = (high << 1 | low >> (LIBJ2_JU_BIT - 1U));
uintmax_t expected_low = low << 1;
int expected_overflow = (int)(high >> (LIBJ2_JU_BIT - 2U));
+ struct libj2_j2i expected_plus_one, expected_minus_one;
+ int carry;
expected_overflow ^= expected_overflow >> 1;
expected_overflow &= 1;
@@ -187,6 +295,9 @@ check_double(uintmax_t high, uintmax_t low)
a_saved = (struct libj2_j2i){.high = high, .low = low};
expected = (struct libj2_j2i){.high = expected_high, .low = expected_low};
+ libj2_j2i_add_ji_to_j2i(&expected, +1, &expected_plus_one);
+ libj2_j2i_add_ji_to_j2i(&expected, -1, &expected_minus_one);
+
a = a_saved;
b = a_saved;
libj2_j2i_add_j2i(&a, &b);
@@ -240,6 +351,66 @@ check_double(uintmax_t high, uintmax_t low)
libj2_j2i_sat_add_j2i_to_j2i(&a, &a, &a);
EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&a) :
expected_overflow ? libj2_j2i_is_min(&a) : libj2_j2i_eq_j2i(&a, &expected));
+
+ carry = 0;
+ a = a_saved;
+ libj2_j2i_add_j2i_carry(&a, &a, &carry);
+ EXPECT(carry == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected));
+
+ carry = 0;
+ r = (struct libj2_j2i){111, 222};
+ a = a_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &a, &r, &carry);
+ EXPECT(carry == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ carry = 0;
+ a = a_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &a, &a, &carry);
+ EXPECT(carry == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected));
+
+ carry = +1;
+ a = a_saved;
+ libj2_j2i_add_j2i_carry(&a, &a, &carry);
+ EXPECT(carry >= expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected_plus_one));
+
+ carry = +1;
+ r = (struct libj2_j2i){111, 222};
+ a = a_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &a, &r, &carry);
+ EXPECT(carry >= expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected_plus_one));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ carry = +1;
+ a = a_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &a, &a, &carry);
+ EXPECT(carry >= expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected_plus_one));
+
+ carry = -1;
+ a = a_saved;
+ libj2_j2i_add_j2i_carry(&a, &a, &carry);
+ EXPECT(carry <= expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected_minus_one));
+
+ carry = -1;
+ r = (struct libj2_j2i){111, 222};
+ a = a_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &a, &r, &carry);
+ EXPECT(carry <= expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected_minus_one));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ carry = -1;
+ a = a_saved;
+ libj2_j2i_add_j2i_to_j2i_carry(&a, &a, &a, &carry);
+ EXPECT(carry <= expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected_minus_one));
}
@@ -248,6 +419,8 @@ main(void)
{
uintmax_t a, b, c, d, max, min, umax, vs[12];
unsigned i, ii, ij, jj, k;
+ struct libj2_j2i u, v;
+ int carry;
srand((unsigned)time(NULL));
@@ -333,6 +506,38 @@ main(void)
}
}
+ carry = +1;
+ libj2_j2i_max(&u);
+ libj2_j2i_zero(&v);
+ libj2_j2i_add_j2i_to_j2i_carry(&u, &v, &u, &carry);
+ EXPECT(carry == +1);
+ EXPECT(libj2_j2i_is_min(&u));
+ EXPECT(libj2_j2i_is_zero(&v));
+
+ carry = +1;
+ libj2_j2i_max(&u);
+ libj2_j2i_zero(&v);
+ libj2_j2i_add_j2i_carry(&u, &v, &carry);
+ EXPECT(carry == +1);
+ EXPECT(libj2_j2i_is_min(&u));
+ EXPECT(libj2_j2i_is_zero(&v));
+
+ carry = -1;
+ libj2_j2i_min(&u);
+ libj2_j2i_zero(&v);
+ libj2_j2i_add_j2i_to_j2i_carry(&u, &v, &u, &carry);
+ EXPECT(carry == -1);
+ EXPECT(libj2_j2i_is_max(&u));
+ EXPECT(libj2_j2i_is_zero(&v));
+
+ carry = -1;
+ libj2_j2i_min(&u);
+ libj2_j2i_zero(&v);
+ libj2_j2i_add_j2i_carry(&u, &v, &carry);
+ EXPECT(carry == -1);
+ EXPECT(libj2_j2i_is_max(&u));
+ EXPECT(libj2_j2i_is_zero(&v));
+
return 0;
}