aboutsummaryrefslogtreecommitdiffstats
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
parentlibj2_j2i_divmod_j2i_to_j2i: test overflow edge case (diff)
downloadlibj2-ac0dd6c546feaec1dec667f01616a2db709bedaf.tar.gz
libj2-ac0dd6c546feaec1dec667f01616a2db709bedaf.tar.bz2
libj2-ac0dd6c546feaec1dec667f01616a2db709bedaf.tar.xz
Add subtraction and addition with carry/borrow and add abs_diff1.2
Signed-off-by: Mattias Andrée <m@maandree.se>
-rw-r--r--Makefile19
-rw-r--r--README19
-rw-r--r--libj2.737
-rw-r--r--libj2/addition.h120
-rw-r--r--libj2/subtraction.h274
l---------libj2_j2i_abs_diff_j2i_to_j2u.31
-rw-r--r--libj2_j2i_abs_diff_j2i_to_j2u.c113
-rw-r--r--libj2_j2i_add_j2i.337
-rw-r--r--libj2_j2i_add_j2i.c207
l---------libj2_j2i_add_j2i_carry.31
-rw-r--r--libj2_j2i_add_j2i_carry.c12
l---------libj2_j2i_add_j2i_to_j2i_carry.31
-rw-r--r--libj2_j2i_add_j2i_to_j2i_carry.c12
l---------libj2_j2i_rsub_j2i_carry.31
-rw-r--r--libj2_j2i_rsub_j2i_carry.c12
-rw-r--r--libj2_j2i_sub_j2i.327
-rw-r--r--libj2_j2i_sub_j2i.c202
l---------libj2_j2i_sub_j2i_carry.31
-rw-r--r--libj2_j2i_sub_j2i_carry.c12
l---------libj2_j2i_sub_j2i_to_j2i_carry.31
-rw-r--r--libj2_j2i_sub_j2i_to_j2i_carry.c12
-rw-r--r--libj2_j2u_abs_diff_j2u.356
-rw-r--r--libj2_j2u_abs_diff_j2u.c12
l---------libj2_j2u_abs_diff_j2u_to_j2u.31
-rw-r--r--libj2_j2u_abs_diff_j2u_to_j2u.c118
-rw-r--r--libj2_j2u_add_j2u.c136
l---------libj2_j2u_add_j2u_carry.31
-rw-r--r--libj2_j2u_add_j2u_carry.c12
l---------libj2_j2u_add_j2u_to_j2u_carry.31
-rw-r--r--libj2_j2u_add_j2u_to_j2u_carry.c12
l---------libj2_j2u_rsub_j2u_borrow.31
-rw-r--r--libj2_j2u_rsub_j2u_borrow.c12
-rw-r--r--libj2_j2u_sub_j2u.326
-rw-r--r--libj2_j2u_sub_j2u.c160
l---------libj2_j2u_sub_j2u_borrow.31
-rw-r--r--libj2_j2u_sub_j2u_borrow.c12
l---------libj2_j2u_sub_j2u_to_j2u_borrow.31
-rw-r--r--libj2_j2u_sub_j2u_to_j2u_borrow.c12
l---------libj2_ji_abs_diff_ju_to_j2u.31
-rw-r--r--libj2_ji_abs_diff_ju_to_j2u.c89
l---------libj2_ju_abs_diff_ji_to_j2u.31
-rw-r--r--libj2_ju_abs_diff_ji_to_j2u.c89
42 files changed, 1868 insertions, 7 deletions
diff --git a/Makefile b/Makefile
index 46770a1..57a5be8 100644
--- a/Makefile
+++ b/Makefile
@@ -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\
diff --git a/README b/README
index 058794a..f54c47c 100644
--- a/README
+++ b/README
@@ -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),
diff --git a/libj2.7 b/libj2.7
index ae0cccc..2dfefee 100644
--- a/libj2.7
+++ b/libj2.7
@@ -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