diff options
Diffstat (limited to '')
42 files changed, 1868 insertions, 7 deletions
@@ -11,7 +11,7 @@ include mk/$(OS).mk LIB_MAJOR = 1 -LIB_MINOR = 1 +LIB_MINOR = 2 LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR) LIB_NAME = j2 @@ -526,7 +526,22 @@ OBJ =\ libj2_j2i_sat_mul_j2i_to_j2i.o\ libj2_j2i_sat_mul_ji.o\ libj2_j2i_sat_mul_ji_to_j2i.o\ - libj2_ji_sat_mul_j2i_to_j2i.o + libj2_ji_sat_mul_j2i_to_j2i.o\ + libj2_j2u_add_j2u_to_j2u_carry.o\ + libj2_j2u_add_j2u_carry.o\ + libj2_j2i_add_j2i_to_j2i_carry.o\ + libj2_j2i_add_j2i_carry.o\ + libj2_j2u_sub_j2u_to_j2u_borrow.o\ + libj2_j2u_sub_j2u_borrow.o\ + libj2_j2u_rsub_j2u_borrow.o\ + libj2_j2i_sub_j2i_to_j2i_carry.o\ + libj2_j2i_sub_j2i_carry.o\ + libj2_j2i_rsub_j2i_carry.o\ + libj2_j2u_abs_diff_j2u_to_j2u.o\ + libj2_j2u_abs_diff_j2u.o\ + libj2_j2i_abs_diff_j2i_to_j2u.o\ + libj2_ji_abs_diff_ju_to_j2u.o\ + libj2_ju_abs_diff_ji_to_j2u.o SUBHDR =\ libj2/constants.h\ @@ -361,6 +361,10 @@ DESCRIPTION libj2_j2u_add_ju_overflow_p(3), libj2_ju_add_j2u_overflow_p(3) Predict whether adding two values will result in an overflow. + libj2_j2i_add_j2i_carry(3), libj2_j2i_add_j2i_to_j2i_carry(3), + libj2_j2u_add_j2u_carry(3), libj2_j2u_add_j2u_to_j2u_carry(3) + Calculate the sum of two values; with overflow carray-over. + libj2_j2i_sat_add_j2i(3), libj2_j2i_sat_add_j2i_to_j2i(3), libj2_j2i_sat_add_ji(3), libj2_j2i_sat_add_ji_to_j2i(3), libj2_ji_sat_add_j2i_to_j2i(3), libj2_j2u_sat_add_j2u(3), @@ -406,6 +410,16 @@ DESCRIPTION Predict whether subtracting a value will result in an overflow. These functions swap the position of the two operands. + libj2_j2i_sub_j2i_carry(3), libj2_j2i_sub_j2i_to_j2i_carry(3), + libj2_j2u_sub_j2u_borrow(3), libj2_j2u_sub_j2u_to_j2u_borrow(3) + Calculate the difference between two values; with + overflow carry-over. + + libj2_j2i_rsub_j2i_carry(3), libj2_j2u_rsub_j2u_borrow(3) + Calculate the difference between two values; with + overflow carry-over. These functions swap the position + of the two operands. + libj2_j2i_sat_sub_j2i(3), libj2_j2i_sat_sub_j2i_to_j2i(3), libj2_j2i_sat_sub_ji(3), libj2_j2i_sat_sub_ji_to_j2i(3), libj2_ji_sat_sub_j2i_to_j2i(3), libj2_j2u_sat_sub_j2u(3), @@ -420,6 +434,11 @@ DESCRIPTION Calculate the difference between two values, but saturate on overflow. These functions swap the position of the two operands. + libj2_j2i_abs_diff_j2i_to_j2u(3), libj2_j2u_abs_diff_j2u(3), + libj2_j2u_abs_diff_j2u_to_j2u(3), libj2_ju_abs_diff_ji_to_j2u(3), + libj2_ji_abs_diff_ju_to_j2u(3) + Calculate the absolute difference between two values. + libj2_j2i_mul_j2i(3), libj2_j2i_mul_j2i_to_j2i(3), libj2_j2i_mul_ji(3), libj2_j2i_mul_ji_to_j2i(3), libj2_ji_mul_j2i_to_j2i(3), libj2_ji_mul_ji_to_j2i(3), @@ -817,6 +817,15 @@ Calculate the sum of two values, and detect overflow. .BR libj2_ju_add_j2u_overflow_p (3) Predict whether adding two values will result in an overflow. .TP +.BR libj2_j2i_add_j2i_carry (3), +.TQ +.BR libj2_j2i_add_j2i_to_j2i_carry (3), +.TQ +.BR libj2_j2u_add_j2u_carry (3), +.TQ +.BR libj2_j2u_add_j2u_to_j2u_carry (3) +Calculate the sum of two values; with overflow carray-over. +.TP .BR libj2_j2i_sat_add_j2i (3), .TQ .BR libj2_j2i_sat_add_j2i_to_j2i (3), @@ -932,6 +941,23 @@ Predict whether subtracting a value will result in an overflow. Predict whether subtracting a value will result in an overflow. These functions swap the position of the two operands. .TP +.BR libj2_j2i_sub_j2i_carry (3), +.TQ +.BR libj2_j2i_sub_j2i_to_j2i_carry (3), +.TQ +.BR libj2_j2u_sub_j2u_borrow (3), +.TQ +.BR libj2_j2u_sub_j2u_to_j2u_borrow (3) +Calculate the difference between two values; with +overflow carry-over. +.TP +.BR libj2_j2i_rsub_j2i_carry (3), +.TQ +.BR libj2_j2u_rsub_j2u_borrow (3) +Calculate the difference between two values; with +overflow carry-over. These functions swap the position +of the two operands. +.TP .BR libj2_j2i_sat_sub_j2i (3), .TQ .BR libj2_j2i_sat_sub_j2i_to_j2i (3), @@ -966,6 +992,17 @@ overflow. Calculate the difference between two values, but saturate on overflow. These functions swap the position of the two operands. .TP +.BR libj2_j2i_abs_diff_j2i_to_j2u (3), +.TQ +.BR libj2_j2u_abs_diff_j2u (3), +.TQ +.BR libj2_j2u_abs_diff_j2u_to_j2u (3), +.TQ +.BR libj2_ju_abs_diff_ji_to_j2u (3), +.TQ +.BR libj2_ji_abs_diff_ju_to_j2u (3) +Calculate the absolute difference between two values. +.TP .BR libj2_j2i_mul_j2i (3), .TQ .BR libj2_j2i_mul_j2i_to_j2i (3), diff --git a/libj2/addition.h b/libj2/addition.h index de44e98..c45716e 100644 --- a/libj2/addition.h +++ b/libj2/addition.h @@ -777,3 +777,123 @@ libj2_ji_add_j2i_to_j2i_overflow(intmax_t a, const struct libj2_j2i *b, struct l { return libj2_j2i_add_ji_to_j2i_overflow(b, a, res); } + + + + + +/** + * Calculate the sum of two unsigned double-max + * precision integers and a carry flag, and + * update the carry flag + * + * `libj2_j2u_add_j2u_to_j2u_carry(a, b, res, &c)` + * imeplements `*res = *a + *b + *c` with + * overflow-detection + * + * @param a The augend + * @param b The addend + * @param res Output parameter for the sum + * @param carry Shall point to the value 1 or 0: + * the result will be incremented + * with the value. When the function + * returns, it will be updated to 1 + * on overflow, and 0 otherwise + * + * @since 1.2 + */ +inline void +libj2_j2u_add_j2u_to_j2u_carry(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res, int *carry) +{ + int overflow = libj2_j2u_add_j2u_to_j2u_overflow(a, b, res); + if (*carry) + overflow |= libj2_j2u_add_ju_overflow(res, 1u); + *carry = overflow; +} + + +/** + * Calculate the sum of two unsigned double-max + * precision integers and a carry flag, and + * update the carry flag + * + * `libj2_j2u_add_j2u_carry(a, b, &c)` + * imeplements `*a = *a + *b + *c` with + * overflow-detection + * + * @param a The augend, and output parameter for the sum + * @param b The addend + * @param carry Shall point to the value 1 or 0: + * the result will be incremented + * with the value. When the function + * returns, it will be updated to 1 + * on overflow, and 0 otherwise + * + * @since 1.2 + */ +inline void +libj2_j2u_add_j2u_carry(struct libj2_j2u *a, const struct libj2_j2u *b, int *carry) +{ + libj2_j2u_add_j2u_to_j2u_carry(a, b, a, carry); +} + + + + + +/** + * Calculate the sum of two signed double-max + * precision integers and a carry flag, and + * update the carry flag + * + * `libj2_j2i_add_j2i_to_j2i_carry(a, b, res, &c)` + * imeplements `*res = *a + *b + *c` with + * overflow-detection + * + * @param a The augend + * @param b The addend + * @param res Output parameter for the sum + * @param carry Shall point to the value +1, -1, or 0: + * the result will be incremented + * with the value. When the function + * returns, it will be updated to +1 + * on positive overflow, -1 on negative + * overflow, and 0 otherwise + * + * @since 1.2 + */ +inline void +libj2_j2i_add_j2i_to_j2i_carry(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res, int *carry) +{ + int overflow = libj2_j2i_add_j2i_to_j2i_overflow(a, b, res); + if (*carry) + overflow |= libj2_j2i_add_ji_overflow(res, *carry > 0 ? +1 : -1); + *carry = overflow; +} + + +/** + * Calculate the sum of two signed double-max + * precision integers and a carry flag, and + * update the carry flag + * + * `libj2_j2i_add_j2i_carry(a, b, &c)` + * imeplements `*a = *a + *b + *c` with + * overflow-detection + * + * @param a The augend, and output parameter for the sum + * @param b The addend + * @param carry Shall point to the value +1, -1, or 0: + * the result will be incremented + * with the value. When the function + * returns, it will be updated to +1 + * on positive overflow, -1 on negative + * overflow, and 0 otherwise + * + * @since 1.2 + */ +inline void +libj2_j2i_add_j2i_carry(struct libj2_j2i *a, const struct libj2_j2i *b, int *carry) +{ + libj2_j2i_add_j2i_to_j2i_carry(a, b, a, carry); +} diff --git a/libj2/subtraction.h b/libj2/subtraction.h index de4a225..c4291d1 100644 --- a/libj2/subtraction.h +++ b/libj2/subtraction.h @@ -1140,3 +1140,277 @@ libj2_j2i_rsub_ji_overflow_p(const struct libj2_j2i *a, intmax_t b) { return libj2_ji_sub_j2i_overflow_p(b, a); } + + + + + +/** + * Calculate the difference between two unsigned + * double-max precision integers + * + * `libj2_j2u_sub_j2u_to_j2u_borrow(a, b, res, borrow)` + * implements `*res = *a - *b - *borrow` with + * overflow detection + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @param res The output parameter for the difference + * @param borrow Shall point to the value 1 or 0: + * the result will be decremented + * with the value. When the function + * returns, it will be updated to 1 + * on overflow, and 0 otherwise + * + * @since 1.2 + */ +inline void +libj2_j2u_sub_j2u_to_j2u_borrow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res, int *borrow) +{ + int overflow = libj2_j2u_sub_j2u_to_j2u_overflow(a, b, res); + if (*borrow) + overflow |= libj2_j2u_sub_ju_overflow(res, 1u); + *borrow = overflow; +} + + +/** + * Calculate the difference between two unsigned + * double-max precision integers + * + * `libj2_j2u_sub_j2u_borrow(a, b, borrow)` + * implements `*a = *a - *b - *borrow` with + * overflow-detection + * + * @param a The minuend (left-hand), also used + * as the output parameter for the difference + * @param b The subtrahend (right-hand) + * @param borrow Shall point to the value 1 or 0: + * the result will be decremented + * with the value. When the function + * returns, it will be updated to 1 + * on overflow, and 0 otherwise + * + * @since 1.2 + */ +inline void +libj2_j2u_sub_j2u_borrow(struct libj2_j2u *a, const struct libj2_j2u *b, int *borrow) +{ + libj2_j2u_sub_j2u_to_j2u_borrow(a, b, a, borrow); +} + + +/** + * Calculate the difference between two unsigned + * double-max precision integers + * + * `libj2_j2u_rsub_j2u_borrow(a, b, borrow)` + * implements `*a = *b - *a - *borrow` with + * overflow-detection + * + * @param a The subtrahend (right-hand), also used + * as the output parameter for the difference + * @param b The minuend (left-hand) + * @param borrow Shall point to the value 1 or 0: + * the result will be decremented + * with the value. When the function + * returns, it will be updated to 1 + * on overflow, and 0 otherwise + * + * @since 1.2 + */ +inline void +libj2_j2u_rsub_j2u_borrow(struct libj2_j2u *a, const struct libj2_j2u *b, int *borrow) +{ + libj2_j2u_sub_j2u_to_j2u_borrow(b, a, a, borrow); +} + + + + + +/** + * Calculate the difference between two signed + * double-max precision integers + * + * `libj2_j2i_sub_j2i_to_j2i_borrow(a, b, res, carry)` + * implements `*res = *a - *b + *carry` with + * overflow-detection + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @param res The output parameter for the difference + * @param borrow Shall point to the value +1, -1, or 0: + * the result will be incremented + * with the value. When the function + * returns, it will be updated to +1 + * on positive overflow, -1 on negative + * overflow, and 0 otherwise + * + * @since 1.2 + */ +inline void +libj2_j2i_sub_j2i_to_j2i_carry(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res, int *carry) +{ + int overflow = libj2_j2i_sub_j2i_to_j2i_overflow(a, b, res); + if (*carry) + overflow |= libj2_j2i_add_ji_overflow(res, *carry > 0 ? +1 : -1); + *carry = overflow; +} + + +/** + * Calculate the difference between two signed + * double-max precision integers + * + * `libj2_j2i_sub_j2i_carry(a, b, carry)` + * implements `*a = *a - *b + *carry` with + * overflow-detection + * + * @param a The minuend (left-hand), also used + * as the output parameter for the difference + * @param b The subtrahend (right-hand) + * @param carry Shall point to the value +1, -1, or 0: + * the result will be incremented + * with the value. When the function + * returns, it will be updated to +1 + * on positive overflow, -1 on negative + * overflow, and 0 otherwise + * + * @since 1.2 + */ +inline void +libj2_j2i_sub_j2i_carry(struct libj2_j2i *a, const struct libj2_j2i *b, int *carry) +{ + libj2_j2i_sub_j2i_to_j2i_carry(a, b, a, carry); +} + + +/** + * Calculate the difference between two signed + * double-max precision integers + * + * `libj2_j2i_rsub_j2i_carry(a, b, carry)` + * implements `*a = *b - *a + *carry` with + * overflow-detection + * + * @param a The minuend (left-hand), also used + * as the output parameter for the difference + * @param b The subtrahend (right-hand) + * @param carry Shall point to the value +1, -1, or 0: + * the result will be incremented + * with the value. When the function + * returns, it will be updated to +1 + * on positive overflow, -1 on negative + * overflow, and 0 otherwise + * + * @since 1.2 + */ +inline void +libj2_j2i_rsub_j2i_carry(struct libj2_j2i *a, const struct libj2_j2i *b, int *carry) +{ + libj2_j2i_sub_j2i_to_j2i_carry(b, a, a, carry); +} + + + + + +/** + * Calculate the absolute difference between + * two unsigned double-max precision integers + * + * @param a One of the terms + * @param b The other term + * @param res The output parameter for the difference + * + * @since 1.2 + */ +inline void +libj2_j2u_abs_diff_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + if (libj2_j2u_ge_j2u(a, b)) + libj2_j2u_sub_j2u_to_j2u(a, b, res); + else + libj2_j2u_sub_j2u_to_j2u(b, a, res); +} + + +/** + * Calculate the absolute difference between + * two unsigned double-max precision integers + * + * @param a One of the terms, also used as the + * output parameter for the difference + * @param b The other term + * + * @since 1.2 + */ +inline void +libj2_j2u_abs_diff_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + if (libj2_j2u_ge_j2u(a, b)) + libj2_j2u_sub_j2u(a, b); + else + libj2_j2u_rsub_j2u(a, b); +} + + +/** + * Calculate the absolute difference between + * two signed double-max precision integers + * + * @param a One of the terms + * @param b The other term + * @param res The output parameter for the difference + * + * @since 1.2 + */ +inline void +libj2_j2i_abs_diff_j2i_to_j2u(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2u *res) +{ + if (libj2_j2i_ge_j2i(a, b)) + libj2_j2i_sub_j2i_to_j2i(a, b, (void *)res); + else + libj2_j2i_sub_j2i_to_j2i(b, a, (void *)res); +} + + +/** + * Calculate the absolute difference between + * a signed and an unsigned max precision integer + * + * @param a The signed term + * @param b The unsigned term + * @param res The output parameter for the difference + * + * @since 1.2 + */ +inline void +libj2_ji_abs_diff_ju_to_j2u(intmax_t a, uintmax_t b, struct libj2_j2u *res) +{ + struct libj2_j2i u, v; + libj2_ji_to_j2i(a, &u); + libj2_ju_to_j2i(b, &v); + libj2_j2i_abs_diff_j2i_to_j2u(&u, &v, res); +} + + +/** + * Calculate the absolute difference between + * an unsigned and a signed max precision integer + * + * @param a The unsigned term + * @param b The signed term + * @param res The output parameter for the difference + * + * @since 1.2 + */ +inline void +libj2_ju_abs_diff_ji_to_j2u(uintmax_t a, intmax_t b, struct libj2_j2u *res) +{ + struct libj2_j2i u, v; + libj2_ju_to_j2i(a, &u); + libj2_ji_to_j2i(b, &v); + libj2_j2i_abs_diff_j2i_to_j2u(&u, &v, res); +} diff --git a/libj2_j2i_abs_diff_j2i_to_j2u.3 b/libj2_j2i_abs_diff_j2i_to_j2u.3 new file mode 120000 index 0000000..88e97e0 --- /dev/null +++ b/libj2_j2i_abs_diff_j2i_to_j2u.3 @@ -0,0 +1 @@ +libj2_j2u_abs_diff_j2u.3
\ No newline at end of file diff --git a/libj2_j2i_abs_diff_j2i_to_j2u.c b/libj2_j2i_abs_diff_j2i_to_j2u.c new file mode 100644 index 0000000..bfa0851 --- /dev/null +++ b/libj2_j2i_abs_diff_j2i_to_j2u.c @@ -0,0 +1,113 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2i_abs_diff_j2i_to_j2u(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2u *res); + + +#else + +static uintmax_t +random_ju(void) +{ + size_t n = LIBJ2_JU_BIT; + uintmax_t r = 0; + while (n--) + if (rand() < rand()) + r |= (uintmax_t)1 << n; + return r; +} + + +static void +calc_expected(const struct libj2_j2i *large, const struct libj2_j2i *small, struct libj2_j2u *expected) +{ + struct libj2_j2u l, s; + struct libj2_j2i e; + + if (!libj2_j2i_is_negative(small)) { + libj2_j2i_sub_j2i_to_j2i(large, small, &e); + libj2_j2i_to_j2u(&e, expected); + } else if (!libj2_j2i_is_positive(large)) { + libj2_abs_j2i_to_j2u(large, &s); + libj2_abs_j2i_to_j2u(small, &l); + libj2_j2u_sub_j2u_to_j2u(&l, &s, expected); + } else { + libj2_j2i_to_j2u(large, expected); + libj2_abs_j2i_to_j2u(small, &s); + libj2_j2u_add_j2u(expected, &s); + } +} + + +static void +check(const struct libj2_j2i *a, const struct libj2_j2i *b) +{ + struct libj2_j2u r, expected; + struct libj2_j2i a_saved = *a, b_saved = *b; + + if (libj2_j2i_ge_j2i(a, b)) + calc_expected(a, b, &expected); + else + calc_expected(b, a, &expected); + + r = (struct libj2_j2u){111, 222}; + libj2_j2i_abs_diff_j2i_to_j2u(a, b, &r); + EXPECT(libj2_j2i_eq_j2i(a, &a_saved)); + EXPECT(libj2_j2i_eq_j2i(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2i_abs_diff_j2i_to_j2u(b, a, &r); + EXPECT(libj2_j2i_eq_j2i(a, &a_saved)); + EXPECT(libj2_j2i_eq_j2i(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2i_abs_diff_j2i_to_j2u(a, a, &r); + EXPECT(libj2_j2i_eq_j2i(a, &a_saved)); + EXPECT(libj2_j2u_is_zero(&r)); +} + + +int +main(void) +{ + struct libj2_j2i a, b; + uintmax_t u, v; + unsigned i; + + srand((unsigned)time(NULL)); + + for (i = 0; i < 256U; i++) { + a.high = random_ju(); + a.low = u = random_ju(); + b.high = random_ju(); + b.low = v = random_ju(); + check(&a, &b); + b.low = 0; + check(&a, &b); + a.low = 0; + check(&a, &b); + + b.high = 0; + a.low = u; + b.low = v; + check(&a, &b); + b.low = 0; + check(&a, &b); + a.low = 0; + check(&a, &b); + + a.high = 0; + a.low = u; + b.low = v; + check(&a, &b); + b.low = 0; + check(&a, &b); + } + + return 0; +} + +#endif diff --git a/libj2_j2i_add_j2i.3 b/libj2_j2i_add_j2i.3 index df0debd..b303be2 100644 --- a/libj2_j2i_add_j2i.3 +++ b/libj2_j2i_add_j2i.3 @@ -23,6 +23,9 @@ int \fBlibj2_j2i_add_j2i_overflow_p\fP(const struct libj2_j2i *\fIa\fP, const st int \fBlibj2_j2i_add_ji_overflow_p\fP(const struct libj2_j2i *\fIa\fP, intmax_t \fIb\fP); int \fBlibj2_ji_add_j2i_overflow_p\fP(intmax_t \fIa\fP, const struct libj2_j2i *\fIb\fP); +void \fBlibj2_j2i_add_j2i_carry\fP(struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP, int *\fIc\fP); +void \fBlibj2_j2i_add_j2i_to_j2i_carry\fP(const struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP, struct libj2_j2i *\fIr\fP, int *\fIc\fP); + void \fBlibj2_j2u_add_j2u\fP(struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP); void \fBlibj2_j2u_add_j2u_to_j2u\fP(const struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP, struct libj2_j2u *\fIr\fP); void \fBlibj2_j2u_add_ju\fP(struct libj2_j2u *\fIa\fP, uintmax_t \fIb\fP); @@ -40,6 +43,9 @@ int \fBlibj2_j2u_add_j2u_overflow_p\fP(const struct libj2_j2u *\fIa\fP, const st int \fBlibj2_j2u_add_ju_overflow_p\fP(const struct libj2_j2u *\fIa\fP, uintmax_t \fIb\fP); int \fBlibj2_ju_add_j2u_overflow_p\fP(uintmax_t \fIa\fP, const struct libj2_j2u *\fIb\fP); +void \fBlibj2_j2u_add_j2u_carry\fP(struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP, int *\fIc\fP); +void \fBlibj2_j2u_add_j2u_to_j2u_carry\fP(const struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP, struct libj2_j2i *\fIr\fP, int *\fIc\fP); + void \fBlibj2_j2i_sat_add_j2i\fP(struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP); void \fBlibj2_j2i_sat_add_j2i_to_j2i\fP(const struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP, struct libj2_j2i *\fIr\fP); void \fBlibj2_j2i_sat_add_ji\fP(struct libj2_j2i *\fIa\fP, intmax_t \fIb\fP); @@ -84,6 +90,28 @@ with word .B overflow in their name), detect arithmetic overflow. .PP +The +.BR libj2_j2i_add_j2i_carry () +and +.BR libj2_j2i_add_j2i_to_j2i_carry () +fuctions add +.IR *c , +which must be +1, -1, or 0, +to the result, and sets +.I *c +to +1 on positive overflow, +-1 on negative overflow, and 0 otherwise. +.PP +.BR libj2_j2u_add_j2u_carry () +and +.BR libj2_j2u_add_j2u_to_j2u_carry () +fuctions add +.IR *c , +which must be 1 or 0, +to the result, and sets +.IR *c +to 1 on overflow, and 0 otherwise. +.PP The result is truncated to the least significant bits, as many as can be stored, in case of overflow; that is, modular arithmetics is used. However, the @@ -155,6 +183,15 @@ and .BR libj2_ju_sat_add_j2u_to_j2u () functions were added in version 1.1 of .BR libj2 . +.PP +The +.BR libj2_j2i_add_j2i_carry (), +.BR libj2_j2i_add_j2i_to_j2i_carry (), +.BR libj2_j2u_add_j2u_carry (), +and +.BR libj2_j2u_add_j2u_to_j2u_carry () +functions were added in version 1.2 of +.BR libj2 . .SH SEE ALSO .BR libj2 (7), 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; } diff --git a/libj2_j2i_add_j2i_carry.3 b/libj2_j2i_add_j2i_carry.3 new file mode 120000 index 0000000..668244f --- /dev/null +++ b/libj2_j2i_add_j2i_carry.3 @@ -0,0 +1 @@ +libj2_j2i_add_j2i.3
\ No newline at end of file diff --git a/libj2_j2i_add_j2i_carry.c b/libj2_j2i_add_j2i_carry.c new file mode 100644 index 0000000..4628685 --- /dev/null +++ b/libj2_j2i_add_j2i_carry.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2i_add_j2i_carry(struct libj2_j2i *a, const struct libj2_j2i *b, int *carry); + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2i_add_j2i.c */ + +#endif diff --git a/libj2_j2i_add_j2i_to_j2i_carry.3 b/libj2_j2i_add_j2i_to_j2i_carry.3 new file mode 120000 index 0000000..abed8e1 --- /dev/null +++ b/libj2_j2i_add_j2i_to_j2i_carry.3 @@ -0,0 +1 @@ +libj2_j2i_add_j2i_carry.3
\ No newline at end of file diff --git a/libj2_j2i_add_j2i_to_j2i_carry.c b/libj2_j2i_add_j2i_to_j2i_carry.c new file mode 100644 index 0000000..fb64cc1 --- /dev/null +++ b/libj2_j2i_add_j2i_to_j2i_carry.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2i_add_j2i_to_j2i_carry(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res, int *carry); + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2i_add_j2i.c */ + +#endif diff --git a/libj2_j2i_rsub_j2i_carry.3 b/libj2_j2i_rsub_j2i_carry.3 new file mode 120000 index 0000000..1a29591 --- /dev/null +++ b/libj2_j2i_rsub_j2i_carry.3 @@ -0,0 +1 @@ +libj2_j2i_sub_j2i_carry.3
\ No newline at end of file diff --git a/libj2_j2i_rsub_j2i_carry.c b/libj2_j2i_rsub_j2i_carry.c new file mode 100644 index 0000000..e145abd --- /dev/null +++ b/libj2_j2i_rsub_j2i_carry.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2i_rsub_j2i_carry(struct libj2_j2i *a, const struct libj2_j2i *b, int *carry); + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_j2i.c */ + +#endif diff --git a/libj2_j2i_sub_j2i.3 b/libj2_j2i_sub_j2i.3 index c0b7a35..b49a0a2 100644 --- a/libj2_j2i_sub_j2i.3 +++ b/libj2_j2i_sub_j2i.3 @@ -23,6 +23,9 @@ int \fBlibj2_j2i_sub_j2i_overflow_p\fP(const struct libj2_j2i *\fIa\fP, const st int \fBlibj2_j2i_sub_ji_overflow_p\fP(const struct libj2_j2i *\fIa\fP, intmax_t \fIb\fP); int \fBlibj2_ji_sub_j2i_overflow_p\fP(intmax_t \fIa\fP, const struct libj2_j2i *\fIb\fP); +void \fBlibj2_j2i_sub_j2i_carry\fP(struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP, int *\fIc\fP); +void \fBlibj2_j2i_sub_j2i_to_j2i_carry\fP(const struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP, struct libj2_j2i *\fIr\fP, int *\fIc\fP); + void \fBlibj2_j2i_rsub_j2i\fP(struct libj2_j2i *\fIb\fP, const struct libj2_j2i *\fIa\fP); void \fBlibj2_j2i_rsub_ji\fP(struct libj2_j2i *\fIb\fP, intmax_t \fIa\fP); @@ -32,6 +35,8 @@ int \fBlibj2_j2i_rsub_ji_overflow\fP(struct libj2_j2i *\fIb\fP, intmax_t \fIa\fP int \fBlibj2_j2i_rsub_j2i_overflow_p\fP(const struct libj2_j2i *\fIb\fP, const struct libj2_j2i *\fIa\fP); int \fBlibj2_j2i_rsub_ji_overflow_p\fP(const struct libj2_j2i *\fIb\fP, intmax_t \fIa\fP); +void \fBlibj2_j2i_rsub_j2i_carry\fP(struct libj2_j2i *\fIb\fP, const struct libj2_j2i *\fIa\fP, int *\fIc\fP); + void \fBlibj2_j2i_sat_sub_j2i\fP(struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP); void \fBlibj2_j2i_sat_sub_j2i_to_j2i\fP(const struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP, struct libj2_j2i *\fIr\fP); void \fBlibj2_j2i_sat_sub_ji\fP(struct libj2_j2i *\fIa\fP, intmax_t \fIb\fP); @@ -84,6 +89,19 @@ with word .B overflow in their name), detect arithmetic overflow. .PP +The +.BR libj2_j2i_sub_j2i_carry (), +.BR libj2_j2i_sub_j2i_to_j2i_carry (), +and +.BR libj2_j2i_rsub_j2i_carry () +functions add +.IR *c , +which must be +1, -1, or 0, +to the result, and sets +.I *c +to +1 on positive overflow, +-1 on negative overflow, and 0 otherwise. +.PP The result is truncated to the least significant bits, as many as can be stored, in case of overflow; that is, modular arithmetics is used. However, the @@ -139,10 +157,19 @@ and .BR libj2_j2i_sat_rsub_ji () functions were added in version 1.1 of .BR libj2 . +.PP +The +.BR libj2_j2i_sub_j2i_carry (), +.BR libj2_j2i_sub_j2i_to_j2i_carry (), +and +.BR libj2_j2i_rsub_j2i_carry () +functions were added in version 1.2 of +.BR libj2 . .SH SEE ALSO .BR libj2 (7), .BR libj2_j2u_sub_j2u (3), +.BR libj2_j2u_abs_diff_j2u (3), .BR libj2_j2i_add_j2i (3), .BR libj2_j2i_mul_j2i (3), .BR libj2_j2i_divmod_j2i (3) diff --git a/libj2_j2i_sub_j2i.c b/libj2_j2i_sub_j2i.c index 78dea79..24610cd 100644 --- a/libj2_j2i_sub_j2i.c +++ b/libj2_j2i_sub_j2i.c @@ -79,7 +79,8 @@ static void check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low) { struct libj2_j2i a, a_saved, b, b_saved, r, expected; - int expected_overflow; + struct libj2_j2i expected_plus_one, expected_minus_one; + int expected_overflow, carry; a.high = a_high; a.low = a_low; @@ -98,6 +99,9 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low) validate(a.high, a.low, b.high, b.low, expected.high, expected.low, expected_overflow); + libj2_j2i_add_ji_to_j2i(&expected, +1, &expected_plus_one); + libj2_j2i_add_ji_to_j2i(&expected, -1, &expected_minus_one); + r = a; EXPECT(libj2_j2i_sub_j2i_to_j2i_overflow(CONST_ARG &r, CONST_ARG &b, &r) == expected_overflow); EXPECT(libj2_j2i_eq_j2i(&b, &b_saved)); @@ -226,6 +230,168 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low) r = a; libj2_j2i_rsub_j2i(&r, CONST_ARG &r); EXPECT(libj2_j2i_is_zero(&r)); + + carry = 0; + r = (struct libj2_j2i){111, 222}; + libj2_j2i_sub_j2i_to_j2i_carry(CONST_ARG &a, CONST_ARG &b, &r, &carry); + EXPECT(carry == expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&a, &a_saved)); + EXPECT(libj2_j2i_eq_j2i(&b, &b_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected)); + + carry = 0; + r = a; + libj2_j2i_sub_j2i_to_j2i_carry(CONST_ARG &r, CONST_ARG &b, &r, &carry); + EXPECT(carry == expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&b, &b_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected)); + + carry = 0; + r = b; + libj2_j2i_sub_j2i_to_j2i_carry(CONST_ARG &a, CONST_ARG &r, &r, &carry); + EXPECT(carry == expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&a, &a_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected)); + + carry = 0; + r = a; + libj2_j2i_sub_j2i_to_j2i_carry(CONST_ARG &r, CONST_ARG &r, &r, &carry); + EXPECT(carry == 0); + EXPECT(libj2_j2i_is_zero(&r)); + + carry = 0; + r = a; + libj2_j2i_sub_j2i_carry(&r, CONST_ARG &b, &carry); + EXPECT(carry == expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&b, &b_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected)); + + carry = 0; + r = a; + libj2_j2i_sub_j2i_carry(&r, CONST_ARG &r, &carry); + EXPECT(carry == 0); + EXPECT(libj2_j2i_is_zero(&r)); + + carry = 0; + r = b; + libj2_j2i_rsub_j2i_carry(&r, CONST_ARG &a, &carry); + EXPECT(carry == expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&a, &a_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected)); + + carry = 0; + r = a; + libj2_j2i_rsub_j2i_carry(&r, CONST_ARG &r, &carry); + EXPECT(carry == 0); + EXPECT(libj2_j2i_is_zero(&r)); + + carry = +1; + r = (struct libj2_j2i){111, 222}; + libj2_j2i_sub_j2i_to_j2i_carry(CONST_ARG &a, CONST_ARG &b, &r, &carry); + EXPECT(carry >= expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&a, &a_saved)); + EXPECT(libj2_j2i_eq_j2i(&b, &b_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected_plus_one)); + + carry = +1; + r = a; + libj2_j2i_sub_j2i_to_j2i_carry(CONST_ARG &r, CONST_ARG &b, &r, &carry); + EXPECT(carry >= expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&b, &b_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected_plus_one)); + + carry = +1; + r = b; + libj2_j2i_sub_j2i_to_j2i_carry(CONST_ARG &a, CONST_ARG &r, &r, &carry); + EXPECT(carry >= expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&a, &a_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected_plus_one)); + + carry = +1; + r = a; + libj2_j2i_sub_j2i_to_j2i_carry(CONST_ARG &r, CONST_ARG &r, &r, &carry); + EXPECT(carry >= 0); + EXPECT(libj2_j2i_eq_ji(&r, +1)); + + carry = +1; + r = a; + libj2_j2i_sub_j2i_carry(&r, CONST_ARG &b, &carry); + EXPECT(carry >= expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&b, &b_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected_plus_one)); + + carry = +1; + r = a; + libj2_j2i_sub_j2i_carry(&r, CONST_ARG &r, &carry); + EXPECT(carry >= 0); + EXPECT(libj2_j2i_eq_ji(&r, +1)); + + carry = +1; + r = b; + libj2_j2i_rsub_j2i_carry(&r, CONST_ARG &a, &carry); + EXPECT(carry >= expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&a, &a_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected_plus_one)); + + carry = +1; + r = a; + libj2_j2i_rsub_j2i_carry(&r, CONST_ARG &r, &carry); + EXPECT(carry >= 0); + EXPECT(libj2_j2i_eq_ji(&r, +1)); + + carry = -1; + r = (struct libj2_j2i){111, 222}; + libj2_j2i_sub_j2i_to_j2i_carry(CONST_ARG &a, CONST_ARG &b, &r, &carry); + EXPECT(carry <= expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&a, &a_saved)); + EXPECT(libj2_j2i_eq_j2i(&b, &b_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected_minus_one)); + + carry = -1; + r = a; + libj2_j2i_sub_j2i_to_j2i_carry(CONST_ARG &r, CONST_ARG &b, &r, &carry); + EXPECT(carry <= expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&b, &b_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected_minus_one)); + + carry = -1; + r = b; + libj2_j2i_sub_j2i_to_j2i_carry(CONST_ARG &a, CONST_ARG &r, &r, &carry); + EXPECT(carry <= expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&a, &a_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected_minus_one)); + + carry = -1; + r = a; + libj2_j2i_sub_j2i_to_j2i_carry(CONST_ARG &r, CONST_ARG &r, &r, &carry); + EXPECT(carry <= 0); + EXPECT(libj2_j2i_eq_ji(&r, -1)); + + carry = -1; + r = a; + libj2_j2i_sub_j2i_carry(&r, CONST_ARG &b, &carry); + EXPECT(carry <= expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&b, &b_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected_minus_one)); + + carry = -1; + r = a; + libj2_j2i_sub_j2i_carry(&r, CONST_ARG &r, &carry); + EXPECT(carry <= 0); + EXPECT(libj2_j2i_eq_ji(&r, -1)); + + carry = -1; + r = b; + libj2_j2i_rsub_j2i_carry(&r, CONST_ARG &a, &carry); + EXPECT(carry <= expected_overflow); + EXPECT(libj2_j2i_eq_j2i(&a, &a_saved)); + EXPECT(libj2_j2i_eq_j2i(&r, &expected_minus_one)); + + carry = -1; + r = a; + libj2_j2i_rsub_j2i_carry(&r, CONST_ARG &r, &carry); + EXPECT(carry <= 0); + EXPECT(libj2_j2i_eq_ji(&r, -1)); } @@ -234,6 +400,8 @@ main(void) { uintmax_t a, b, c, d, max, min, umax, vs[12]; unsigned i, ii, iii, iv, k, j; + struct libj2_j2i u, v; + int carry; srand((unsigned)time(NULL)); @@ -290,6 +458,38 @@ main(void) } } + carry = +1; + libj2_j2i_max(&u); + libj2_j2i_zero(&v); + libj2_j2i_sub_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_sub_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_sub_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_sub_j2i_carry(&u, &v, &carry); + EXPECT(carry == -1); + EXPECT(libj2_j2i_is_max(&u)); + EXPECT(libj2_j2i_is_zero(&v)); + return 0; } diff --git a/libj2_j2i_sub_j2i_carry.3 b/libj2_j2i_sub_j2i_carry.3 new file mode 120000 index 0000000..2bb1ba8 --- /dev/null +++ b/libj2_j2i_sub_j2i_carry.3 @@ -0,0 +1 @@ +libj2_j2i_sub_j2i.3
\ No newline at end of file diff --git a/libj2_j2i_sub_j2i_carry.c b/libj2_j2i_sub_j2i_carry.c new file mode 100644 index 0000000..854d4ac --- /dev/null +++ b/libj2_j2i_sub_j2i_carry.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2i_sub_j2i_carry(struct libj2_j2i *a, const struct libj2_j2i *b, int *carry); + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_j2i.c */ + +#endif diff --git a/libj2_j2i_sub_j2i_to_j2i_carry.3 b/libj2_j2i_sub_j2i_to_j2i_carry.3 new file mode 120000 index 0000000..1a29591 --- /dev/null +++ b/libj2_j2i_sub_j2i_to_j2i_carry.3 @@ -0,0 +1 @@ +libj2_j2i_sub_j2i_carry.3
\ No newline at end of file diff --git a/libj2_j2i_sub_j2i_to_j2i_carry.c b/libj2_j2i_sub_j2i_to_j2i_carry.c new file mode 100644 index 0000000..c38e734 --- /dev/null +++ b/libj2_j2i_sub_j2i_to_j2i_carry.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2i_sub_j2i_to_j2i_carry(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res, int *carry); + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_j2i.c */ + +#endif diff --git a/libj2_j2u_abs_diff_j2u.3 b/libj2_j2u_abs_diff_j2u.3 new file mode 100644 index 0000000..fe667cb --- /dev/null +++ b/libj2_j2u_abs_diff_j2u.3 @@ -0,0 +1,56 @@ +.TH LIBJ2_J2U_ABS_DIFF_J2U 3 LIBJ2 +.SH NAME +libj2_j2u_abs_diff_j2u \- Calculate absolute difference + +.SH SYNOPSIS +.nf +#include <libj2.h> + +void \fBlibj2_j2u_abs_diff_j2u\fP(struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP); +void \fBlibj2_j2u_abs_diff_j2u_to_j2u\fP(const struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP, struct libj2_j2u *\fIr\fP); +void \fBlibj2_j2i_abs_diff_j2i_to_j2u\fP(const struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP, struct libj2_j2u *\fIr\fP); +void \fBlibj2_ji_abs_diff_ju_to_j2u\fP(intmax_t \fIa\fP, uintmax_t \fIb\fP, struct libj2_j2u *\fIr\fP); +void \fBlibj2_ju_abs_diff_ji_to_j2u\fP(uintmax_t \fIa\fP, intmax_t \fIb\fP, struct libj2_j2u *\fIr\fP); +.fi +.PP +Link with +.IR -lj2 . + +.SH DESCRIPTION +The above listed functions calculate the +value absolute of the difference of the +values of +.I a +and +.I b +and stores the result in +.IR r , +except the +.BR libj2_j2u_abs_diff_j2u () +function, which stores the result in +.IR a . +.PP +The arguments are assumed to be +.RI non- NULL . + +.SH RETURN VALUE +None + +.SH ERRORS +The above listed functions cannot fail. + +.SH HISTORY +The +.BR libj2_j2u_abs_diff_j2u (), +.BR libj2_j2u_abs_diff_j2u_to_j2u (), +.BR libj2_j2i_abs_diff_j2i_to_j2u (), +.BR libj2_ju_abs_diff_ji_to_j2u (), +and +.BR libj2_ji_abs_diff_ju_to_j2u () +functions were added in version 1.2 of +.BR libj2 . + +.SH SEE ALSO +.BR libj2 (7), +.BR libj2_j2i_sub_j2i (3), +.BR libj2_j2u_sub_j2u (3) diff --git a/libj2_j2u_abs_diff_j2u.c b/libj2_j2u_abs_diff_j2u.c new file mode 100644 index 0000000..9c10016 --- /dev/null +++ b/libj2_j2u_abs_diff_j2u.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_abs_diff_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_abs_diff_j2u_to_j2u */ + +#endif diff --git a/libj2_j2u_abs_diff_j2u_to_j2u.3 b/libj2_j2u_abs_diff_j2u_to_j2u.3 new file mode 120000 index 0000000..88e97e0 --- /dev/null +++ b/libj2_j2u_abs_diff_j2u_to_j2u.3 @@ -0,0 +1 @@ +libj2_j2u_abs_diff_j2u.3
\ No newline at end of file diff --git a/libj2_j2u_abs_diff_j2u_to_j2u.c b/libj2_j2u_abs_diff_j2u_to_j2u.c new file mode 100644 index 0000000..6199e27 --- /dev/null +++ b/libj2_j2u_abs_diff_j2u_to_j2u.c @@ -0,0 +1,118 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_abs_diff_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); + + +#else + +static uintmax_t +random_ju(void) +{ + size_t n = LIBJ2_JU_BIT; + uintmax_t r = 0; + while (n--) + if (rand() < rand()) + r |= (uintmax_t)1 << n; + return r; +} + + +static void +check_(const struct libj2_j2u *a, const struct libj2_j2u *b, const struct libj2_j2u *expected) +{ + struct libj2_j2u r, a_saved = *a, b_saved = *b; + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_abs_diff_j2u_to_j2u(a, b, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_abs_diff_j2u_to_j2u(&r, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_j2u_abs_diff_j2u_to_j2u(a, &r, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_abs_diff_j2u(&r, b); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_abs_diff_j2u_to_j2u(a, a, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_is_zero(&r)); + + r = *a; + libj2_j2u_abs_diff_j2u_to_j2u(&r, &r, &r); + EXPECT(libj2_j2u_is_zero(&r)); + + r = *a; + libj2_j2u_abs_diff_j2u(&r, &r); + EXPECT(libj2_j2u_is_zero(&r)); +} + + +static void +check(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + struct libj2_j2u expected; + + if (libj2_j2u_ge_j2u(a, b)) + libj2_j2u_sub_j2u_to_j2u(a, b, &expected); + else + libj2_j2u_sub_j2u_to_j2u(b, a, &expected); + + check_(a, b, &expected); + check_(b, a, &expected); +} + + +int +main(void) +{ + struct libj2_j2u a, b; + uintmax_t u, v; + unsigned i; + + srand((unsigned)time(NULL)); + + for (i = 0; i < 256U; i++) { + a.high = random_ju(); + a.low = u = random_ju(); + b.high = random_ju(); + b.low = v = random_ju(); + check(&a, &b); + b.low = 0; + check(&a, &b); + a.low = 0; + check(&a, &b); + + b.high = 0; + a.low = u; + b.low = v; + check(&a, &b); + b.low = 0; + check(&a, &b); + a.low = 0; + check(&a, &b); + + a.high = 0; + a.low = u; + b.low = v; + check(&a, &b); + b.low = 0; + check(&a, &b); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_add_j2u.c b/libj2_j2u_add_j2u.c index 861e207..77c7504 100644 --- a/libj2_j2u_add_j2u.c +++ b/libj2_j2u_add_j2u.c @@ -23,12 +23,15 @@ 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_j2u a, b, r, a_saved, b_saved, expected; + struct libj2_j2u a, b, r, a_saved, b_saved, expected, expected_plus_one; + int carry; a_saved = (struct libj2_j2u){.high = a_high, .low = a_low}; b_saved = (struct libj2_j2u){.high = b_high, .low = b_low}; expected = (struct libj2_j2u){.high = r_high, .low = r_low}; + libj2_j2u_add_ju_to_j2u(&expected, 1U, &expected_plus_one); + a = a_saved; b = b_saved; libj2_j2u_add_j2u(&a, &b); @@ -112,6 +115,74 @@ check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low, libj2_j2u_sat_add_j2u_to_j2u(&a, &b, &b); EXPECT(r_overflow ? libj2_j2u_is_max(&b) : libj2_j2u_eq_j2u(&b, &expected)); EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + carry = 0; + a = a_saved; + b = b_saved; + libj2_j2u_add_j2u_carry(&a, &b, &carry); + EXPECT(carry == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + carry = 0; + r = (struct libj2_j2u){111, 222}; + a = a_saved; + b = b_saved; + libj2_j2u_add_j2u_to_j2u_carry(&a, &b, &r, &carry); + EXPECT(carry == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + carry = 0; + a = a_saved; + b = b_saved; + libj2_j2u_add_j2u_to_j2u_carry(&a, &b, &a, &carry); + EXPECT(carry == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + carry = 0; + a = a_saved; + b = b_saved; + libj2_j2u_add_j2u_to_j2u_carry(&a, &b, &b, &carry); + EXPECT(carry == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&b, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + carry = 1; + a = a_saved; + b = b_saved; + libj2_j2u_add_j2u_carry(&a, &b, &carry); + EXPECT(carry >= r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected_plus_one)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + carry = 1; + r = (struct libj2_j2u){111, 222}; + a = a_saved; + b = b_saved; + libj2_j2u_add_j2u_to_j2u_carry(&a, &b, &r, &carry); + EXPECT(carry >= r_overflow); + EXPECT(libj2_j2u_eq_j2u(&r, &expected_plus_one)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + carry = 1; + a = a_saved; + b = b_saved; + libj2_j2u_add_j2u_to_j2u_carry(&a, &b, &a, &carry); + EXPECT(carry >= r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected_plus_one)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + carry = 1; + a = a_saved; + b = b_saved; + libj2_j2u_add_j2u_to_j2u_carry(&a, &b, &b, &carry); + EXPECT(carry >= r_overflow); + EXPECT(libj2_j2u_eq_j2u(&b, &expected_plus_one)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); } @@ -153,14 +224,17 @@ check_manual(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_lo static void check_double(uintmax_t high, uintmax_t low) { - struct libj2_j2u a, r, a_saved, expected, b; + struct libj2_j2u a, r, a_saved, expected, expected_plus_one, b; uintmax_t expected_high = (high << 1 | low >> (LIBJ2_JU_BIT - 1U)); uintmax_t expected_low = low << 1; int expected_overflow = !!(high >> (LIBJ2_JU_BIT - 1U)); + int carry; a_saved = (struct libj2_j2u){.high = high, .low = low}; expected = (struct libj2_j2u){.high = expected_high, .low = expected_low}; + libj2_j2u_add_ju_to_j2u(&expected, 1U, &expected_plus_one); + a = a_saved; b = a_saved; libj2_j2u_add_j2u(&a, &b); @@ -211,6 +285,46 @@ check_double(uintmax_t high, uintmax_t low) a = a_saved; libj2_j2u_sat_add_j2u_to_j2u(&a, &a, &a); EXPECT(expected_overflow ? libj2_j2u_is_max(&a) : libj2_j2u_eq_j2u(&a, &expected)); + + carry = 0; + a = a_saved; + libj2_j2u_add_j2u_carry(&a, &a, &carry); + EXPECT(carry == expected_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + + carry = 0; + r = (struct libj2_j2u){111, 222}; + a = a_saved; + libj2_j2u_add_j2u_to_j2u_carry(&a, &a, &r, &carry); + EXPECT(carry == expected_overflow); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + carry = 0; + a = a_saved; + libj2_j2u_add_j2u_to_j2u_carry(&a, &a, &a, &carry); + EXPECT(carry == expected_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + + carry = 1; + a = a_saved; + libj2_j2u_add_j2u_carry(&a, &a, &carry); + EXPECT(carry >= expected_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected_plus_one)); + + carry = 1; + r = (struct libj2_j2u){111, 222}; + a = a_saved; + libj2_j2u_add_j2u_to_j2u_carry(&a, &a, &r, &carry); + EXPECT(carry >= expected_overflow); + EXPECT(libj2_j2u_eq_j2u(&r, &expected_plus_one)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + carry = 1; + a = a_saved; + libj2_j2u_add_j2u_to_j2u_carry(&a, &a, &a, &carry); + EXPECT(carry >= expected_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected_plus_one)); } @@ -218,6 +332,8 @@ int main(void) { unsigned i; + struct libj2_j2u a, b; + int carry; srand((unsigned)time(NULL)); @@ -246,6 +362,22 @@ main(void) check_manual(UINTMAX_MAX - 1U, UINTMAX_MAX - 1U, 1, 2, 0, 0, 1); check_manual(UINTMAX_MAX - 1U, UINTMAX_MAX - 1U, 1, 3, 0, 1, 1); + carry = 1; + libj2_j2u_max(&a); + libj2_j2u_zero(&b); + libj2_j2u_add_j2u_to_j2u_carry(&a, &b, &a, &carry); + EXPECT(carry == 1); + EXPECT(libj2_j2u_is_zero(&a)); + EXPECT(libj2_j2u_is_zero(&b)); + + carry = 1; + libj2_j2u_max(&a); + libj2_j2u_zero(&b); + libj2_j2u_add_j2u_carry(&a, &b, &carry); + EXPECT(carry == 1); + EXPECT(libj2_j2u_is_zero(&a)); + EXPECT(libj2_j2u_is_zero(&b)); + return 0; } diff --git a/libj2_j2u_add_j2u_carry.3 b/libj2_j2u_add_j2u_carry.3 new file mode 120000 index 0000000..abed8e1 --- /dev/null +++ b/libj2_j2u_add_j2u_carry.3 @@ -0,0 +1 @@ +libj2_j2i_add_j2i_carry.3
\ No newline at end of file diff --git a/libj2_j2u_add_j2u_carry.c b/libj2_j2u_add_j2u_carry.c new file mode 100644 index 0000000..ed79a36 --- /dev/null +++ b/libj2_j2u_add_j2u_carry.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_add_j2u_carry(struct libj2_j2u *a, const struct libj2_j2u *b, int *carry); + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_j2u.c */ + +#endif diff --git a/libj2_j2u_add_j2u_to_j2u_carry.3 b/libj2_j2u_add_j2u_to_j2u_carry.3 new file mode 120000 index 0000000..abed8e1 --- /dev/null +++ b/libj2_j2u_add_j2u_to_j2u_carry.3 @@ -0,0 +1 @@ +libj2_j2i_add_j2i_carry.3
\ No newline at end of file diff --git a/libj2_j2u_add_j2u_to_j2u_carry.c b/libj2_j2u_add_j2u_to_j2u_carry.c new file mode 100644 index 0000000..4618771 --- /dev/null +++ b/libj2_j2u_add_j2u_to_j2u_carry.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_add_j2u_to_j2u_carry(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res, int *carry); + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_j2u.c */ + +#endif diff --git a/libj2_j2u_rsub_j2u_borrow.3 b/libj2_j2u_rsub_j2u_borrow.3 new file mode 120000 index 0000000..99fc5d4 --- /dev/null +++ b/libj2_j2u_rsub_j2u_borrow.3 @@ -0,0 +1 @@ +libj2_j2u_sub_j2u_borrow.3
\ No newline at end of file diff --git a/libj2_j2u_rsub_j2u_borrow.c b/libj2_j2u_rsub_j2u_borrow.c new file mode 100644 index 0000000..d7e220b --- /dev/null +++ b/libj2_j2u_rsub_j2u_borrow.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_rsub_j2u_borrow(struct libj2_j2u *a, const struct libj2_j2u *b, int *borrow); + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */ + +#endif diff --git a/libj2_j2u_sub_j2u.3 b/libj2_j2u_sub_j2u.3 index cbadfd2..4ed6863 100644 --- a/libj2_j2u_sub_j2u.3 +++ b/libj2_j2u_sub_j2u.3 @@ -25,6 +25,9 @@ int \fBlibj2_j2u_sub_ju_overflow_p\fP(const struct libj2_j2u *\fIa\fP, uintmax_t int \fBlibj2_ju_sub_j2u_overflow_p\fP(uintmax_t \fIa\fP, const struct libj2_j2u *\fIb\fP); int \fBlibj2_ju_sub_ju_overflow_p\fP(uintmax_t \fIa\fP, uintmax_t \fIb\fP); +void \fBlibj2_j2u_sub_j2u_borrow\fP(struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP, int *\fIc\fP); +void \fBlibj2_j2u_sub_j2u_to_j2u_borrow\fP(const struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP, struct libj2_j2u *\fIr\fP, int *\fIc\fP); + void \fBlibj2_j2u_rsub_j2u\fP(struct libj2_j2u *\fIb\fP, const struct libj2_j2u *\fIa\fP); void \fBlibj2_j2u_rsub_ju\fP(struct libj2_j2u *\fIb\fP, uintmax_t \fIa\fP); @@ -34,6 +37,8 @@ int \fBlibj2_j2u_rsub_ju_overflow\fP(struct libj2_j2u *\fIb\fP, uintmax_t \fIa\f int \fBlibj2_j2u_rsub_j2u_overflow_p\fP(const struct libj2_j2u *\fIb\fP, const struct libj2_j2u *\fIa\fP); int \fBlibj2_j2u_rsub_ju_overflow_p\fP(const struct libj2_j2u *\fIb\fP, uintmax_t \fIa\fP); +void \fBlibj2_j2u_rsub_j2u_borrow\fP(struct libj2_j2u *\fIb\fP, const struct libj2_j2u *\fIa\fP, int *\fIc\fP); + void \fBlibj2_j2u_sat_sub_j2u\fP(struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP); void \fBlibj2_j2u_sat_sub_j2u_to_j2u\fP(const struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP, struct libj2_j2u *\fIr\fP); void \fBlibj2_j2u_sat_sub_ju\fP(struct libj2_j2u *\fIa\fP, uintmax_t \fIb\fP); @@ -88,6 +93,18 @@ with word .B overflow in their name), detect arithmetic overflow. .PP +The +.BR libj2_j2u_sub_j2u_borrow (), +.BR libj2_j2u_sub_j2u_to_j2u_borrow (), +and +.BR libj2_j2u_rsub_j2u_borrow () +functions subtract +.IR *c , +which must be 1 or 0, +from the result, and sets +.I *c +to 1 on overflow, and 0 otherwise. +.PP The result is truncated to the least significant bits, as many as can be stored, in case of overflow; that is, modular arithmetics is used. However, the @@ -149,6 +166,14 @@ and .BR libj2_j2u_sat_rsub_ju () functions were added in version 1.1 of .BR libj2 . +.PP +The +.BR libj2_j2u_sub_j2u_borrow (), +.BR libj2_j2u_sub_j2u_to_j2u_borrow (), +and +.BR libj2_j2u_rsub_j2u_borrow () +functions were added in version 1.2 of +.BR libj2 . .SH NOTES The return value 1 represents negative @@ -157,6 +182,7 @@ overflow. Positive overflow is impossible. .SH SEE ALSO .BR libj2 (7), .BR libj2_j2i_sub_j2i (3), +.BR libj2_j2u_abs_diff_j2u (3), .BR libj2_j2i_add_j2i (3), .BR libj2_j2i_mul_j2i (3), .BR libj2_j2i_divmod_j2i (3) diff --git a/libj2_j2u_sub_j2u.c b/libj2_j2u_sub_j2u.c index 288aa33..d2e65fd 100644 --- a/libj2_j2u_sub_j2u.c +++ b/libj2_j2u_sub_j2u.c @@ -23,12 +23,15 @@ 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_j2u a, b, r, a_saved, b_saved, expected; + struct libj2_j2u a, b, r, a_saved, b_saved, expected, expected_minus_one; + int borrow; a_saved = (struct libj2_j2u){.high = a_high, .low = a_low}; b_saved = (struct libj2_j2u){.high = b_high, .low = b_low}; expected = (struct libj2_j2u){.high = r_high, .low = r_low}; + libj2_j2u_sub_ju_to_j2u(&expected, 1, &expected_minus_one); + a = a_saved; b = b_saved; libj2_j2u_sub_j2u(&a, &b); @@ -136,6 +139,90 @@ check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low, EXPECT(libj2_j2u_rsub_j2u_overflow_p(&b, &a) == r_overflow); EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + borrow = 0; + a = a_saved; + b = b_saved; + libj2_j2u_sub_j2u_borrow(&a, &b, &borrow); + EXPECT(borrow == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + borrow = 0; + r = (struct libj2_j2u){111, 222}; + a = a_saved; + b = b_saved; + libj2_j2u_sub_j2u_to_j2u_borrow(&a, &b, &r, &borrow); + EXPECT(borrow == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + borrow = 0; + a = a_saved; + b = b_saved; + libj2_j2u_sub_j2u_to_j2u_borrow(&a, &b, &a, &borrow); + EXPECT(borrow == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + borrow = 0; + a = a_saved; + b = b_saved; + libj2_j2u_sub_j2u_to_j2u_borrow(&a, &b, &b, &borrow); + EXPECT(borrow == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&b, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + borrow = 0; + a = a_saved; + b = b_saved; + libj2_j2u_rsub_j2u_borrow(&b, &a, &borrow); + EXPECT(borrow == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&b, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + borrow = 1; + a = a_saved; + b = b_saved; + libj2_j2u_sub_j2u_borrow(&a, &b, &borrow); + EXPECT(borrow >= r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected_minus_one)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + borrow = 1; + r = (struct libj2_j2u){111, 222}; + a = a_saved; + b = b_saved; + libj2_j2u_sub_j2u_to_j2u_borrow(&a, &b, &r, &borrow); + EXPECT(borrow >= r_overflow); + EXPECT(libj2_j2u_eq_j2u(&r, &expected_minus_one)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + borrow = 1; + a = a_saved; + b = b_saved; + libj2_j2u_sub_j2u_to_j2u_borrow(&a, &b, &a, &borrow); + EXPECT(borrow >= r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected_minus_one)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + borrow = 1; + a = a_saved; + b = b_saved; + libj2_j2u_sub_j2u_to_j2u_borrow(&a, &b, &b, &borrow); + EXPECT(borrow >= r_overflow); + EXPECT(libj2_j2u_eq_j2u(&b, &expected_minus_one)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + borrow = 1; + a = a_saved; + b = b_saved; + libj2_j2u_rsub_j2u_borrow(&b, &a, &borrow); + EXPECT(borrow >= r_overflow); + EXPECT(libj2_j2u_eq_j2u(&b, &expected_minus_one)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); } @@ -170,6 +257,7 @@ static void check_double(uintmax_t high, uintmax_t low) { struct libj2_j2u a, a_saved, r; + int borrow; a_saved = (struct libj2_j2u){.high = high, .low = low}; @@ -234,6 +322,58 @@ check_double(uintmax_t high, uintmax_t low) a = a_saved; EXPECT(libj2_j2u_rsub_j2u_overflow_p((const struct libj2_j2u *)&a, (const struct libj2_j2u *)&a) == 0); EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + borrow = 0; + a = a_saved; + libj2_j2u_sub_j2u_borrow(&a, &a, &borrow); + EXPECT(borrow == 0); + EXPECT(libj2_j2u_is_zero(&a)); + + borrow = 0; + r = (struct libj2_j2u){111, 222}; + a = a_saved; + libj2_j2u_sub_j2u_to_j2u_borrow(&a, &a, &r, &borrow); + EXPECT(borrow == 0); + EXPECT(libj2_j2u_is_zero(&r)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + borrow = 0; + a = a_saved; + libj2_j2u_sub_j2u_to_j2u_borrow(&a, &a, &a, &borrow); + EXPECT(borrow == 0); + EXPECT(libj2_j2u_is_zero(&a)); + + borrow = 0; + a = a_saved; + libj2_j2u_rsub_j2u_borrow(&a, &a, &borrow); + EXPECT(borrow == 0); + EXPECT(libj2_j2u_is_zero(&a)); + + borrow = 1; + a = a_saved; + libj2_j2u_sub_j2u_borrow(&a, &a, &borrow); + EXPECT(borrow == 1); + EXPECT(libj2_j2u_is_max(&a)); + + borrow = 1; + r = (struct libj2_j2u){111, 222}; + a = a_saved; + libj2_j2u_sub_j2u_to_j2u_borrow(&a, &a, &r, &borrow); + EXPECT(borrow == 1); + EXPECT(libj2_j2u_is_max(&r)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + borrow = 1; + a = a_saved; + libj2_j2u_sub_j2u_to_j2u_borrow(&a, &a, &a, &borrow); + EXPECT(borrow == 1); + EXPECT(libj2_j2u_is_max(&a)); + + borrow = 1; + a = a_saved; + libj2_j2u_rsub_j2u_borrow(&a, &a, &borrow); + EXPECT(borrow == 1); + EXPECT(libj2_j2u_is_max(&a)); } @@ -241,6 +381,8 @@ int main(void) { unsigned i; + struct libj2_j2u a, b; + int borrow; srand((unsigned)time(NULL)); @@ -272,6 +414,22 @@ main(void) check_double(UINTMAX_MAX, random_ju()); } + borrow = 1; + libj2_j2u_min(&a); + libj2_j2u_zero(&b); + libj2_j2u_sub_j2u_to_j2u_borrow(&a, &b, &a, &borrow); + EXPECT(borrow == 1); + EXPECT(libj2_j2u_is_max(&a)); + EXPECT(libj2_j2u_is_zero(&b)); + + borrow = 1; + libj2_j2u_min(&a); + libj2_j2u_zero(&b); + libj2_j2u_sub_j2u_borrow(&a, &b, &borrow); + EXPECT(borrow == 1); + EXPECT(libj2_j2u_is_max(&a)); + EXPECT(libj2_j2u_is_zero(&b)); + return 0; } diff --git a/libj2_j2u_sub_j2u_borrow.3 b/libj2_j2u_sub_j2u_borrow.3 new file mode 120000 index 0000000..126e9a9 --- /dev/null +++ b/libj2_j2u_sub_j2u_borrow.3 @@ -0,0 +1 @@ +libj2_j2u_sub_j2u.3
\ No newline at end of file diff --git a/libj2_j2u_sub_j2u_borrow.c b/libj2_j2u_sub_j2u_borrow.c new file mode 100644 index 0000000..0b64f16 --- /dev/null +++ b/libj2_j2u_sub_j2u_borrow.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_sub_j2u_borrow(struct libj2_j2u *a, const struct libj2_j2u *b, int *borrow); + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */ + +#endif diff --git a/libj2_j2u_sub_j2u_to_j2u_borrow.3 b/libj2_j2u_sub_j2u_to_j2u_borrow.3 new file mode 120000 index 0000000..99fc5d4 --- /dev/null +++ b/libj2_j2u_sub_j2u_to_j2u_borrow.3 @@ -0,0 +1 @@ +libj2_j2u_sub_j2u_borrow.3
\ No newline at end of file diff --git a/libj2_j2u_sub_j2u_to_j2u_borrow.c b/libj2_j2u_sub_j2u_to_j2u_borrow.c new file mode 100644 index 0000000..35b3ed2 --- /dev/null +++ b/libj2_j2u_sub_j2u_to_j2u_borrow.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_sub_j2u_to_j2u_borrow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res, int *borrow); + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */ + +#endif diff --git a/libj2_ji_abs_diff_ju_to_j2u.3 b/libj2_ji_abs_diff_ju_to_j2u.3 new file mode 120000 index 0000000..88e97e0 --- /dev/null +++ b/libj2_ji_abs_diff_ju_to_j2u.3 @@ -0,0 +1 @@ +libj2_j2u_abs_diff_j2u.3
\ No newline at end of file diff --git a/libj2_ji_abs_diff_ju_to_j2u.c b/libj2_ji_abs_diff_ju_to_j2u.c new file mode 100644 index 0000000..d56b94b --- /dev/null +++ b/libj2_ji_abs_diff_ju_to_j2u.c @@ -0,0 +1,89 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ji_abs_diff_ju_to_j2u(intmax_t a, uintmax_t b, struct libj2_j2u *res); + + +#else + +static uintmax_t +random_ju(void) +{ + size_t n = LIBJ2_JU_BIT; + uintmax_t r = 0; + while (n--) + if (rand() < rand()) + r |= (uintmax_t)1 << n; + return r; +} + + +int +main(void) +{ + struct libj2_j2u r, expected; + uintmax_t a; + intmax_t b; + unsigned i; + + srand((unsigned)time(NULL)); + + r = (struct libj2_j2u){111, 222}; + libj2_ji_abs_diff_ju_to_j2u(0, 0, &r); + EXPECT(libj2_j2u_eq_ju(&r, 0)); + + r = (struct libj2_j2u){111, 222}; + libj2_ji_abs_diff_ju_to_j2u(0, UINTMAX_MAX, &r); + EXPECT(libj2_j2u_eq_ju(&r, UINTMAX_MAX)); + + r = (struct libj2_j2u){111, 222}; + libj2_ji_abs_diff_ju_to_j2u(INTMAX_MAX, 0, &r); + EXPECT(libj2_j2u_eq_ji(&r, INTMAX_MAX)); + + r = (struct libj2_j2u){111, 222}; + libj2_ji_abs_diff_ju_to_j2u(-INTMAX_MAX, 0, &r); + EXPECT(libj2_j2u_eq_ju(&r, INTMAX_MAX)); + + r = (struct libj2_j2u){111, 222}; + libj2_ji_abs_diff_ju_to_j2u(INTMAX_MAX, UINTMAX_MAX, &r); + EXPECT(libj2_j2u_eq_ju(&r, (uintmax_t)INTMAX_MAX + 1U)); + + r = (struct libj2_j2u){111, 222}; + libj2_ji_abs_diff_ju_to_j2u(-INTMAX_MAX, UINTMAX_MAX, &r); + libj2_ju_to_j2u(UINTMAX_MAX, &expected); + libj2_j2u_add_ju(&expected, (uintmax_t)INTMAX_MAX); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + for (i = 0; i < 256U; i++) { + a = random_ju(); + b = (intmax_t)(random_ju() >> 1); + + r = (struct libj2_j2u){111, 222}; + libj2_ji_abs_diff_ju_to_j2u(-b, a, &r); + libj2_ju_to_j2u(a, &expected); + libj2_j2u_add_ju(&expected, (uintmax_t)b); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_ji_abs_diff_ju_to_j2u(b, a, &r); + if ((uintmax_t)b < a) { + libj2_ju_to_j2u(a, &expected); + libj2_j2u_sub_ju(&expected, (uintmax_t)b); + } else { + libj2_ju_to_j2u((uintmax_t)b, &expected); + libj2_j2u_sub_ju(&expected, a); + } + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + if (a <= (uintmax_t)INTMAX_MAX) { + r = (struct libj2_j2u){111, 222}; + libj2_ji_abs_diff_ju_to_j2u((intmax_t)a, (uintmax_t)b, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + } + } + + return 0; +} + +#endif diff --git a/libj2_ju_abs_diff_ji_to_j2u.3 b/libj2_ju_abs_diff_ji_to_j2u.3 new file mode 120000 index 0000000..88e97e0 --- /dev/null +++ b/libj2_ju_abs_diff_ji_to_j2u.3 @@ -0,0 +1 @@ +libj2_j2u_abs_diff_j2u.3
\ No newline at end of file diff --git a/libj2_ju_abs_diff_ji_to_j2u.c b/libj2_ju_abs_diff_ji_to_j2u.c new file mode 100644 index 0000000..f3a2d50 --- /dev/null +++ b/libj2_ju_abs_diff_ji_to_j2u.c @@ -0,0 +1,89 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_abs_diff_ji_to_j2u(uintmax_t a, intmax_t b, struct libj2_j2u *res); + + +#else + +static uintmax_t +random_ju(void) +{ + size_t n = LIBJ2_JU_BIT; + uintmax_t r = 0; + while (n--) + if (rand() < rand()) + r |= (uintmax_t)1 << n; + return r; +} + + +int +main(void) +{ + struct libj2_j2u r, expected; + uintmax_t a; + intmax_t b; + unsigned i; + + srand((unsigned)time(NULL)); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_abs_diff_ji_to_j2u(0, 0, &r); + EXPECT(libj2_j2u_eq_ju(&r, 0)); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_abs_diff_ji_to_j2u(UINTMAX_MAX, 0, &r); + EXPECT(libj2_j2u_eq_ju(&r, UINTMAX_MAX)); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_abs_diff_ji_to_j2u(0, INTMAX_MAX, &r); + EXPECT(libj2_j2u_eq_ji(&r, INTMAX_MAX)); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_abs_diff_ji_to_j2u(0, -INTMAX_MAX, &r); + EXPECT(libj2_j2u_eq_ju(&r, INTMAX_MAX)); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_abs_diff_ji_to_j2u(UINTMAX_MAX, INTMAX_MAX, &r); + EXPECT(libj2_j2u_eq_ju(&r, (uintmax_t)INTMAX_MAX + 1U)); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_abs_diff_ji_to_j2u(UINTMAX_MAX, -INTMAX_MAX, &r); + libj2_ju_to_j2u(UINTMAX_MAX, &expected); + libj2_j2u_add_ju(&expected, (uintmax_t)INTMAX_MAX); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + for (i = 0; i < 256U; i++) { + a = random_ju(); + b = (intmax_t)(random_ju() >> 1); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_abs_diff_ji_to_j2u(a, -b, &r); + libj2_ju_to_j2u(a, &expected); + libj2_j2u_add_ju(&expected, (uintmax_t)b); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_abs_diff_ji_to_j2u(a, b, &r); + if ((uintmax_t)b < a) { + libj2_ju_to_j2u(a, &expected); + libj2_j2u_sub_ju(&expected, (uintmax_t)b); + } else { + libj2_ju_to_j2u((uintmax_t)b, &expected); + libj2_j2u_sub_ju(&expected, a); + } + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + if (a <= (uintmax_t)INTMAX_MAX) { + r = (struct libj2_j2u){111, 222}; + libj2_ju_abs_diff_ji_to_j2u((uintmax_t)b, (intmax_t)a, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + } + } + + return 0; +} + +#endif |
