aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2025-12-27 11:29:31 +0100
committerMattias Andrée <m@maandree.se>2025-12-27 11:29:31 +0100
commita72264006b738c8aa3d49d7835a86bcce130d20d (patch)
treee29423bcaaa1341b19ce9febd3f8de9fc0f95983
parentFix libj2_j2u_add_j2u_overflow_p (diff)
downloadlibj2-a72264006b738c8aa3d49d7835a86bcce130d20d.tar.gz
libj2-a72264006b738c8aa3d49d7835a86bcce130d20d.tar.bz2
libj2-a72264006b738c8aa3d49d7835a86bcce130d20d.tar.xz
Add signed arithmetics
Signed-off-by: Mattias Andrée <m@maandree.se>
-rw-r--r--Makefile92
-rw-r--r--README78
-rw-r--r--common.h14
-rw-r--r--libj2.7162
-rw-r--r--libj2.h19
-rw-r--r--libj2/addition.h388
-rw-r--r--libj2/bit-shifting.h16
-rw-r--r--libj2/division.h758
-rw-r--r--libj2/multiplication.h597
-rw-r--r--libj2/subtraction.h515
-rw-r--r--libj2_j2i_add_j2i.c341
-rw-r--r--libj2_j2i_add_j2i_overflow.c13
-rw-r--r--libj2_j2i_add_j2i_overflow_p.c13
-rw-r--r--libj2_j2i_add_j2i_to_j2i.c13
-rw-r--r--libj2_j2i_add_j2i_to_j2i_overflow.c13
-rw-r--r--libj2_j2i_add_ji.c253
-rw-r--r--libj2_j2i_add_ji_overflow.c13
-rw-r--r--libj2_j2i_add_ji_overflow_p.c13
-rw-r--r--libj2_j2i_add_ji_to_j2i.c13
-rw-r--r--libj2_j2i_add_ji_to_j2i_overflow.c13
-rw-r--r--libj2_j2i_div_j2i.c13
-rw-r--r--libj2_j2i_div_j2i_return.c13
-rw-r--r--libj2_j2i_div_j2i_to_j2i.c13
-rw-r--r--libj2_j2i_div_j2i_to_j2i_underflow.c13
-rw-r--r--libj2_j2i_div_j2i_underflow.c13
-rw-r--r--libj2_j2i_div_ji.c13
-rw-r--r--libj2_j2i_div_ji_return.c13
-rw-r--r--libj2_j2i_div_ji_to_j2i.c13
-rw-r--r--libj2_j2i_div_ji_to_j2i_underflow.c13
-rw-r--r--libj2_j2i_div_ji_underflow.c13
-rw-r--r--libj2_j2i_divmod_j2i.c13
-rw-r--r--libj2_j2i_divmod_j2i_to_j2i.c459
-rw-r--r--libj2_j2i_divmod_j2i_to_j2i_j2i.c14
-rw-r--r--libj2_j2i_divmod_ji.c13
-rw-r--r--libj2_j2i_divmod_ji_to_j2i.c13
-rw-r--r--libj2_j2i_divmod_ji_to_j2i_j2i.c14
-rw-r--r--libj2_j2i_max.c2
-rw-r--r--libj2_j2i_min.c4
-rw-r--r--libj2_j2i_mod_j2i.c13
-rw-r--r--libj2_j2i_mod_j2i_to_j2i.c13
-rw-r--r--libj2_j2i_mod_ji.c13
-rw-r--r--libj2_j2i_mod_ji_to_j2i.c13
-rw-r--r--libj2_j2i_mul_j2i.c14
-rw-r--r--libj2_j2i_mul_j2i_overflow.c13
-rw-r--r--libj2_j2i_mul_j2i_overflow_p.c13
-rw-r--r--libj2_j2i_mul_j2i_overflow_p_quick.c13
-rw-r--r--libj2_j2i_mul_j2i_to_j2i.c13
-rw-r--r--libj2_j2i_mul_j2i_to_j2i_overflow.c13
-rw-r--r--libj2_j2i_mul_j2i_to_j2i_overflow_p.c13
-rw-r--r--libj2_j2i_mul_ji.c373
-rw-r--r--libj2_j2i_mul_ji_overflow.c13
-rw-r--r--libj2_j2i_mul_ji_overflow_p.c13
-rw-r--r--libj2_j2i_mul_ji_overflow_p_quick.c13
-rw-r--r--libj2_j2i_mul_ji_to_j2i.c13
-rw-r--r--libj2_j2i_mul_ji_to_j2i_overflow.c13
-rw-r--r--libj2_j2i_mul_ji_to_j2i_overflow_p.c13
-rw-r--r--libj2_j2i_rdiv_j2i.c13
-rw-r--r--libj2_j2i_rdiv_j2i_underflow.c13
-rw-r--r--libj2_j2i_rdivmod_j2i.c13
-rw-r--r--libj2_j2i_rdivmod_j2i_to_j2i.c13
-rw-r--r--libj2_j2i_rmod_j2i.c13
-rw-r--r--libj2_j2i_rsub_j2i.c13
-rw-r--r--libj2_j2i_rsub_j2i_overflow.c13
-rw-r--r--libj2_j2i_rsub_j2i_overflow_p.c13
-rw-r--r--libj2_j2i_rsub_ji.c13
-rw-r--r--libj2_j2i_rsub_ji_overflow.c13
-rw-r--r--libj2_j2i_rsub_ji_overflow_p.c13
-rw-r--r--libj2_j2i_sub_j2i.c244
-rw-r--r--libj2_j2i_sub_j2i_overflow.c13
-rw-r--r--libj2_j2i_sub_j2i_overflow_p.c13
-rw-r--r--libj2_j2i_sub_j2i_to_j2i.c13
-rw-r--r--libj2_j2i_sub_j2i_to_j2i_overflow.c13
-rw-r--r--libj2_j2i_sub_ji.c201
-rw-r--r--libj2_j2i_sub_ji_overflow.c13
-rw-r--r--libj2_j2i_sub_ji_overflow_p.c13
-rw-r--r--libj2_j2i_sub_ji_to_j2i.c13
-rw-r--r--libj2_j2i_sub_ji_to_j2i_overflow.c13
-rw-r--r--libj2_ji_add_j2i_overflow_p.c13
-rw-r--r--libj2_ji_add_j2i_to_j2i.c13
-rw-r--r--libj2_ji_add_j2i_to_j2i_overflow.c13
-rw-r--r--libj2_ji_add_ji_to_j2i.c153
-rw-r--r--libj2_ji_mul_j2i_overflow_p.c13
-rw-r--r--libj2_ji_mul_j2i_overflow_p_quick.c13
-rw-r--r--libj2_ji_mul_j2i_to_j2i.c13
-rw-r--r--libj2_ji_mul_j2i_to_j2i_overflow.c13
-rw-r--r--libj2_ji_mul_j2i_to_j2i_overflow_p.c13
-rw-r--r--libj2_ji_mul_ji_to_j2i.c221
-rw-r--r--libj2_ji_sub_j2i_overflow_p.c13
-rw-r--r--libj2_ji_sub_j2i_to_j2i.c13
-rw-r--r--libj2_ji_sub_j2i_to_j2i_overflow.c13
-rw-r--r--libj2_ji_sub_ji_to_j2i.c94
-rw-r--r--libj2_ju_mul_ju_to_j2u.c5
-rw-r--r--libj2_minus_j2i.c2
-rw-r--r--libj2_vmax_j2i_to_j2i.c2
-rw-r--r--libj2_vmax_j2u_to_j2u.c2
-rw-r--r--libj2_vmin_j2i_to_j2i.c2
-rw-r--r--libj2_vmin_j2u_to_j2u.c2
97 files changed, 5811 insertions, 101 deletions
diff --git a/Makefile b/Makefile
index 5e847bd..6969060 100644
--- a/Makefile
+++ b/Makefile
@@ -386,13 +386,11 @@ OBJ =\
libj2_max_j2i.o\
libj2_vmin_j2i.o\
libj2_min_j2i.o\
- libj2_vmax_j2i_to_j2i.o\
libj2_max_j2i_to_j2i.o\
libj2_min_j2i_to_j2i.o\
libj2_vmin_j2i_to_j2i.o\
libj2_vmin_j2i_return.o\
libj2_min_j2i_return.o\
- libj2_max_j2i_to_j2i.o\
libj2_vmax_j2i_to_j2i.o\
libj2_vmax_j2i_return.o\
libj2_max_j2i_return.o\
@@ -429,7 +427,86 @@ OBJ =\
libj2_j2i_lsh_overflow_p.o\
libj2_ji_lsh_overflow_p.o\
libj2_j2i_rsh_underflow_p.o\
- libj2_ji_rsh_underflow_p.o
+ libj2_ji_rsh_underflow_p.o\
+ libj2_j2i_add_j2i.o\
+ libj2_j2i_add_j2i_overflow.o\
+ libj2_j2i_add_j2i_overflow_p.o\
+ libj2_j2i_add_j2i_to_j2i.o\
+ libj2_j2i_add_j2i_to_j2i_overflow.o\
+ libj2_j2i_add_ji.o\
+ libj2_j2i_add_ji_overflow.o\
+ libj2_j2i_add_ji_overflow_p.o\
+ libj2_j2i_add_ji_to_j2i.o\
+ libj2_j2i_add_ji_to_j2i_overflow.o\
+ libj2_ji_add_j2i_overflow_p.o\
+ libj2_ji_add_j2i_to_j2i.o\
+ libj2_ji_add_j2i_to_j2i_overflow.o\
+ libj2_ji_add_ji_to_j2i.o\
+ libj2_j2i_rsub_j2i.o\
+ libj2_j2i_rsub_j2i_overflow.o\
+ libj2_j2i_rsub_j2i_overflow_p.o\
+ libj2_j2i_rsub_ji.o\
+ libj2_j2i_rsub_ji_overflow.o\
+ libj2_j2i_rsub_ji_overflow_p.o\
+ libj2_j2i_sub_j2i.o\
+ libj2_j2i_sub_j2i_overflow.o\
+ libj2_j2i_sub_j2i_overflow_p.o\
+ libj2_j2i_sub_j2i_to_j2i.o\
+ libj2_j2i_sub_j2i_to_j2i_overflow.o\
+ libj2_j2i_sub_ji.o\
+ libj2_j2i_sub_ji_overflow.o\
+ libj2_j2i_sub_ji_overflow_p.o\
+ libj2_j2i_sub_ji_to_j2i.o\
+ libj2_j2i_sub_ji_to_j2i_overflow.o\
+ libj2_ji_sub_j2i_overflow_p.o\
+ libj2_ji_sub_j2i_to_j2i.o\
+ libj2_ji_sub_j2i_to_j2i_overflow.o\
+ libj2_ji_sub_ji_to_j2i.o\
+ libj2_j2i_mul_j2i.o\
+ libj2_j2i_mul_j2i_overflow.o\
+ libj2_j2i_mul_j2i_overflow_p.o\
+ libj2_j2i_mul_j2i_overflow_p_quick.o\
+ libj2_j2i_mul_j2i_to_j2i.o\
+ libj2_j2i_mul_j2i_to_j2i_overflow.o\
+ libj2_j2i_mul_j2i_to_j2i_overflow_p.o\
+ libj2_j2i_mul_ji.o\
+ libj2_j2i_mul_ji_overflow.o\
+ libj2_j2i_mul_ji_overflow_p.o\
+ libj2_j2i_mul_ji_overflow_p_quick.o\
+ libj2_j2i_mul_ji_to_j2i.o\
+ libj2_j2i_mul_ji_to_j2i_overflow.o\
+ libj2_j2i_mul_ji_to_j2i_overflow_p.o\
+ libj2_ji_mul_j2i_overflow_p.o\
+ libj2_ji_mul_j2i_overflow_p_quick.o\
+ libj2_ji_mul_j2i_to_j2i.o\
+ libj2_ji_mul_j2i_to_j2i_overflow.o\
+ libj2_ji_mul_j2i_to_j2i_overflow_p.o\
+ libj2_ji_mul_ji_to_j2i.o\
+ libj2_j2i_div_j2i.o\
+ libj2_j2i_div_j2i_return.o\
+ libj2_j2i_div_j2i_to_j2i.o\
+ libj2_j2i_div_j2i_to_j2i_underflow.o\
+ libj2_j2i_div_j2i_underflow.o\
+ libj2_j2i_div_ji.o\
+ libj2_j2i_div_ji_return.o\
+ libj2_j2i_div_ji_to_j2i.o\
+ libj2_j2i_div_ji_to_j2i_underflow.o\
+ libj2_j2i_div_ji_underflow.o\
+ libj2_j2i_divmod_j2i.o\
+ libj2_j2i_divmod_j2i_to_j2i.o\
+ libj2_j2i_divmod_j2i_to_j2i_j2i.o\
+ libj2_j2i_divmod_ji.o\
+ libj2_j2i_divmod_ji_to_j2i.o\
+ libj2_j2i_divmod_ji_to_j2i_j2i.o\
+ libj2_j2i_mod_j2i.o\
+ libj2_j2i_mod_j2i_to_j2i.o\
+ libj2_j2i_mod_ji.o\
+ libj2_j2i_mod_ji_to_j2i.o\
+ libj2_j2i_rdiv_j2i.o\
+ libj2_j2i_rdiv_j2i_underflow.o\
+ libj2_j2i_rdivmod_j2i.o\
+ libj2_j2i_rdivmod_j2i_to_j2i.o\
+ libj2_j2i_rmod_j2i.o
SUBHDR =\
libj2/constants.h\
@@ -516,6 +593,13 @@ check: $(TEST)
$(CHECK_PREFIX) ./"$$t";\
done
+makefile-check:
+ grep '\.o\\\{0,1\}$$' < Makefile |\
+ sed 's/^'"$$(printf '\t')"'//' |\
+ sed 's/\.o\\\{0,1\}$$/\.c/' |\
+ sort |\
+ diff -u <(printf '%s\n' *.c | sort) -
+
install: libj2.a libj2.$(LIBEXT)
mkdir -p -- "$(DESTDIR)$(PREFIX)/lib"
mkdir -p -- "$(DESTDIR)$(PREFIX)/include/libj2"
@@ -553,4 +637,4 @@ clean:
.SUFFIXES:
.SUFFIXES: .lo .o .c .to .t
-.PHONY: all install uninstall clean
+.PHONY: all check release-check install uninstall clean
diff --git a/README b/README
index b00910b..c55ef0a 100644
--- a/README
+++ b/README
@@ -340,18 +340,24 @@ DESCRIPTION
libj2 provides the following arithmetic functions:
+ libj2_j2i_add_j2i(3), libj2_j2i_add_j2i_to_j2i(3),
+ libj2_j2i_add_ji(3), libj2_j2i_add_ji_to_j2ui3),
+ libj2_ji_add_j2i_to_j2i(3), libj2_ji_add_ji_to_j2i(3),
libj2_j2u_add_j2u(3), libj2_j2u_add_j2u_to_j2u(3),
libj2_j2u_add_ju(3), libj2_j2u_add_ju_to_j2u(3),
libj2_ju_add_j2u_to_j2u(3), libj2_ju_add_ju_to_j2u(3)
Calculate the sum of two values.
- libj2_j2u_add_j2u_overflow(3), libj2_j2u_add_j2u_to_j2u_overflow(3),
- libj2_j2u_add_ju_overflow(3), libj2_j2u_add_ju_to_j2u_overflow(3),
- libj2_ju_add_j2u_to_j2u_overflow(3)
+ libj2_j2i_add_j2i_overflow(3), libj2_j2i_add_j2i_to_j2i_overflow(3),
+ libj2_j2i_add_ji_overflow(3), libj2_j2i_add_ji_to_j2i_overflow(3),
+ libj2_ji_add_j2i_to_j2i_overflow(3), libj2_j2u_add_j2u_overflow(3),
+ libj2_j2u_add_j2u_to_j2u_overflow(3), libj2_j2u_add_ju_overflow(3),
+ libj2_j2u_add_ju_to_j2u_overflow(3), libj2_ju_add_j2u_to_j2u_overflow(3)
Calculate the sum of two values, and detect overflow.
- libj2_j2u_add_j2u_overflow_p(3), libj2_j2u_add_ju_overflow_p(3),
- libj2_ju_add_j2u_overflow_p(3)
+ libj2_j2i_add_j2i_overflow_p(3), libj2_j2i_add_ji_overflow_p(3),
+ libj2_ji_add_j2i_overflow_p(3), libj2_j2u_add_j2u_overflow_p(3),
+ 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_j2u_sat_add_j2u(3), libj2_j2u_sat_add_j2u_to_j2u(3),
@@ -359,29 +365,40 @@ DESCRIPTION
libj2_ju_sat_add_j2u_to_j2u(3)
Calculate the sum of two values, but saturate on overflow.
+ libj2_j2i_sub_j2i(3), libj2_j2i_sub_j2i_to_j2i(3),
+ libj2_j2i_sub_ji(3), libj2_j2i_sub_ji_to_j2i(3),
+ libj2_ji_sub_j2i_to_j2i(3), libj2_ji_sub_ji_to_j2i(3),
libj2_j2u_sub_j2u(3), libj2_j2u_sub_j2u_to_j2u(3),
libj2_j2u_sub_ju(3), libj2_j2u_sub_ju_to_j2u(3),
libj2_ju_sub_j2u_to_j2u(3), libj2_ju_sub_ju_to_j2u(3)
Calculate the difference between two values.
+ libj2_j2i_rsub_j2i(3), libj2_j2i_rsub_ji(3),
libj2_j2u_rsub_j2u(3), libj2_j2u_rsub_ju(3)
Calculate the difference between two values. These functions
swap the position of the two operands.
- libj2_j2u_sub_j2u_overflow(3), libj2_j2u_sub_j2u_to_j2u_overflow(3),
- libj2_j2u_sub_ju_overflow(3), libj2_j2u_sub_ju_to_j2u_overflow(3),
- libj2_ju_sub_j2u_to_j2u_overflow(3), libj2_ju_sub_ju_to_j2u_overflow(3)
+ libj2_j2i_sub_j2i_overflow(3), libj2_j2i_sub_j2i_to_j2i_overflow(3),
+ libj2_j2i_sub_ji_overflow(3), libj2_j2i_sub_ji_to_j2i_overflow(3),
+ libj2_ji_sub_j2i_to_j2i_overflow(3), libj2_j2u_sub_j2u_overflow(3),
+ libj2_j2u_sub_j2u_to_j2u_overflow(3), libj2_j2u_sub_ju_overflow(3),
+ libj2_j2u_sub_ju_to_j2u_overflow(3), libj2_ju_sub_j2u_to_j2u_overflow(3),
+ libj2_ju_sub_ju_to_j2u_overflow(3)
Calculate the difference between two values, and detect
overflow.
+ libj2_j2i_rsub_j2i_overflow(3), libj2_j2i_rsub_ji_overflow(3),
libj2_j2u_rsub_j2u_overflow(3), libj2_j2u_rsub_ju_overflow(3)
Calculate the difference between two values, and detect
overflow. These functions swap the position of the two operands.
- libj2_j2u_sub_j2u_overflow_p(3), libj2_j2u_sub_ju_overflow_p(3),
- libj2_ju_sub_j2u_overflow_p(3), libj2_ju_sub_ju_overflow_p(3)
+ libj2_j2i_sub_j2i_overflow_p(3), libj2_j2i_sub_ji_overflow_p(3),
+ libj2_ji_sub_j2i_overflow_p(3), libj2_j2u_sub_j2u_overflow_p(3),
+ libj2_j2u_sub_ju_overflow_p(3), libj2_ju_sub_j2u_overflow_p(3),
+ libj2_ju_sub_ju_overflow_p(3)
Predict whether subtracting a value will result in an overflow.
+ libj2_j2i_rsub_j2i_overflow_p(3), libj2_j2i_rsub_ji_overflow_p(3),
libj2_j2u_rsub_j2u_overflow_p(3), libj2_j2u_rsub_ju_overflow_p(3)
Predict whether subtracting a value will result in an overflow.
These functions swap the position of the two operands.
@@ -396,29 +413,41 @@ DESCRIPTION
Calculate the difference between two values, but saturate on
overflow. These functions swap the position of the two operands.
+ 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),
libj2_j2u_mul_j2u(3), libj2_j2u_mul_j2u_to_j2u(3),
libj2_j2u_mul_ju(3), libj2_j2u_mul_ju_to_j2u(3),
libj2_ju_mul_j2u_to_j2u(3), libj2_ju_mul_ju_to_j2u(3),
libj2_j2u_mul_j2u_destructive(3)
Calculate the product of two values.
- libj2_j2u_mul_j2u_overflow(3), libj2_j2u_mul_j2u_to_j2u_overflow(3),
- libj2_j2u_mul_ju_overflow(3), libj2_j2u_mul_ju_to_j2u_overflow(3),
- libj2_ju_mul_j2u_to_j2u_overflow(3),
+ libj2_j2i_mul_j2i_overflow(3), libj2_j2i_mul_j2i_to_j2i_overflow(3),
+ libj2_j2i_mul_ji_overflow(3), libj2_j2i_mul_ji_to_j2i_overflow(3),
+ libj2_ji_mul_j2i_to_j2i_overflow(3), libj2_j2u_mul_j2u_overflow(3),
+ libj2_j2u_mul_j2u_to_j2u_overflow(3), libj2_j2u_mul_ju_overflow(3),
+ libj2_j2u_mul_ju_to_j2u_overflow(3), libj2_ju_mul_j2u_to_j2u_overflow(3),
libj2_j2u_mul_j2u_overflow_destructive(3)
Calculate the product of two values, and detect overflow.
- libj2_j2u_mul_j2u_overflow_p(3), libj2_j2u_mul_ju_overflow_p(3),
- libj2_ju_mul_j2u_overflow_p(3)
+ libj2_j2i_mul_j2i_overflow_p(3), libj2_j2i_mul_ji_overflow_p(3),
+ libj2_ji_mul_j2i_overflow_p(3), libj2_j2u_mul_j2u_overflow_p(3),
+ libj2_j2u_mul_ju_overflow_p(3), libj2_ju_mul_j2u_overflow_p(3)
Predict whether multiplying two values will result in an
overflow.
+ libj2_j2i_mul_j2i_overflow_p_quick(3),
+ libj2_j2i_mul_ji_overflow_p_quick(3),
+ libj2_ji_mul_j2i_overflow_p_quick(3),
libj2_j2u_mul_j2u_overflow_p_quick(3),
libj2_j2u_mul_ju_overflow_p_quick(3),
libj2_ju_mul_j2u_overflow_p_quick(3)
Predict whether multiplying two values will result in an
overflow, but do not preform the prediction if it is costly.
+ libj2_j2i_mul_j2i_to_j2i_overflow_p(3),
+ libj2_j2i_mul_ji_to_j2i_overflow_p(3),
+ libj2_ji_mul_j2i_to_j2i_overflow_p(3),
libj2_j2u_mul_j2u_to_j2u_overflow_p(3),
libj2_j2u_mul_ju_to_j2u_overflow_p(3),
libj2_ju_mul_j2u_to_j2u_overflow_p(3)
@@ -431,44 +460,55 @@ DESCRIPTION
libj2_ju_sat_mul_j2u_to_j2u(3), libj2_j2u_sat_mul_j2u_destructive(3)
Calculate the product of two values, but saturate on overflow.
+ libj2_j2i_divmod_j2i(3), libj2_j2i_divmod_j2i_to_j2i(3),
+ libj2_j2i_divmod_j2i_to_j2i_j2i(3), libj2_j2i_divmod_ji(3),
+ libj2_j2i_divmod_ji_to_j2i(3), libj2_j2i_divmod_ji_to_j2i_j2i(3),
libj2_j2u_divmod_j2u(3), libj2_j2u_divmod_j2u_to_j2u(3),
libj2_j2u_divmod_j2u_to_j2u_j2u(3), libj2_j2u_divmod_ju(3),
libj2_j2u_divmod_ju_to_j2u(3), libj2_j2u_divmod_ju_to_j2u_j2u(3)
Calculate the ratio between values, and keep the computed
remainder.
+ libj2_j2i_rdivmod_j2i(3), libj2_j2i_rdivmod_j2i_to_j2i(3),
libj2_j2u_rdivmod_j2u(3), libj2_j2u_rdivmod_j2u_to_j2u(3)
Calculate the ratio between values, and keep the computed
remainder. These functions swap the position of the two
operands.
+ libj2_j2i_div_j2i(3), libj2_j2i_div_j2i_to_j2i(3),
+ libj2_j2i_div_j2i_return(3), libj2_j2i_div_ji(3),
+ libj2_j2i_div_ji_to_j2i(3), libj2_j2i_div_ji_return(3),
libj2_j2u_div_j2u(3), libj2_j2u_div_j2u_to_j2u(3),
libj2_j2u_div_j2u_return(3), libj2_j2u_div_ju(3),
libj2_j2u_div_ju_to_j2u(3), libj2_j2u_div_ju_return(3)
Calculate the ratio between values, and discard the
computed remainder.
- libj2_j2u_rdiv_j2u(3)
+ libj2_j2i_rdiv_j2i(3), libj2_j2u_rdiv_j2u(3)
Calculate the ratio between values, and discard the
computed remainder. This function swaps the position of the two
operands.
+ libj2_j2i_div_j2i_to_j2i_underflow(3), libj2_j2i_div_j2i_underflow(3),
+ libj2_j2i_div_ji_to_j2i_underflow(3), libj2_j2i_div_ji_underflow(3),
libj2_j2u_div_j2u_to_j2u_underflow(3), libj2_j2u_div_j2u_underflow(3),
libj2_j2u_div_ju_to_j2u_underflow(3), libj2_j2u_div_ju_underflow(3)
Calculate the ratio between values, and discard the
computed remainder, but detect underflow (non-zero remainder).
- libj2_j2u_rdiv_j2u_underflow(3)
+ libj2_j2i_rdiv_j2i_underflow(3), libj2_j2u_rdiv_j2u_underflow(3)
Calculate the ratio between values, and discard the
computed remainder, but detect underflow (non-zero remainder).
This function swaps the position of the two operands.
- libj2_j2u_mod_j2u(3), libj2_j2u_mod_j2u_to_j2u(3), libj2_j2u_mod_ju(3),
+ libj2_j2i_mod_j2i(3), libj2_j2i_mod_j2i_to_j2i(3), libj2_j2i_mod_ji(3),
+ libj2_j2i_mod_ji_to_j2i(3), libj2_j2u_mod_j2u(3),
+ libj2_j2u_mod_j2u_to_j2u(3), libj2_j2u_mod_ju(3),
libj2_j2u_mod_ju_to_j2u(3)
Calculate the remainder of the integer division between two
values.
- libj2_j2u_rmod_j2u(3)
+ libj2_j2i_rmod_j2i(3), libj2_j2u_rmod_j2u(3)
Calculate the remainder of the integer division between two
values. This function swaps the position of the two operands.
diff --git a/common.h b/common.h
index 876d2ef..54f1e2e 100644
--- a/common.h
+++ b/common.h
@@ -1,13 +1,8 @@
/* See LICENSE file for copyright and license details. */
+#define LIBJ2_COMPILING_
#include "libj2.h"
-#if defined(__GNUC__)
-# define CONST __attribute__((__const__))
-# define PURE __attribute__((__pure__))
-#else
-# define CONST
-# define PURE
-#endif
+#define PURE LIBJ2_PURE_
#if defined(__clang__)
# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* broken warning, spams false positives */
@@ -15,6 +10,11 @@
#endif
#ifdef TEST
+# if defined(__GNUC__)
+# define CONST __attribute__((__const__))
+# else
+# define CONST
+# endif
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
diff --git a/libj2.7 b/libj2.7
index a5976e5..7275a69 100644
--- a/libj2.7
+++ b/libj2.7
@@ -752,6 +752,18 @@ Set the least significant cleared bit.
.B libj2
provides the following arithmetic functions:
.TP
+.BR libj2_j2i_add_j2i (3),
+.TQ
+.BR libj2_j2i_add_j2i_to_j2i (3),
+.TQ
+.BR libj2_j2i_add_ji (3),
+.TQ
+.BR libj2_j2i_add_ji_to_j2i (3),
+.TQ
+.BR libj2_ji_add_j2i_to_j2i (3),
+.TQ
+.BR libj2_ji_add_ji_to_j2i (3),
+.TQ
.BR libj2_j2u_add_j2u (3),
.TQ
.BR libj2_j2u_add_j2u_to_j2u (3),
@@ -765,6 +777,16 @@ provides the following arithmetic functions:
.BR libj2_ju_add_ju_to_j2u (3)
Calculate the sum of two values.
.TP
+.BR libj2_j2i_add_j2i_overflow (3),
+.TQ
+.BR libj2_j2i_add_j2i_to_j2i_overflow (3),
+.TQ
+.BR libj2_j2i_add_ji_overflow (3),
+.TQ
+.BR libj2_j2i_add_ji_to_j2i_overflow (3),
+.TQ
+.BR libj2_ji_add_j2i_to_j2i_overflow (3),
+.TQ
.BR libj2_j2u_add_j2u_overflow (3),
.TQ
.BR libj2_j2u_add_j2u_to_j2u_overflow (3),
@@ -776,6 +798,12 @@ Calculate the sum of two values.
.BR libj2_ju_add_j2u_to_j2u_overflow (3)
Calculate the sum of two values, and detect overflow.
.TP
+.BR libj2_j2i_add_j2i_overflow_p (3),
+.TQ
+.BR libj2_j2i_add_ji_overflow_p (3),
+.TQ
+.BR libj2_ji_add_j2i_overflow_p (3),
+.TQ
.BR libj2_j2u_add_j2u_overflow_p (3),
.TQ
.BR libj2_j2u_add_ju_overflow_p (3),
@@ -794,6 +822,18 @@ Predict whether adding two values will result in an overflow.
.BR libj2_ju_sat_add_j2u_to_j2u (3)
Calculate the sum of two values, but saturate on overflow.
.TP
+.BR libj2_j2i_sub_j2i (3),
+.TQ
+.BR libj2_j2i_sub_j2i_to_j2i (3),
+.TQ
+.BR libj2_j2i_sub_ji (3),
+.TQ
+.BR libj2_j2i_sub_ji_to_j2i (3),
+.TQ
+.BR libj2_ji_sub_j2i_to_j2i (3),
+.TQ
+.BR libj2_ji_sub_ji_to_j2i (3),
+.TQ
.BR libj2_j2u_sub_j2u (3),
.TQ
.BR libj2_j2u_sub_j2u_to_j2u (3),
@@ -806,13 +846,27 @@ Calculate the sum of two values, but saturate on overflow.
.TQ
.BR libj2_ju_sub_ju_to_j2u (3)
Calculate the difference between two values.
+.TP
+.BR libj2_j2i_rsub_j2i (3),
+.TQ
+.BR libj2_j2i_rsub_ji (3),
.TQ
.BR libj2_j2u_rsub_j2u (3),
.TQ
.BR libj2_j2u_rsub_ju (3)
Calculate the difference between two values. These functions
swap the position of the two operands.
-.TP
+.TQ
+.BR libj2_j2i_sub_j2i_overflow (3),
+.TQ
+.BR libj2_j2i_sub_j2i_to_j2i_overflow (3),
+.TQ
+.BR libj2_j2i_sub_ji_overflow (3),
+.TQ
+.BR libj2_j2i_sub_ji_to_j2i_overflow (3),
+.TQ
+.BR libj2_ji_sub_j2i_to_j2i_overflow (3),
+.TQ
.BR libj2_j2u_sub_j2u_overflow (3),
.TQ
.BR libj2_j2u_sub_j2u_to_j2u_overflow (3),
@@ -826,13 +880,23 @@ swap the position of the two operands.
.BR libj2_ju_sub_ju_to_j2u_overflow (3)
Calculate the difference between two values, and detect
overflow.
-.TP
+.TQ
+.BR libj2_j2i_rsub_j2i_overflow (3),
+.TQ
+.BR libj2_j2i_rsub_ji_overflow (3),
+.TQ
.BR libj2_j2u_rsub_j2u_overflow (3),
.TQ
.BR libj2_j2u_rsub_ju_overflow (3)
Calculate the difference between two values, and detect
overflow. These functions swap the position of the two operands.
.TP
+.BR libj2_j2i_sub_j2i_overflow_p (3),
+.TQ
+.BR libj2_j2i_sub_ji_overflow_p (3),
+.TQ
+.BR libj2_ji_sub_j2i_overflow_p (3),
+.TQ
.BR libj2_j2u_sub_j2u_overflow_p (3),
.TQ
.BR libj2_j2u_sub_ju_overflow_p (3),
@@ -842,6 +906,10 @@ overflow. These functions swap the position of the two operands.
.BR libj2_ju_sub_ju_overflow_p (3)
Predict whether subtracting a value will result in an overflow.
.TP
+.BR libj2_j2i_rsub_j2i_overflow_p (3),
+.TQ
+.BR libj2_j2i_rsub_ji_overflow_p (3),
+.TQ
.BR libj2_j2u_rsub_j2u_overflow_p (3),
.TQ
.BR libj2_j2u_rsub_ju_overflow_p (3)
@@ -868,6 +936,18 @@ overflow.
Calculate the difference between two values, but saturate on
overflow. These functions swap the position of the two operands.
.TP
+.BR libj2_j2i_mul_j2i (3),
+.TQ
+.BR libj2_j2i_mul_j2i_to_j2i (3),
+.TQ
+.BR libj2_j2i_mul_ji (3),
+.TQ
+.BR libj2_j2i_mul_ji_to_j2i (3),
+.TQ
+.BR libj2_ji_mul_j2i_to_j2i (3),
+.TQ
+.BR libj2_ji_mul_ji_to_j2i (3),
+.TQ
.BR libj2_j2u_mul_j2u (3),
.TQ
.BR libj2_j2u_mul_j2u_to_j2u (3),
@@ -883,6 +963,16 @@ overflow. These functions swap the position of the two operands.
.BR libj2_j2u_mul_j2u_destructive (3)
Calculate the product of two values.
.TP
+.BR libj2_j2i_mul_j2i_overflow (3),
+.TQ
+.BR libj2_j2i_mul_j2i_to_j2i_overflow (3),
+.TQ
+.BR libj2_j2i_mul_ji_overflow (3),
+.TQ
+.BR libj2_j2i_mul_ji_to_j2i_overflow (3),
+.TQ
+.BR libj2_ji_mul_j2i_to_j2i_overflow (3),
+.TQ
.BR libj2_j2u_mul_j2u_overflow (3),
.TQ
.BR libj2_j2u_mul_j2u_to_j2u_overflow (3),
@@ -896,6 +986,12 @@ Calculate the product of two values.
.BR libj2_j2u_mul_j2u_overflow_destructive (3)
Calculate the product of two values, and detect overflow.
.TP
+.BR libj2_j2i_mul_j2i_overflow_p (3),
+.TQ
+.BR libj2_j2i_mul_ji_overflow_p (3),
+.TQ
+.BR libj2_ji_mul_j2i_overflow_p (3),
+.TQ
.BR libj2_j2u_mul_j2u_overflow_p (3),
.TQ
.BR libj2_j2u_mul_ju_overflow_p (3),
@@ -904,6 +1000,12 @@ Calculate the product of two values, and detect overflow.
Predict whether multiplying two values will result in an
overflow.
.TP
+.BR libj2_j2i_mul_j2i_overflow_p_quick (3),
+.TQ
+.BR libj2_j2i_mul_ji_overflow_p_quick (3),
+.TQ
+.BR libj2_ji_mul_j2i_overflow_p_quick (3),
+.TQ
.BR libj2_j2u_mul_j2u_overflow_p_quick (3),
.TQ
.BR libj2_j2u_mul_ju_overflow_p_quick (3),
@@ -912,6 +1014,12 @@ overflow.
Predict whether multiplying two values will result in an
overflow, but do not preform the prediction if it is costly.
.TP
+.BR libj2_j2i_mul_j2i_to_j2i_overflow_p (3),
+.TQ
+.BR libj2_j2i_mul_ji_to_j2i_overflow_p (3),
+.TQ
+.BR libj2_ji_mul_j2i_to_j2i_overflow_p (3),
+.TQ
.BR libj2_j2u_mul_j2u_to_j2u_overflow_p (3),
.TQ
.BR libj2_j2u_mul_ju_to_j2u_overflow_p (3),
@@ -934,6 +1042,18 @@ multiplication.
.BR libj2_j2u_sat_mul_j2u_destructive (3)
Calculate the product of two values, but saturate on overflow.
.TP
+.BR libj2_j2i_divmod_j2i (3),
+.TQ
+.BR libj2_j2i_divmod_j2i_to_j2i (3),
+.TQ
+.BR libj2_j2i_divmod_j2i_to_j2i_j2i (3),
+.TQ
+.BR libj2_j2i_divmod_ji (3),
+.TQ
+.BR libj2_j2i_divmod_ji_to_j2i (3),
+.TQ
+.BR libj2_j2i_divmod_ji_to_j2i_j2i (3),
+.TQ
.BR libj2_j2u_divmod_j2u (3),
.TQ
.BR libj2_j2u_divmod_j2u_to_j2u (3),
@@ -948,12 +1068,28 @@ Calculate the product of two values, but saturate on overflow.
Calculate the ratio between values, and keep the computed
remainder.
.TP
+.BR libj2_j2i_rdivmod_j2i (3),
+.TQ
+.BR libj2_j2i_rdivmod_j2i_to_j2i (3),
+.TQ
.BR libj2_j2u_rdivmod_j2u (3),
.TQ
.BR libj2_j2u_rdivmod_j2u_to_j2u (3)
Calculate the ratio between values, and keep the computed
remainder. These functions swap the position of the two
operands.
+.TP
+.BR libj2_j2i_div_j2i (3),
+.TQ
+.BR libj2_j2i_div_j2i_to_j2i (3),
+.TQ
+.BR libj2_j2i_div_j2i_return (3),
+.TQ
+.BR libj2_j2i_div_ji (3),
+.TQ
+.BR libj2_j2i_div_ji_to_j2i (3),
+.TQ
+.BR libj2_j2i_div_ji_return (3),
.TQ
.BR libj2_j2u_div_j2u (3),
.TQ
@@ -969,11 +1105,21 @@ operands.
Calculate the ratio between values, and discard the
computed remainder.
.TP
+.BR libj2_j2i_rdiv_j2i (3),
+.TQ
.BR libj2_j2u_rdiv_j2u (3)
Calculate the ratio between values, and discard the
computed remainder. This function swaps the position of the two
operands.
.TP
+.BR libj2_j2i_div_j2i_to_j2i_underflow (3),
+.TQ
+.BR libj2_j2i_div_j2i_underflow (3),
+.TQ
+.BR libj2_j2i_div_ji_to_j2i_underflow (3),
+.TQ
+.BR libj2_j2i_div_ji_underflow (3),
+.TQ
.BR libj2_j2u_div_j2u_to_j2u_underflow (3),
.TQ
.BR libj2_j2u_div_j2u_underflow (3),
@@ -984,11 +1130,21 @@ operands.
Calculate the ratio between values, and discard the
computed remainder, but detect underflow (non-zero remainder).
.TP
+.BR libj2_j2i_rdiv_j2i_underflow (3),
+.TQ
.BR libj2_j2u_rdiv_j2u_underflow (3)
Calculate the ratio between values, and discard the
computed remainder, but detect underflow (non-zero remainder).
This function swaps the position of the two operands.
.TP
+.BR libj2_j2i_mod_j2i (3),
+.TQ
+.BR libj2_j2i_mod_j2i_to_j2i (3),
+.TQ
+.BR libj2_j2i_mod_ji (3),
+.TQ
+.BR libj2_j2i_mod_ji_to_j2i (3),
+.TQ
.BR libj2_j2u_mod_j2u (3),
.TQ
.BR libj2_j2u_mod_j2u_to_j2u (3),
@@ -999,6 +1155,8 @@ This function swaps the position of the two operands.
Calculate the remainder of the integer division between two
values.
.TP
+.BR libj2_j2i_rmod_j2i (3),
+.TQ
.BR libj2_j2u_rmod_j2u (3)
Calculate the remainder of the integer division between two
values. This function swaps the position of the two operands.
diff --git a/libj2.h b/libj2.h
index 07c251b..7e389a6 100644
--- a/libj2.h
+++ b/libj2.h
@@ -162,17 +162,22 @@ enum libj2_overflow {
#include "libj2/sign-shifting.h"
#include "libj2/bit-shifting.h"
#include "libj2/bit-scanning.h"
-#include "libj2/addition.h" /* TODO add signed versions */
-#include "libj2/subtraction.h" /* TODO add signed versions */
-#include "libj2/multiplication.h" /* TODO add signed versions */
-#include "libj2/division.h" /* TODO add signed versions */
+#include "libj2/addition.h"
+#include "libj2/subtraction.h"
+#include "libj2/multiplication.h"
+#include "libj2/division.h"
#include "libj2/saturated-math.h" /* TODO add signed versions */
#include "libj2/strings.h"
-#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
-# undef LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_
+#if !defined(LIBJ2_COMPILING_)
+# if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+# undef LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_
+# endif
+# if defined(LIBJ2_USE_GCC_PARITYG_)
+# undef LIBJ2_USE_GCC_PARITYG_
+# endif
+# undef LIBJ2_PURE_
#endif
-#undef LIBJ2_PURE_
#endif
diff --git a/libj2/addition.h b/libj2/addition.h
index c0fed6e..de44e98 100644
--- a/libj2/addition.h
+++ b/libj2/addition.h
@@ -172,7 +172,7 @@ libj2_ju_add_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct
/**
* Calculate the sum, as an unsigned double-max precision
- * integer, of two unsigned double-max precision integers
+ * integer, of two unsigned max precision integers
*
* `libj2_ju_add_ju_to_j2u(a, b, res)` implements
* `*res = a + b`, where `a` and `b` are converted to
@@ -222,10 +222,11 @@ libj2_j2u_add_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
/**
- * Calculate the sum of two unsigned double-max precision
- * integers
+ * Calculate the sum of two unsigned double-max
+ * precision integers
*
- * `libj2_j2u_add_j2u_to_j2u(a, b, res)` implements `*res = *a + *b`
+ * `libj2_j2u_add_j2u_to_j2u(a, b, res)` implements
+ * `*res = *a + *b`
*
* @param a The augend
* @param b The addend
@@ -350,7 +351,7 @@ libj2_j2u_add_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_j2u_add_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b)
{
return a->low > UINTMAX_MAX - b && a->high == UINTMAX_MAX;
@@ -371,7 +372,7 @@ libj2_j2u_add_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b)
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_ju_add_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b)
{
return libj2_j2u_add_ju_overflow_p(b, a);
@@ -391,9 +392,10 @@ libj2_ju_add_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b)
* @param b The addend
* @return 1 if the addition would overflow, 0 otherwise
*
- * @since 1.0
+ * @since 1.0 (broken)
+ * @since 1.1 (fixed)
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_j2u_add_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b)
{
if (a == b)
@@ -405,3 +407,373 @@ libj2_j2u_add_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *
else
return a->high > UINTMAX_MAX - b->high;
}
+
+
+
+
+
+/**
+ * Calculate the sum of a signed double-max precision
+ * integer and a signed max precision integer
+ *
+ * `libj2_j2i_add_ji(a, b)` implements `*a += b`
+ *
+ * @param a The augend, and output parameter for the sum
+ * @param b The addend
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_add_ji(struct libj2_j2i *a, intmax_t b)
+{
+ struct libj2_j2u u;
+ if (b < 0) {
+ u.high = UINTMAX_MAX;
+ u.low = ~(uintmax_t)-(b + 1);
+ } else {
+ u.high = 0;
+ u.low = (uintmax_t)b;
+ }
+ libj2_j2u_add_j2u((void *)a, &u);
+}
+
+
+/**
+ * Calculate the sum of two signed double-max precision
+ * integers
+ *
+ * `libj2_j2i_add_j2i(a, b)` implements `*a += *b`
+ *
+ * @param a The augend, and output parameter for the sum
+ * @param b The addend
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_add_j2i(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ libj2_j2u_add_j2u((void *)a, (const void *)b);
+}
+
+
+/**
+ * Calculate the sum of a signed double-max precision
+ * integer and a signed max precision integer
+ *
+ * `libj2_j2i_add_ji_to_j2i(a, b, res)` implements
+ * `*res = *a + b`
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_add_ji_to_j2i(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res)
+{
+ struct libj2_j2u u;
+ if (b < 0) {
+ u.high = UINTMAX_MAX;
+ u.low = ~(uintmax_t)-(b + 1);
+ } else {
+ u.high = 0;
+ u.low = (uintmax_t)b;
+ }
+ libj2_j2u_add_j2u_to_j2u((const void *)a, &u, (void *)res);
+}
+
+
+/**
+ * Calculate the sum of two signed double-max precision
+ * integers
+ *
+ * `libj2_j2i_add_j2i_to_j2i(a, b, res)` implements `*res = *a + *b`
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_add_j2i_to_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ libj2_j2u_add_j2u_to_j2u((const void *)a, (const void *)b, (void *)res);
+}
+
+
+/**
+ * Calculate the sum, as a signed double-max precision
+ * integer, of two signed max precision integers
+ *
+ * `libj2_ji_add_ji_to_j2i(a, b, res)` implements
+ * `*res = a + b`, where `a` and `b` are converted to
+ * `struct libj2_j2i`'s
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ *
+ * @since 1.1
+ */
+inline void
+libj2_ji_add_ji_to_j2i(intmax_t a, intmax_t b, struct libj2_j2i *res)
+{
+ struct libj2_j2u u, v;
+ if (a < 0) {
+ u.high = UINTMAX_MAX;
+ u.low = ~(uintmax_t)-(a + 1);
+ } else {
+ u.high = 0;
+ u.low = (uintmax_t)a;
+ }
+ if (b < 0) {
+ v.high = UINTMAX_MAX;
+ v.low = ~(uintmax_t)-(b + 1);
+ } else {
+ v.high = 0;
+ v.low = (uintmax_t)b;
+ }
+ libj2_j2u_add_j2u_to_j2u(&u, &v, (void *)res);
+}
+
+
+/**
+ * Calculate the sum of a signed max precision
+ * integer and a signed double-max precision integer
+ *
+ * `libj2_ji_add_j2i_to_j2i(a, b, res)` implements
+ * `*res = a + *b`
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ *
+ * @since 1.1
+ */
+inline void
+libj2_ji_add_j2i_to_j2i(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ libj2_j2i_add_ji_to_j2i(b, a, res);
+}
+
+
+/**
+ * Predict the result-overflow signal
+ * `libj2_j2i_add_j2i_to_j2i_overflow` or
+ * `libj2_j2i_add_j2i_overflow` will return
+ *
+ * `libj2_j2i_add_j2i_overflow_p(a, b)` implements
+ * `libj2_j2i_add_j2i_to_j2i_overflow(a, b, &(struct libj2_j2i){})`
+ * in an efficient manner
+ *
+ * @param a The augend
+ * @param b The addend
+ * @return +1 if the addition would overflow positively,
+ * -1 if the addition would overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline int
+libj2_j2i_add_j2i_overflow_p(const struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ if (libj2_j2i_is_positive(a) && libj2_j2i_is_positive(b)) {
+ if (a == b)
+ return (int)(a->high >> (LIBJ2_JU_BIT - 2U));
+ if (a->low > UINTMAX_MAX - b->low)
+ return a->high >= (uintmax_t)INTMAX_MAX - b->high;
+ else
+ return a->high > (uintmax_t)INTMAX_MAX - b->high;
+ } else if (libj2_j2i_is_negative(a) && libj2_j2i_is_negative(b)) {
+ if (a == b)
+ return ~a->high >> (LIBJ2_JU_BIT - 2U) ? -1 : 0;
+ if (a->low > UINTMAX_MAX - b->low)
+ return a->high + b->high + 1U < ~(uintmax_t)INTMAX_MAX ? -1 : 0;
+ else
+ return a->high + b->high < ~(uintmax_t)INTMAX_MAX ? -1 : 0;
+ } else {
+ return 0;
+ }
+}
+
+
+/**
+ * Predict the result-overflow signal
+ * `libj2_j2i_add_ji_to_j2i_overflow` or
+ * `libj2_j2i_add_ji_overflow` will return
+ *
+ * `libj2_j2i_add_ji_overflow_p(a, b)` implements
+ * `libj2_j2i_add_ji_to_j2i_overflow(a, b, &(struct libj2_j2i){})`
+ * in an efficient manner
+ *
+ * @param a The augend
+ * @param b The addend
+ * @return +1 if the addition would overflow positively,
+ * -1 if the addition would overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline int
+libj2_j2i_add_ji_overflow_p(const struct libj2_j2i *a, intmax_t b)
+{
+ if (b > 0 && libj2_j2i_is_positive(a)) {
+ if (a->low > UINTMAX_MAX - (uintmax_t)b)
+ return a->high >= (uintmax_t)INTMAX_MAX;
+ else
+ return a->high > (uintmax_t)INTMAX_MAX;
+ } else if (b < 0 && libj2_j2i_is_negative(a)) {
+ if (a->low > UINTMAX_MAX - ~(uintmax_t)-(b + 1))
+ return a->high < ~(uintmax_t)INTMAX_MAX ? -1 : 0;
+ else
+ return a->high <= ~(uintmax_t)INTMAX_MAX ? -1 : 0;
+ } else {
+ return 0;
+ }
+}
+
+
+/**
+ * Predict the result-overflow signal
+ * `libj2_ji_add_j2i_to_j2i_overflow` will return
+ *
+ * `libj2_ji_add_j2i_overflow_p(a, b)` implements
+ * `libj2_ji_add_j2i_to_j2i_overflow(a, b, &(struct libj2_j2i){})`
+ * in an efficient manner
+ *
+ * @param a The augend
+ * @param b The addend
+ * @return +1 if the addition would overflow positively,
+ * -1 if the addition would overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline int
+libj2_ji_add_j2i_overflow_p(intmax_t a, const struct libj2_j2i *b)
+{
+ return libj2_j2i_add_ji_overflow_p(b, a);
+}
+
+
+/**
+ * Calculate the sum of a signed double-max precision
+ * integer and a signed max precision integer
+ *
+ * `libj2_j2i_add_ji_overflow(a, b)` implements `*a += b`
+ * with overflow-detection
+ *
+ * @param a The augend, and output parameter for the sum
+ * @param b The addend
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_add_ji_overflow(struct libj2_j2i *a, intmax_t b)
+{
+ int overflow = libj2_j2i_add_ji_overflow_p(a, b);
+ libj2_j2i_add_ji(a, b);
+ return overflow;
+}
+
+
+/**
+ * Calculate the sum of two signed double-max precision
+ * integers
+ *
+ * `libj2_j2i_add_j2i_overflow(a, b)` implements `*a += *b`
+ * with overflow-detection
+ *
+ * @param a The augend, and output parameter for the sum
+ * @param b The addend
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_add_j2i_overflow(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ int overflow = libj2_j2i_add_j2i_overflow_p(a, b);
+ libj2_j2i_add_j2i(a, b);
+ return overflow;
+}
+
+
+/**
+ * Calculate the sum of a signed double-max precision
+ * integer and a signed max precision integer
+ *
+ * `libj2_j2i_add_ji_to_j2i_overflow(a, b, res)` implements
+ * `*res = *a + b` with overflow-detection
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_add_ji_to_j2i_overflow(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res)
+{
+ int overflow = libj2_j2i_add_ji_overflow_p(a, b);
+ libj2_j2i_add_ji_to_j2i(a, b, res);
+ return overflow;
+}
+
+
+/**
+ * Calculate the sum of two signed double-max precision
+ * integers
+ *
+ * `libj2_j2i_add_j2i_to_j2i_overflow(a, b, res)` implements
+ * `*res = *a + *b` with overflow-detection
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_add_j2i_to_j2i_overflow(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ int overflow = libj2_j2i_add_j2i_overflow_p(a, b);
+ libj2_j2i_add_j2i_to_j2i(a, b, res);
+ return overflow;
+}
+
+
+/**
+ * Calculate the sum of a signed max precision
+ * integer and a signed double-max precision integer
+ *
+ * `libj2_ji_add_j2i_to_j2i_overflow(a, b, res)` implements
+ * `*res = a + *b` with overflow-detection
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_ji_add_j2i_to_j2i_overflow(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ return libj2_j2i_add_ji_to_j2i_overflow(b, a, res);
+}
diff --git a/libj2/bit-shifting.h b/libj2/bit-shifting.h
index 7cf44bf..b04a533 100644
--- a/libj2/bit-shifting.h
+++ b/libj2/bit-shifting.h
@@ -624,7 +624,7 @@ libj2_ju_rrot_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res)
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_j2u_lsh_overflow_p(const struct libj2_j2u *a, unsigned b)
{
if (b >= LIBJ2_J2U_BIT)
@@ -654,7 +654,7 @@ libj2_j2u_lsh_overflow_p(const struct libj2_j2u *a, unsigned b)
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_ju_lsh_overflow_p(uintmax_t a, unsigned b)
{
if (b >= LIBJ2_J2U_BIT)
@@ -681,7 +681,7 @@ libj2_ju_lsh_overflow_p(uintmax_t a, unsigned b)
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_j2u_rsh_underflow_p(const struct libj2_j2u *a, unsigned b)
{
if (b >= LIBJ2_J2U_BIT)
@@ -711,7 +711,7 @@ libj2_j2u_rsh_underflow_p(const struct libj2_j2u *a, unsigned b)
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_ju_rsh_underflow_p(uintmax_t a, unsigned b)
{
if (b >= LIBJ2_JU_BIT)
@@ -839,7 +839,7 @@ libj2_ji_lsh_to_j2i(intmax_t a, unsigned b, struct libj2_j2i *res)
*
* @since 1.1
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_j2i_lsh_overflow_p(const struct libj2_j2i *a, unsigned b)
{
if (!b) {
@@ -885,7 +885,7 @@ libj2_j2i_lsh_overflow_p(const struct libj2_j2i *a, unsigned b)
*
* @since 1.1
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_ji_lsh_overflow_p(intmax_t a, unsigned b)
{
if (b >= LIBJ2_J2I_BIT)
@@ -1251,7 +1251,7 @@ libj2_ji_rsh_to_j2i_underflow(intmax_t a, unsigned b, struct libj2_j2i *res)
*
* @since 1.1
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_j2i_rsh_underflow_p(const struct libj2_j2i *a, unsigned b)
{
if (libj2_j2i_is_negative(a)) {
@@ -1284,7 +1284,7 @@ libj2_j2i_rsh_underflow_p(const struct libj2_j2i *a, unsigned b)
*
* @since 1.1
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_ji_rsh_underflow_p(intmax_t a, unsigned b)
{
if (b >= LIBJ2_JU_BIT)
diff --git a/libj2/division.h b/libj2/division.h
index 274ce13..603a1b6 100644
--- a/libj2/division.h
+++ b/libj2/division.h
@@ -702,3 +702,761 @@ libj2_j2u_div_ju_to_j2u_underflow(const struct libj2_j2u *a, uintmax_t b, struct
libj2_j2u_divmod_ju_to_j2u(&c, b, res);
return c.high || c.low;
}
+
+
+
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of two signed
+ * double-max precision integers
+ *
+ * `libj2_j2i_divmod_j2i_to_j2i(a, b, res_q)`
+ * implements `*res_q = *a / *b, *a %= *b`
+ *
+ * For the quotient q, and remainder r,
+ * dividend n, and divisor d, it will be true
+ * that qd + r = n
+ *
+ * Overflows if `libj2_j2i_is_min(a) && libj2_j2i_eq_ji(b, -1)`
+ *
+ * @param a The dividend (left-hand), also used as
+ * the output parameter for the remainder
+ * @param b The divisor (right-hand)
+ * @param res_q Output parameter for the quotient
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_divmod_j2i_to_j2i(struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res_q)
+{
+ int a_neg = libj2_j2i_is_negative(a);
+ int b_neg = libj2_j2i_is_negative(b);
+ struct libj2_j2u u;
+ if (b_neg)
+ libj2_minus_j2i_to_j2u(b, &u);
+ else
+ libj2_j2i_to_j2u(b, &u);
+ if (a_neg)
+ libj2_minus_j2i(a);
+ libj2_j2u_divmod_j2u_to_j2u((void *)a, &u, (void *)res_q);
+ if (a_neg)
+ libj2_minus_j2i(a);
+ if (a_neg != b_neg)
+ libj2_minus_j2i(res_q);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of two signed
+ * double-max precision integers
+ *
+ * `libj2_j2i_divmod_j2i_to_j2i_j2i(a, b, res_q, res_r)`
+ * implements `*res_q = *a / *b, *res_r = *a % *b`
+ *
+ * For the quotient q, and remainder r,
+ * dividend n, and divisor d, it will be true
+ * that qd + r = n
+ *
+ * Overflows if `libj2_j2i_is_min(a) && libj2_j2i_eq_ji(b, -1)`
+ *
+ * @param a The dividend (left-hand)
+ * @param b The divisor (right-hand)
+ * @param res_q Output parameter for the quotient
+ * @param res_r Output parameter for the remainder
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_divmod_j2i_to_j2i_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b,
+ struct libj2_j2i *res_q, struct libj2_j2i *res_r)
+{
+ if (res_r == b) {
+ struct libj2_j2i r = *a;
+ libj2_j2i_divmod_j2i_to_j2i(&r, b, res_q);
+ *res_r = r;
+ } else {
+ *res_r = *a;
+ libj2_j2i_divmod_j2i_to_j2i(res_r, b, res_q);
+ }
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of two signed
+ * double-max precision integers
+ *
+ * `libj2_j2i_divmod_j2i(a, b)` implements
+ * `t = (intmax_t)(*a / *b), *a %= *b, t`
+ * (using an intermediate variable `t`)
+ *
+ * For the quotient q, and remainder r,
+ * dividend n, and divisor d, it will be true
+ * that qd + r = n; however the high half
+ * of the q is discarded in this function's
+ * return value
+ *
+ * Overflows if `libj2_j2i_is_min(a) && libj2_j2i_eq_ji(b, -1)`
+ *
+ * @param a The dividend (left-hand), also used as
+ * the output parameter for the remainder
+ * @param b The divisor (right-hand)
+ * @return The low half of the quotient
+ *
+ * @since 1.1
+ */
+inline intmax_t
+libj2_j2i_divmod_j2i(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ struct libj2_j2i q;
+ libj2_j2i_divmod_j2i_to_j2i(a, b, &q);
+ if (libj2_j2i_is_negative(&q)) {
+ libj2_minus_j2i(&q);
+ return -(intmax_t)q.low;
+ } else {
+ return (intmax_t)q.low;
+ }
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of a signed
+ * double-max precision integer (dividend) and
+ * a signed max precision integer (divisor)
+ *
+ * `libj2_j2i_divmod_ji(a, b)` implements
+ * `t = (intmax_t)(*a / b), *a %= b, t`
+ * (using an intermediate variable `t`)
+ *
+ * For the quotient q, and remainder r,
+ * dividend n, and divisor d, it will be true
+ * that qd + r = n; however the high half
+ * of the q is discarded in this function's
+ * return value
+ *
+ * Overflows if `libj2_j2i_is_min(a) && b == -1`
+ *
+ * @param a The dividend (left-hand), also used as
+ * the output parameter for the remainder
+ * @param b The divisor (right-hand)
+ * @return The low half of the quotient
+ *
+ * @since 1.1
+ */
+inline intmax_t
+libj2_j2i_divmod_ji(struct libj2_j2i *a, intmax_t b)
+{
+ int a_neg = libj2_j2i_is_negative(a);
+ uintmax_t u, q;
+ if (a_neg)
+ libj2_minus_j2i(a);
+ if (b < 0)
+ u = (uintmax_t)-(b + 1) + 1U;
+ else
+ u = (uintmax_t)b;
+ q = libj2_j2u_divmod_ju((void *)a, u);
+ if (a_neg)
+ libj2_minus_j2i(a);
+ return a_neg != (b < 0) ? -(intmax_t)q : (intmax_t)q;
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of a signed
+ * double-max precision integer (dividend) and
+ * a signed max precision integer (divisor)
+ *
+ * `libj2_j2i_divmod_ji_to_j2i(a, b, res_q)`
+ * implements `*res_q = *a / b, *a %= b`
+ *
+ * For the quotient q, and remainder r,
+ * dividend n, and divisor d, it will be true
+ * that qd + r = n
+ *
+ * Overflows if `libj2_j2i_is_min(a) && b == -1`
+ *
+ * @param a The dividend (left-hand), also used as
+ * the output parameter for the remainder
+ * @param b The divisor (right-hand)
+ * @param res_q Output parameter for the quotient
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_divmod_ji_to_j2i(struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res_q)
+{
+ int a_neg = libj2_j2i_is_negative(a);
+ uintmax_t u;
+ if (a_neg)
+ libj2_minus_j2i(a);
+ if (b < 0)
+ u = (uintmax_t)-(b + 1) + 1U;
+ else
+ u = (uintmax_t)b;
+ res_q->high = a->high / u;
+ res_q->low = libj2_j2u_divmod_ju((void *)a, u);
+ if (a_neg)
+ libj2_minus_j2i(a);
+ if (a_neg != (b < 0))
+ libj2_minus_j2i(res_q);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of a signed
+ * double-max precision integer (dividend) and
+ * a signed max precision integer (divisor)
+ *
+ * `libj2_j2i_divmod_ji_to_j2i_j2i(a, b, res_q, res_r)`
+ * implements `*res_q = *a / b, *res_r = *a % b`
+ *
+ * For the quotient q, and remainder r,
+ * dividend n, and divisor d, it will be true
+ * that qd + r = n
+ *
+ * Overflows if `libj2_j2i_is_min(a) && b == -1`
+ *
+ * @param a The dividend (left-hand)
+ * @param b The divisor (right-hand)
+ * @param res_q Output parameter for the quotient
+ * @param res_r Output parameter for the remainder
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_divmod_ji_to_j2i_j2i(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res_q, struct libj2_j2i *res_r)
+{
+ int a_neg = libj2_j2i_is_negative(a);
+ uintmax_t u;
+ if (a_neg)
+ libj2_minus_j2i_to_j2u(a, (void *)res_r);
+ else
+ *res_r = *a;
+ if (b < 0)
+ u = (uintmax_t)-(b + 1) + 1U;
+ else
+ u = (uintmax_t)b;
+ res_q->high = res_r->high / u;
+ res_q->low = libj2_j2u_divmod_ju((void *)res_r, u);
+ if (a_neg)
+ libj2_minus_j2i(res_r);
+ if (a_neg != (b < 0))
+ libj2_minus_j2i(res_q);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of two signed
+ * double-max precision integers; in this variant
+ * of `libj2_j2i_rdivmod_j2i_to_j2i`, the dividend
+ * (left-hand) is the second parameter and the
+ * divisor (right-hand) is the first parameter
+ *
+ * `libj2_j2i_rdivmod_j2i_to_j2i(a, b, res_q)`
+ * implements `*res_q = *b / *a, *a = *b % *a`
+ *
+ * For the quotient q, and remainder r,
+ * dividend n, and divisor d, it will be true
+ * that qd + r = n
+ *
+ * Overflows if `libj2_j2i_is_min(b) && libj2_j2i_eq_ji(a, -1)`
+ *
+ * @param a The divisor (right-hand), also used as
+ * the output parameter for the remainder
+ * @param b The dividend (left-hand)
+ * @param res_q Output parameter for the quotient
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_rdivmod_j2i_to_j2i(struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res_q)
+{
+ struct libj2_j2i res_r;
+ libj2_j2i_divmod_j2i_to_j2i_j2i(b, a, res_q, &res_r);
+ *a = res_r;
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of two signed
+ * double-max precision integers; in this variant
+ * of `libj2_j2i_rdivmod_j2i_to_j2i`, the dividend
+ * (left-hand) is the second parameter and the
+ * divisor (right-hand) is the first parameter
+ *
+ * `libj2_j2i_rdivmod_j2i(a, b)` implements
+ * `t = (intmax_t)(*b / *a), *a = *b % *a, t`
+ * (using an intermediate variable `t`)
+ *
+ * For the quotient q, and remainder r,
+ * dividend n, and divisor d, it will be true
+ * that qd + r = n; however the high half
+ * of the q is discarded in this function's
+ * return value
+ *
+ * Overflows if `libj2_j2i_is_min(b) && libj2_j2i_eq_ji(a, -1)`
+ *
+ * @param a The divisor (right-hand), also used as
+ * the output parameter for the remainder
+ * @param b The dividend (left-hand)
+ * @return The low half of the quotient
+ *
+ * @since 1.1
+ */
+inline intmax_t
+libj2_j2i_rdivmod_j2i(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ struct libj2_j2i q;
+ libj2_j2i_divmod_j2i_to_j2i_j2i(b, a, &q, a);
+ if (libj2_j2i_is_negative(&q)) {
+ libj2_minus_j2i(&q);
+ return -(intmax_t)q.low;
+ } else {
+ return (intmax_t)q.low;
+ }
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of two signed double-max
+ * precision integers
+ *
+ * `libj2_j2i_div_j2i(a, b)` implements `*a /= *b`
+ *
+ * Overflows if `libj2_j2i_is_min(a) && libj2_j2i_eq_ji(b, -1)`
+ *
+ * @param a The dividend (left-hand), also used as
+ * the output parameter for the quotient
+ * @param b The divisor (right-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_div_j2i(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ struct libj2_j2i c = *a;
+ libj2_j2i_divmod_j2i_to_j2i(&c, b, a);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of two signed double-max
+ * precision integers
+ *
+ * `libj2_j2i_div_j2i_to_j2i(a, b, res)`
+ * implements `*res = *a / *b`
+ *
+ * Overflows if `libj2_j2i_is_min(a) && libj2_j2i_eq_ji(b, -1)`
+ *
+ * @param a The dividend (left-hand)
+ * @param b The divisor (right-hand)
+ * @param res Output parameter for the quotient
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_div_j2i_to_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ struct libj2_j2i c = *a;
+ libj2_j2i_divmod_j2i_to_j2i(&c, b, res);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of two signed double-max
+ * precision integers
+ *
+ * `libj2_j2i_div_j2i_return(a, b)`
+ * implements `(intmax_t)(*a / *b)`
+ *
+ * Overflows if `libj2_j2i_is_min(a) && libj2_j2i_eq_ji(b, -1)`
+ *
+ * @param a The dividend (left-hand)
+ * @param b The divisor (right-hand)
+ * @return The low half of the quotient
+ *
+ * @since 1.1
+ */
+inline intmax_t
+libj2_j2i_div_j2i_return(const struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ struct libj2_j2i c = *a;
+ return libj2_j2i_divmod_j2i(&c, b);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of two signed double-max
+ * precision integers; in this variant
+ * of `libj2_j2i_div_j2i`, the dividend
+ * (left-hand) is the second parameter and the
+ * divisor (right-hand) is the first parameter
+ *
+ * `libj2_j2i_rdiv_j2i(a, b)` implements `*a = *b / *a`
+ *
+ * Overflows if `libj2_j2i_is_min(b) && libj2_j2i_eq_ji(a, -1)`
+ *
+ * @param a The divisor (right-hand), also used as
+ * the output parameter for the quotient
+ * @param b The dividend (left-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_rdiv_j2i(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ struct libj2_j2i c = *b;
+ libj2_j2i_divmod_j2i_to_j2i(&c, a, a);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of a signed double-max
+ * precision integer (dividend) and a
+ * signed max precision integer (divisor)
+ *
+ * `libj2_j2i_div_ji(a, b)` implements `*a /= b`
+ *
+ * Overflows if `libj2_j2i_is_min(a) && b == -1`
+ *
+ * @param a The dividend (left-hand), also used as
+ * the output parameter for the quotient
+ * @param b The divisor (right-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_div_ji(struct libj2_j2i *a, intmax_t b)
+{
+ struct libj2_j2i c = *a;
+ libj2_j2i_divmod_ji_to_j2i(&c, b, a);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of a signed double-max
+ * precision integer (dividend) and a
+ * signed max precision integer (divisor)
+ *
+ * `libj2_j2i_div_ji_to_j2i(a, b, res)`
+ * implements `*res = *a / b`
+ *
+ * Overflows if `libj2_j2i_is_min(a) && b == -1`
+ *
+ * @param a The dividend (left-hand)
+ * @param b The divisor (right-hand)
+ * @param res Output parameter for the quotient
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_div_ji_to_j2i(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res)
+{
+ struct libj2_j2i c = *a;
+ libj2_j2i_divmod_ji_to_j2i(&c, b, res);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of a signed double-max
+ * precision integer (dividend) and a
+ * signed max precision integer (divisor)
+ *
+ * `libj2_j2i_div_ji_return(a, b)`
+ * implements `(intmax_t)(*a / b)`
+ *
+ * Overflows if `libj2_j2i_is_min(a) && b == -1`
+ *
+ * @param a The dividend (left-hand)
+ * @param b The divisor (right-hand)
+ * @return The low half of the quotient
+ *
+ * @since 1.1
+ */
+inline intmax_t
+libj2_j2i_div_ji_return(const struct libj2_j2i *a, intmax_t b)
+{
+ struct libj2_j2i c = *a;
+ return libj2_j2i_divmod_ji(&c, b);
+}
+
+
+/**
+ * Calculate the integer remainder, for integer
+ * division with the quotient rounded towards zero,
+ * of two signed double-max precision integers
+ *
+ * `libj2_j2i_mod_j2i(a, b)` implements `*a %= *b`
+ *
+ * @param a The dividend (left-hand), also used as
+ * the output parameter for the remainder
+ * @param b The divisor (right-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_mod_j2i(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ (void) libj2_j2i_divmod_j2i(a, b);
+}
+
+
+/**
+ * Calculate the integer remainder, for integer
+ * division with the quotient rounded towards zero,
+ * of two signed double-max precision integers
+ *
+ * `libj2_j2i_mod_j2i_to_j2i(a, b, res)`
+ * implements `*res = *a % *b`
+ *
+ * @param a The dividend (left-hand)
+ * @param b The divisor (right-hand)
+ * @param res Output parameter for the remainder
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_mod_j2i_to_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ if (res == b) {
+ struct libj2_j2i r = *a;
+ libj2_j2i_mod_j2i(&r, b);
+ *res = r;
+ } else {
+ *res = *a;
+ libj2_j2i_mod_j2i(res, b);
+ }
+}
+
+
+/**
+ * Calculate the integer remainder, for integer
+ * division with the quotient rounded towards zero,
+ * of two signed double-max precision integers;
+ * in this variant of `libj2_j2i_mod_j2i`, the
+ * dividend (left-hand) is the second parameter
+ * and the divisor (right-hand) is the first parameter
+ *
+ * `libj2_j2i_rmod_j2i_to_j2i(a, b)` implements
+ * `*a = *b % *a`
+ *
+ * @param a The divisor (right-hand), also used as
+ * the output parameter for the remainder
+ * @param b The dividend (left-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_rmod_j2i(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ libj2_j2i_mod_j2i_to_j2i(b, a, a);
+}
+
+
+/**
+ * Calculate the integer remainder, for integer
+ * division with the quotient rounded towards zero,
+ * of a signed double-max precision integer
+ * (dividend) and a signed max precision
+ * integer (divisor)
+ *
+ * `libj2_j2i_mod_ji(a, b)` implements `*a %= b`
+ *
+ * @param a The dividend (left-hand), also used as
+ * the output parameter for the remainder
+ * @param b The divisor (right-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_mod_ji(struct libj2_j2i *a, intmax_t b)
+{
+ int a_neg = libj2_j2i_is_negative(a);
+ uintmax_t u;
+ if (a_neg)
+ libj2_minus_j2i(a);
+ if (b < 0)
+ u = (uintmax_t)-(b + 1) + 1U;
+ else
+ u = (uintmax_t)b;
+ libj2_j2u_mod_ju((void *)a, u);
+ if (a_neg)
+ libj2_minus_j2i(a);
+}
+
+
+/**
+ * Calculate the integer remainder, for integer
+ * division with the quotient rounded towards zero,
+ * of a signed double-max precision integer
+ * (dividend) and a signed max precision
+ * integer (divisor)
+ *
+ * `libj2_j2i_mod_ji_to_j2i(a, b, res)`
+ * implements `*res = *a % b`
+ *
+ * @param a The dividend (left-hand)
+ * @param b The divisor (right-hand)
+ * @param res Output parameter for the remainder
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_mod_ji_to_j2i(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res)
+{
+ *res = *a;
+ libj2_j2i_mod_ji(res, b);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of two signed double-max
+ * precision integers
+ *
+ * `libj2_j2i_div_j2i_underflow(a, b)` implements
+ * `t = !!(*a % b), *a /= *b, t`
+ * (using an intermediate variable `t`)
+ *
+ * Overflows if `libj2_j2i_is_min(a) && libj2_j2i_eq_ji(b, -1)`
+ *
+ * @param a The dividend (left-hand), also used as
+ * the output parameter for the quotient
+ * @param b The divisor (right-hand)
+ * @return 1 if the remainder is non-zero, 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_div_j2i_underflow(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ struct libj2_j2i c = *a;
+ libj2_j2i_divmod_j2i_to_j2i(&c, b, a);
+ return c.high || c.low;
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of two signed double-max
+ * precision integers
+ *
+ * `libj2_j2i_div_j2i_to_j2i_underflow(a, b, res)`
+ * implements `*res = *a / *b, !!(a % b)`
+ *
+ * @param a The dividend (left-hand)
+ * @param b The divisor (right-hand)
+ * @param res Output parameter for the quotient
+ * @return 1 if the remainder is non-zero, 0 otherwise
+ *
+ * Overflows if `libj2_j2i_is_min(a) && libj2_j2i_eq_ji(b, -1)`
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_div_j2i_to_j2i_underflow(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ struct libj2_j2i c = *a;
+ libj2_j2i_divmod_j2i_to_j2i(&c, b, res);
+ return c.high || c.low;
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of two signed double-max
+ * precision integers; in this variant
+ * of `libj2_j2i_div_j2i`, the dividend
+ * (left-hand) is the second parameter and the
+ * divisor (right-hand) is the first parameter
+ *
+ * `libj2_j2i_rdiv_j2i_underflow(a, b)` implements
+ * `t = !!(*a % *b), *a = *b / *a, t`
+ * (using an intermediate variable `t`)
+ *
+ * Overflows if `libj2_j2i_is_min(b) && libj2_j2i_eq_ji(a, -1)`
+ *
+ * @param a The divisor (right-hand), also used as
+ * the output parameter for the quotient
+ * @param b The dividend (left-hand)
+ * @return 1 if the remainder is non-zero, 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_rdiv_j2i_underflow(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ struct libj2_j2i c = *b;
+ libj2_j2i_divmod_j2i_to_j2i(&c, a, a);
+ return c.high || c.low;
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of a signed double-max
+ * precision integer (dividend) and a
+ * signed max precision integer (divisor)
+ *
+ * `libj2_j2i_div_ji_underflow(a, b)` implements
+ * `t = !!(a % b), *a /= b, t`
+ * (using an intermediate variable `t`)
+ *
+ * Overflows if `libj2_j2i_is_min(a) && b == -1`
+ *
+ * @param a The dividend (left-hand), also used as
+ * the output parameter for the quotient
+ * @param b The divisor (right-hand)
+ * @return 1 if the remainder is non-zero, 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_div_ji_underflow(struct libj2_j2i *a, intmax_t b)
+{
+ struct libj2_j2i c = *a;
+ libj2_j2i_divmod_ji_to_j2i(&c, b, a);
+ return c.high || c.low;
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of a signed double-max
+ * precision integer (dividend) and a
+ * signed max precision integer (divisor)
+ *
+ * `libj2_j2i_div_ji_to_j2i_underflow(a, b, res)`
+ * implements `*res = *a / b, !!(a % b)`
+ *
+ * Overflows if `libj2_j2i_is_min(a) && b == -1`
+ *
+ * @param a The dividend (left-hand)
+ * @param b The divisor (right-hand)
+ * @param res Output parameter for the quotient
+ * @return 1 if the remainder is non-zero, 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_div_ji_to_j2i_underflow(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res)
+{
+ struct libj2_j2i c = *a;
+ libj2_j2i_divmod_ji_to_j2i(&c, b, res);
+ return c.high || c.low;
+}
diff --git a/libj2/multiplication.h b/libj2/multiplication.h
index eb0d9a5..a80161b 100644
--- a/libj2/multiplication.h
+++ b/libj2/multiplication.h
@@ -6,7 +6,7 @@
/**
* Calculate the unsigned double-max precision integer
- * product of two unsigned double-max precision integers
+ * product of two unsigned max precision integers
*
* `libj2_ju_mul_ju_to_j2u(a, b, res)` implements
* `*res = a * b`, where `a` and `b` are converted
@@ -63,8 +63,8 @@ libj2_ju_mul_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *res)
/**
- * Calculate the product of an unsigned double-max
- * precision integer (multiplier) and an unsigned
+ * Calculate the product of a signed double-max
+ * precision integer (multiplier) and a signed
* max precision integer (multiplicand)
*
* `libj2_j2u_mul_ju_to_j2u(a, b)` implements `*a *= b`,
@@ -86,8 +86,8 @@ libj2_j2u_mul_ju(struct libj2_j2u *a, uintmax_t b)
/**
- * Calculate the product of an unsigned double-max
- * precision integer (multiplier) and an unsigned
+ * Calculate the product of a signed double-max
+ * precision integer (multiplier) and a signed
* max precision integer (multiplicand)
*
* `libj2_j2u_mul_ju_to_j2u(a, b, res)` implements
@@ -109,8 +109,8 @@ libj2_j2u_mul_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u
/**
- * Calculate the product of an unsigned max
- * precision integer (multiplier) and an unsigned
+ * Calculate the product of a signed max
+ * precision integer (multiplier) and a signed
* double-max precision integer (multiplicand)
*
* `libj2_ju_mul_j2u_to_j2u(a, b, res)` implements
@@ -132,8 +132,8 @@ libj2_ju_mul_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u
/**
- * Calculate the product of an unsigned double-max
- * precision integer (multiplier) and an unsigned
+ * Calculate the product of a signed double-max
+ * precision integer (multiplier) and a signed
* max precision integer (multiplicand)
*
* `libj2_j2u_mul_ju_to_overflow(a, b)` implements
@@ -176,8 +176,8 @@ libj2_j2u_mul_ju_overflow(struct libj2_j2u *a, uintmax_t b)
/**
- * Calculate the product of an unsigned double-max
- * precision integer (multiplier) and an unsigned
+ * Calculate the product of a signed double-max
+ * precision integer (multiplier) and a signed
* max precision integer (multiplicand)
*
* `libj2_j2u_mul_ju_to_j2u_overflow(a, b, res)`
@@ -201,8 +201,8 @@ libj2_j2u_mul_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct
/**
- * Calculate the product of an unsigned max
- * precision integer (multiplier) and an unsigned
+ * Calculate the product of a signed max
+ * precision integer (multiplier) and a signed
* double-max precision integer (multiplicand)
*
* `libj2_ju_mul_j2u_to_j2u_overflow(a, b, res)`
@@ -400,11 +400,11 @@ libj2_j2u_mul_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_
* @param b The multiplicand
* @return `LIBJ2_OVERFLOW` (= 1) if the multiplication would overflow,
* `LIBJ2_NO_OVERFLOW` (= 0) if the multiplication would not overflow,
- * or `LIBJ2_OVERFLOW_UNKNOWN` if the prediction was not made
+ * or `LIBJ2_OVERFLOW_UNKNOWN` (= +2) if the prediction was not made
*
* @since 1.0
*/
-inline enum libj2_overflow
+LIBJ2_PURE_ inline enum libj2_overflow
libj2_j2u_mul_j2u_overflow_p_quick(const struct libj2_j2u *a, const struct libj2_j2u *b)
{
unsigned lz;
@@ -434,11 +434,11 @@ libj2_j2u_mul_j2u_overflow_p_quick(const struct libj2_j2u *a, const struct libj2
* @param b The multiplicand
* @return `LIBJ2_OVERFLOW` (= 1) if the multiplication would overflow,
* `LIBJ2_NO_OVERFLOW` (= 0) if the multiplication would not overflow,
- * or `LIBJ2_OVERFLOW_UNKNOWN` if the prediction was not made
+ * or `LIBJ2_OVERFLOW_UNKNOWN` (= +2) if the prediction was not made
*
* @since 1.0
*/
-inline enum libj2_overflow
+LIBJ2_PURE_ inline enum libj2_overflow
libj2_j2u_mul_ju_overflow_p_quick(const struct libj2_j2u *a, uintmax_t b)
{
return libj2_j2u_mul_j2u_overflow_p_quick(a, &(struct libj2_j2u){.high = 0, .low = b});
@@ -453,11 +453,11 @@ libj2_j2u_mul_ju_overflow_p_quick(const struct libj2_j2u *a, uintmax_t b)
* @param b The multiplicand
* @return `LIBJ2_OVERFLOW` (= 1) if the multiplication would overflow,
* `LIBJ2_NO_OVERFLOW` (= 0) if the multiplication would not overflow,
- * or `LIBJ2_OVERFLOW_UNKNOWN` if the prediction was not made
+ * or `LIBJ2_OVERFLOW_UNKNOWN` (= +2) if the prediction was not made
*
* @since 1.0
*/
-inline enum libj2_overflow
+LIBJ2_PURE_ inline enum libj2_overflow
libj2_ju_mul_j2u_overflow_p_quick(uintmax_t a, const struct libj2_j2u *b)
{
return libj2_j2u_mul_ju_overflow_p_quick(b, a);
@@ -479,7 +479,7 @@ libj2_ju_mul_j2u_overflow_p_quick(uintmax_t a, const struct libj2_j2u *b)
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_j2u_mul_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b)
{
enum libj2_overflow overflow;
@@ -527,7 +527,7 @@ libj2_j2u_mul_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_j2u_mul_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b)
{
return libj2_j2u_mul_j2u_overflow_p(a, &(struct libj2_j2u){.high = 0, .low = b});
@@ -548,7 +548,7 @@ libj2_j2u_mul_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b)
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_ju_mul_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b)
{
return libj2_j2u_mul_ju_overflow_p(b, a);
@@ -643,3 +643,556 @@ libj2_ju_mul_j2u_to_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b, struc
{
return libj2_j2u_mul_ju_to_j2u_overflow_p(b, a, res, res_set);
}
+
+
+
+
+
+/**
+ * Calculate the product of two signed double-max
+ * precision integers
+ *
+ * `libj2_j2i_mul_j2i_overflow(a, b)` implements
+ * `*a *= *b` with overflow-detection
+ *
+ * @param a The multiplier, also used as the
+ * output parameter for the product
+ * @param b The multiplicand
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_mul_j2i_overflow(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ struct libj2_j2u t;
+ int overflow, neg = libj2_j2i_is_negative(a);
+ if (neg)
+ libj2_minus_j2i(a);
+ if (a == b) {
+ neg = 0;
+ } else if (libj2_j2i_is_negative(b)) {
+ neg ^= 1;
+ libj2_minus_j2i_to_j2u(b, &t);
+ b = (const void *)&t;
+ }
+ overflow = libj2_j2u_mul_j2u_overflow((void *)a, (const void *)b);
+ if (neg) {
+ if (overflow)
+ overflow = -overflow;
+ else if (libj2_j2i_is_min(a))
+ return 0;
+ else if (libj2_j2i_is_negative(a))
+ overflow = -1;
+ libj2_minus_j2i(a);
+ } else if (!overflow) {
+ overflow = libj2_j2i_is_negative(a);
+ }
+ return overflow;
+}
+
+
+/**
+ * Calculate the product of two signed double-max
+ * precision integers
+ *
+ * `libj2_j2i_mul_j2i_to_j2i_overflow(a, b, res)`
+ * implements `*res = *a * *b` with overflow-detection
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_mul_j2i_to_j2i_overflow(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ if (a == res) {
+ return libj2_j2i_mul_j2i_overflow(res, b);
+ } else if (b == res) {
+ return libj2_j2i_mul_j2i_overflow(res, a);
+ } else {
+ *res = *a;
+ return libj2_j2i_mul_j2i_overflow(res, b);
+ }
+}
+
+
+/**
+ * Predict whether `libj2_j2i_mul_j2i_overflow_destructive`
+ * `libj2_j2i_mul_j2i_overflow`, or `libj2_j2i_mul_j2i_to_j2i_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_j2i_mul_j2i_overflow_p(a, b)` implements
+ * `libj2_j2i_mul_j2i_to_j2i_overflow(a, b, &(struct libj2_j2i){})`
+ * in an efficient manner for most cases
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @return +1 if the multiplication would overflow positively,
+ * -1 if the multiplication would overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline int
+libj2_j2i_mul_j2i_overflow_p(const struct libj2_j2i *a, const struct libj2_j2i *b) /* TODO optimised impl */
+{
+ return libj2_j2i_mul_j2i_to_j2i_overflow(a, b, &(struct libj2_j2i){0, 0});
+}
+
+
+/**
+ * Variant of `libj2_j2i_mul_j2i_overflow_p` that
+ * that stops the overflow-prediction is costly
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @return `LIBJ2_POSITIVE_OVERFLOW` (= +1) if the
+ * multiplication would overflow positively,
+ * `LIBJ2_NEGATIVE_OVERFLOW` (= -1) if the
+ * multiplication would overflow negatively,
+ * `LIBJ2_NO_OVERFLOW` (= 0) if the multiplication
+ * would not overflow,
+ * `LIBJ2_POSITIVE_OVERFLOW_UNKNOWN` (= +2)
+ * if the prediction was not made but the
+ * multiplication could overflow positively, or
+ * `LIBJ2_NEGATIVE_OVERFLOW_UNKNOWN` (= -2)
+ * if the prediction was not made but the
+ * multiplication could overflow negatively
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline enum libj2_overflow
+libj2_j2i_mul_j2i_overflow_p_quick(const struct libj2_j2i *a, const struct libj2_j2i *b) /* TODO optimised impl */
+{
+ int ret = libj2_j2i_mul_j2i_to_j2i_overflow(a, b, &(struct libj2_j2i){0, 0});
+ return (enum libj2_overflow)ret;
+}
+
+
+/**
+ * Variant of `libj2_j2i_mul_j2i_overflow_p` that
+ * that performs the multiplication if the
+ * overflow-prediction is costly
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ * @param res_set Output parameter for whether `*res` is set,
+ * if set to 1 when the function returns,
+ * `*res` will be set to the product,
+ * if set to 0 when the function returns,
+ * `*res` will be unmodified;
+ * will never be set to any other value
+ * @return +1 if the multiplication would or did overflow positively,
+ * -1 if the multiplication would or did overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_mul_j2i_to_j2i_overflow_p(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res, int *res_set) /* TODO optimised impl */
+{
+ *res_set = 1;
+ return libj2_j2i_mul_j2i_to_j2i_overflow(a, b, res);
+}
+
+
+/**
+ * Calculate the signed double-max precision integer
+ * product of two signed max precision integers
+ *
+ * `libj2_ji_mul_ji_to_j2i(a, b, res)` implements
+ * `*res = a * b`, where `a` and `b` are converted
+ * into `struct libj2_j2i`'s
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ *
+ * @since 1.1
+ */
+inline void
+libj2_ji_mul_ji_to_j2i(intmax_t a, intmax_t b, struct libj2_j2i *res)
+{
+ int neg = (a < 0) ^ (b < 0);
+ libj2_ju_mul_ju_to_j2u((uintmax_t)(a < 0 ? -a : a), (uintmax_t)(b < 0 ? -b : b), (void *)res);
+ if (neg)
+ libj2_minus_j2i(res);
+}
+
+
+/**
+ * Calculate the product of a signed double-max
+ * precision integer (multiplier) and a signed
+ * max precision integer (multiplicand)
+ *
+ * `libj2_j2i_mul_ji_to_j2i(a, b)` implements `*a *= b`,
+ * where `b` are converted into an `struct libj2_j2i`
+ *
+ * @param a The multiplier, also used as the
+ * output parameter for the product
+ * @param b The multiplicand
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_mul_ji(struct libj2_j2i *a, intmax_t b)
+{
+ int neg = libj2_j2i_is_negative(a);
+ if (neg)
+ libj2_minus_j2i(a);
+ if (b < 0) {
+ neg ^= 1;
+ b = -b;
+ }
+ libj2_j2u_mul_ju((void *)a, (uintmax_t)b);
+ if (neg)
+ libj2_minus_j2i(a);
+}
+
+
+/**
+ * Calculate the product of a signed double-max
+ * precision integer (multiplier) and a signed
+ * max precision integer (multiplicand)
+ *
+ * `libj2_j2i_mul_ji_to_j2i(a, b, res)` implements
+ * `*res = *a * b`, where `b` are converted into
+ * an `struct libj2_j2i`
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_mul_ji_to_j2i(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res)
+{
+ *res = *a;
+ libj2_j2i_mul_ji(res, b);
+}
+
+
+/**
+ * Calculate the product of a signed max
+ * precision integer (multiplier) and a signed
+ * double-max precision integer (multiplicand)
+ *
+ * `libj2_ji_mul_j2i_to_j2i(a, b, res)` implements
+ * `*res = a * *b`, where `a` are converted into
+ * an `struct libj2_j2i`
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ *
+ * @since 1.1
+ */
+inline void
+libj2_ji_mul_j2i_to_j2i(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ libj2_j2i_mul_ji_to_j2i(b, a, res);
+}
+
+
+/**
+ * Calculate the product of a signed double-max
+ * precision integer (multiplier) and a signed
+ * max precision integer (multiplicand)
+ *
+ * `libj2_j2i_mul_ji_to_overflow(a, b)` implements
+ * `*a *= b`, where `b` are converted into an
+ * `struct libj2_j2i`, with overflow-detection
+ *
+ * @param a The multiplier, also used as the
+ * output parameter for the product
+ * @param b The multiplicand
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_mul_ji_overflow(struct libj2_j2i *a, intmax_t b)
+{
+ struct libj2_j2i t;
+ libj2_ji_to_j2i(b, &t);
+ return libj2_j2i_mul_j2i_overflow(a, &t);
+}
+
+
+/**
+ * Calculate the product of a signed double-max
+ * precision integer (multiplier) and a signed
+ * max precision integer (multiplicand)
+ *
+ * `libj2_j2i_mul_ji_to_j2i_overflow(a, b, res)`
+ * implements `*res = *a * b`, where `b` are
+ * converted into an `struct libj2_j2i`, with
+ * overflow-detection
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_mul_ji_to_j2i_overflow(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res)
+{
+ struct libj2_j2i t;
+ libj2_ji_to_j2i(b, &t);
+ return libj2_j2i_mul_j2i_to_j2i_overflow(a, &t, res);
+}
+
+
+/**
+ * Calculate the product of a signed max
+ * precision integer (multiplier) and a signed
+ * double-max precision integer (multiplicand)
+ *
+ * `libj2_ji_mul_j2i_to_j2i_overflow(a, b, res)`
+ * implements `*res = a * *b`, where `a` are
+ * converted into an `struct libj2_j2i`, with
+ * overflow-detection
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_ji_mul_j2i_to_j2i_overflow(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ return libj2_j2i_mul_ji_to_j2i_overflow(b, a, res);
+}
+
+
+/**
+ * Calculate the product of two signed double-max
+ * precision integers
+ *
+ * `libj2_j2i_mul_j2i(a, b)` implements `*a *= *b`
+ *
+ * @param a The multiplier, also used as the
+ * output parameter for the product
+ * @param b The multiplicand
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_mul_j2i(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ struct libj2_j2u t;
+ int neg = libj2_j2i_is_negative(a);
+ if (neg)
+ libj2_minus_j2i(a);
+ if (a == b) {
+ neg = 0;
+ } else if (libj2_j2i_is_negative(b)) {
+ neg ^= 1;
+ libj2_minus_j2i_to_j2u(b, &t);
+ b = (const void *)&t;
+ }
+ libj2_j2u_mul_j2u((void *)a, (const void *)b);
+ if (neg)
+ libj2_minus_j2i(a);
+}
+
+
+/**
+ * Calculate the product of two signed double-max
+ * precision integers
+ *
+ * `libj2_j2i_mul_j2i_to_j2i(a, b, res)`
+ * implements `*res = *a * *b`
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_mul_j2i_to_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ if (a == res) {
+ common:
+ libj2_j2i_mul_j2i(res, b);
+ } else if (b == res) {
+ b = a;
+ goto common;
+ } else if (a == b) {
+ if (libj2_j2i_is_negative(a)) {
+ libj2_minus_j2i_to_j2u(a, (void *)res);
+ libj2_j2u_mul_j2u((void *)res, (const void *)res);
+ } else {
+ libj2_j2u_mul_j2u_to_j2u((const void *)a, (const void *)b, (void *)res);
+ }
+ } else {
+ *res = *a;
+ goto common;
+ }
+}
+
+
+/**
+ * Variant of `libj2_j2i_mul_ji_overflow_p` that
+ * that stops the overflow-prediction is costly
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @return `LIBJ2_OVERFLOW` (= 1) if the multiplication would overflow,
+ * `LIBJ2_NO_OVERFLOW` (= 0) if the multiplication would not overflow,
+ * or `LIBJ2_OVERFLOW_UNKNOWN` (= +2) if the prediction was not made
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline enum libj2_overflow
+libj2_j2i_mul_ji_overflow_p_quick(const struct libj2_j2i *a, intmax_t b)
+{
+ struct libj2_j2i t;
+ libj2_ji_to_j2i(b, &t);
+ return libj2_j2i_mul_j2i_overflow_p_quick(a, &t);
+}
+
+
+/**
+ * Variant of `libj2_ji_mul_j2i_overflow_p` that
+ * that stops the overflow-prediction is costly
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @return `LIBJ2_OVERFLOW` (= 1) if the multiplication would overflow,
+ * `LIBJ2_NO_OVERFLOW` (= 0) if the multiplication would not overflow,
+ * or `LIBJ2_OVERFLOW_UNKNOWN` (= +2) if the prediction was not made
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline enum libj2_overflow
+libj2_ji_mul_j2i_overflow_p_quick(intmax_t a, const struct libj2_j2i *b)
+{
+ return libj2_j2i_mul_ji_overflow_p_quick(b, a);
+}
+
+
+/**
+ * Predict whether `libj2_j2i_mul_ji_overflow`
+ * or `libj2_j2i_mul_ji_to_j2i_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_j2i_mul_ji_overflow_p(a, b)` implements
+ * `libj2_j2i_mul_ji_to_j2i_overflow(a, b, &(struct libj2_j2i){})`
+ * in an efficient manner for most cases
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @return +1 if the multiplication would overflow positively,
+ * -1 if the multiplication would overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline int
+libj2_j2i_mul_ji_overflow_p(const struct libj2_j2i *a, intmax_t b)
+{
+ struct libj2_j2i t;
+ libj2_ji_to_j2i(b, &t);
+ return libj2_j2i_mul_j2i_overflow_p(a, &t);
+}
+
+
+/**
+ * Predict whether `libj2_ji_mul_j2i_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_ji_mul_j2i_overflow_p(a, b)` implements
+ * `libj2_ji_mul_j2i(&(struct libj2_j2i){.high = a->high, .low = a->low}, b)`
+ * in an efficient manner for most cases
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @return +1 if the multiplication would overflow positively,
+ * -1 if the multiplication would overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline int
+libj2_ji_mul_j2i_overflow_p(intmax_t a, const struct libj2_j2i *b)
+{
+ return libj2_j2i_mul_ji_overflow_p(b, a);
+}
+
+
+/**
+ * Variant of `libj2_j2i_mul_ji_overflow_p` that
+ * that performs the multiplication if the
+ * overflow-prediction is costly
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ * @param res_set Output parameter for whether `*res` is set,
+ * if set to 1 when the function returns,
+ * `*res` will be set to the product,
+ * if set to 0 when the function returns,
+ * `*res` will be unmodified;
+ * will never be set to any other value
+ * @return +1 if the multiplication would or did overflow positively,
+ * -1 if the multiplication would or did overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_mul_ji_to_j2i_overflow_p(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res, int *res_set)
+{
+ struct libj2_j2i t;
+ libj2_ji_to_j2i(b, &t);
+ return libj2_j2i_mul_j2i_to_j2i_overflow_p(a, &t, res, res_set);
+}
+
+
+/**
+ * Variant of `libj2_ji_mul_j2i_overflow_p` that
+ * that performs the multiplication if the
+ * overflow-prediction is costly
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ * @param res_set Output parameter for whether `*res` is set,
+ * if set to 1 when the function returns,
+ * `*res` will be set to the product,
+ * if set to 0 when the function returns,
+ * `*res` will be unmodified;
+ * will never be set to any other value
+ * @return +1 if the multiplication would or did overflow positively,
+ * -1 if the multiplication would or did overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_ji_mul_j2i_to_j2i_overflow_p(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res, int *res_set)
+{
+ return libj2_j2i_mul_ji_to_j2i_overflow_p(b, a, res, res_set);
+}
diff --git a/libj2/subtraction.h b/libj2/subtraction.h
index 5d4ee2e..de4a225 100644
--- a/libj2/subtraction.h
+++ b/libj2/subtraction.h
@@ -388,9 +388,9 @@ libj2_ju_sub_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct
* `libj2_j2u_rsub_j2u(a, b, res)` implements
* `*a = *b - *a`
*
- * @param a The subtrahend (right-hand), also used as
- * the output parameter for the difference
- * @param b The minuend (left-hand)
+ * @param a The subtrahend (right-hand), also used as
+ * the output parameter for the difference
+ * @param b The minuend (left-hand)
*
* @since 1.0
*/
@@ -526,7 +526,7 @@ libj2_j2u_rsub_ju_overflow(struct libj2_j2u *a, uintmax_t b)
/**
- * Predict whether `libj2_j2u_sub_ju_to_j2u_overflow`
+ * Predict whether `libj2_j2u_sub_ju_to_j2u_overflow`
* or `libj2_j2u_sub_ju_overflow` will return a
* result-overflow signal
*
@@ -540,7 +540,7 @@ libj2_j2u_rsub_ju_overflow(struct libj2_j2u *a, uintmax_t b)
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_j2u_sub_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b)
{
return a->low < b && !a->high;
@@ -548,7 +548,7 @@ libj2_j2u_sub_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b)
/**
- * Predict whether `libj2_ju_sub_j2u_to_j2u_overflow`
+ * Predict whether `libj2_ju_sub_j2u_to_j2u_overflow`
* will return a result-overflow signal
*
* `libj2_ju_sub_j2u_overflow_p(a, b)` implements
@@ -561,7 +561,7 @@ libj2_j2u_sub_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b)
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_ju_sub_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b)
{
return b->high || b->low > a;
@@ -569,7 +569,7 @@ libj2_ju_sub_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b)
/**
- * Predict whether `libj2_ju_sub_ju_to_j2u_overflow`
+ * Predict whether `libj2_ju_sub_ju_to_j2u_overflow`
* will return a result-overflow signal
*
* `libj2_ju_sub_ju_overflow_p(a, b)` implements
@@ -582,7 +582,7 @@ libj2_ju_sub_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b)
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_ju_sub_ju_overflow_p(uintmax_t a, uintmax_t b)
{
return a < b;
@@ -590,7 +590,7 @@ libj2_ju_sub_ju_overflow_p(uintmax_t a, uintmax_t b)
/**
- * Predict whether `libj2_j2u_sub_j2u_to_j2u_overflow`
+ * Predict whether `libj2_j2u_sub_j2u_to_j2u_overflow`
* or `libj2_j2u_sub_j2u_overflow` will return a
* result-overflow signal
*
@@ -604,7 +604,7 @@ libj2_ju_sub_ju_overflow_p(uintmax_t a, uintmax_t b)
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_j2u_sub_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b)
{
return libj2_j2u_sub_ju_overflow_p(a, b->low) || a->high < b->high;
@@ -625,7 +625,7 @@ libj2_j2u_sub_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_j2u_rsub_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b)
{
return libj2_j2u_sub_j2u_overflow_p(b, a);
@@ -646,8 +646,497 @@ libj2_j2u_rsub_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u
*
* @since 1.0
*/
-inline int
+LIBJ2_PURE_ inline int
libj2_j2u_rsub_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b)
{
return libj2_ju_sub_j2u_overflow_p(b, a);
}
+
+
+
+
+
+/**
+ * Calculate the difference between two signed
+ * double-max precision integers
+ *
+ * `libj2_j2i_sub_j2i_to_j2i(a, b, res)` implements
+ * `*res = *a - *b`
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @param res Output parameter for the difference
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_sub_j2i_to_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ libj2_j2u_sub_j2u_to_j2u((const void *)a, (const void *)b, (void *)res);
+}
+
+
+/**
+ * Calculate the difference between a signed
+ * double-max precision integer (minuend) and a
+ * signed max precision integer (subtrahend)
+ *
+ * `libj2_j2i_sub_ji_to_j2i(a, b, res)`
+ * implements `*res = *a - b`
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @param res Output parameter for the difference
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_sub_ji_to_j2i(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res)
+{
+ struct libj2_j2i t;
+ libj2_ji_to_j2i(b, &t);
+ libj2_j2i_sub_j2i_to_j2i(a, &t, res);
+}
+
+
+/**
+ * Calculate the difference between a signed
+ * max precision integer (minuend) and a signed
+ * double-max precision integer (subtrahend)
+ *
+ * `libj2_ji_sub_j2i_to_j2i(a, b, res)`
+ * implements `*res = a - *b`
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @param res Output parameter for the difference
+ *
+ * @since 1.1
+ */
+inline void
+libj2_ji_sub_j2i_to_j2i(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ struct libj2_j2i t;
+ libj2_ji_to_j2i(a, &t);
+ libj2_j2i_sub_j2i_to_j2i(&t, b, res);
+}
+
+
+/**
+ * Calculate the difference between two signed
+ * max precision integers, as a signed double-max
+ * precision integer
+ *
+ * `libj2_ji_sub_ji_to_j2i(a, b, res)`
+ * implements `*res = a - b`, where `a` and `b`
+ * are converted into `struct libj2_j2i`'s
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @param res Output parameter for the difference
+ *
+ * @since 1.1
+ */
+inline void
+libj2_ji_sub_ji_to_j2i(intmax_t a, intmax_t b, struct libj2_j2i *res)
+{
+ struct libj2_j2i s, t;
+ libj2_ji_to_j2i(a, &s);
+ libj2_ji_to_j2i(b, &t);
+ libj2_j2i_sub_j2i_to_j2i(&s, &t, res);
+}
+
+
+/**
+ * Calculate the difference between two signed
+ * double-max precision integers
+ *
+ * `libj2_j2i_sub_j2i(a, b)` implements `*a -= *b`
+ *
+ * @param a The minuend (left-hand), also used
+ * as the output parameter for the difference
+ * @param b The subtrahend (right-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_sub_j2i(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ libj2_j2u_sub_j2u((void *)a, (const void *)b);
+}
+
+
+/**
+ * Calculate the difference between a signed
+ * double-max precision integer (minuend) and a
+ * signed max precision integer (subtrahend)
+ *
+ * `libj2_j2i_sub_ji(a, b)` implements `*a -= b`
+ *
+ * @param a The minuend (left-hand), also used as the
+ * output parameter for the difference
+ * @param b The subtrahend (right-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_sub_ji(struct libj2_j2i *a, intmax_t b)
+{
+ struct libj2_j2i t;
+ libj2_ji_to_j2i(b, &t);
+ libj2_j2i_sub_j2i(a, &t);
+}
+
+
+/**
+ * Predict whether `libj2_j2i_sub_j2i_to_j2i_overflow`
+ * or `libj2_j2i_sub_j2i_overflow` will return a
+ * result-overflow signal
+ *
+ * `libj2_j2i_sub_j2i_overflow_p(a, b)` implements
+ * `libj2_j2i_sub_j2i_to_j2i_overflow(a, b, &(struct libj2_j2i){})`
+ * in an efficient manner
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @return +1 if the subtraction would overflow positively,
+ * -1 if the subtraction would overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline int
+libj2_j2i_sub_j2i_overflow_p(const struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ if (libj2_j2i_is_negative(a)) {
+ if (!libj2_j2i_is_positive(b))
+ return 0;
+ return a->high - b->high - (uintmax_t)(a->low < b->low) <= (uintmax_t)INTMAX_MAX ? -1 : 0;
+ } else {
+ if (!libj2_j2i_is_negative(b))
+ return 0;
+ return a->high - b->high - (uintmax_t)(a->low < b->low) > (uintmax_t)INTMAX_MAX;
+ }
+}
+
+
+/**
+ * Predict whether `libj2_j2i_sub_ji_to_j2i_overflow`
+ * or `libj2_j2i_sub_ji_overflow` will return a
+ * result-overflow signal
+ *
+ * `libj2_j2i_sub_ji_overflow_p(a, b)` implements
+ * `libj2_j2i_sub_ji_to_j2i_overflow(a, b, &(struct libj2_j2i){})`
+ * in an efficient manner
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @return +1 if the subtraction would overflow positively,
+ * -1 if the subtraction would overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline int
+libj2_j2i_sub_ji_overflow_p(const struct libj2_j2i *a, intmax_t b)
+{
+ struct libj2_j2i t;
+ libj2_ji_to_j2i(b, &t);
+ return libj2_j2i_sub_j2i_overflow_p(a, &t);
+}
+
+
+/**
+ * Predict whether `libj2_ji_sub_j2i_to_j2i_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_ji_sub_j2i_overflow_p(a, b)` implements
+ * `libj2_ji_sub_j2i_to_j2i_overflow(a, b, &(struct libj2_j2i){})`
+ * in an efficient manner
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @return +1 if the subtraction would overflow positively,
+ * -1 if the subtraction would overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline int
+libj2_ji_sub_j2i_overflow_p(intmax_t a, const struct libj2_j2i *b)
+{
+ struct libj2_j2i t;
+ libj2_ji_to_j2i(a, &t);
+ return libj2_j2i_sub_j2i_overflow_p(&t, b);
+}
+
+
+/**
+ * Calculate the difference between two signed
+ * double-max precision integers
+ *
+ * `libj2_j2i_sub_j2i_to_j2i_overflow(a, b, res)`
+ * implements `*res = *a - *b` with overflow-detection
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @param res Output parameter for the difference
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_sub_j2i_to_j2i_overflow(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ int overflow = libj2_j2i_sub_j2i_overflow_p(a, b);
+ libj2_j2i_sub_j2i_to_j2i(a, b, res);
+ return overflow;
+}
+
+
+/**
+ * Calculate the difference between a signed
+ * double-max precision integer (minuend) and a
+ * signed max precision integer (subtrahend)
+ *
+ * `libj2_j2i_sub_ji_to_j2i_overflow(a, b, res)`
+ * implements `*res = *a - b` with overflow-detection
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @param res Output parameter for the difference
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_sub_ji_to_j2i_overflow(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res)
+{
+ struct libj2_j2i t;
+ libj2_ji_to_j2i(b, &t);
+ return libj2_j2i_sub_j2i_to_j2i_overflow(a, &t, res);
+}
+
+
+/**
+ * Calculate the difference between a signed
+ * max precision integer (minuend) and a signed
+ * double-max precision integer (subtrahend)
+ *
+ * `libj2_ji_sub_j2i_to_j2i_overflow(a, b, res)`
+ * implements `*res = a - *b` with overflow-detection
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @param res Output parameter for the difference
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_ji_sub_j2i_to_j2i_overflow(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ struct libj2_j2i t;
+ libj2_ji_to_j2i(a, &t);
+ return libj2_j2i_sub_j2i_to_j2i_overflow(&t, b, res);
+}
+
+
+/**
+ * Calculate the difference between two signed
+ * double-max precision integers
+ *
+ * `libj2_j2i_sub_j2i_overflow(a, b)`
+ * implements `*a -= *b` with overflow-detection
+ *
+ * @param a The minuend (left-hand), also used
+ * as the output parameter for the difference
+ * @param b The subtrahend (right-hand)
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_sub_j2i_overflow(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ return libj2_j2i_sub_j2i_to_j2i_overflow(a, b, a);
+}
+
+
+/**
+ * Calculate the difference between a signed
+ * double-max precision integer (minuend) and a
+ * signed max precision integer (subtrahend)
+ *
+ * `libj2_j2i_sub_ji_overflow(a, b)` implements
+ * `*a -= b` with overflow-detection
+ *
+ * @param a The minuend (left-hand), also used as the
+ * output parameter for the difference
+ * @param b The subtrahend (right-hand)
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_sub_ji_overflow(struct libj2_j2i *a, intmax_t b)
+{
+ return libj2_j2i_sub_ji_to_j2i_overflow(a, b, a);
+}
+
+
+/**
+ * Calculate the difference between two signed
+ * max precision integers; in this variant of
+ * `libj2_j2i_sub_j2i`, the minuend (left-hand)
+ * is the second parameter and the subtrahend
+ * (right-hand) is the first parameter
+ *
+ * `libj2_j2i_rsub_j2i(a, b, res)` implements
+ * `*a = *b - *a`
+ *
+ * @param a The subtrahend (right-hand), also used as
+ * the output parameter for the difference
+ * @param b The minuend (left-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_rsub_j2i(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ libj2_j2i_sub_j2i_to_j2i(b, a, a);
+}
+
+
+/**
+ * Calculate the difference between a signed
+ * max precision integer (minuend) and a signed
+ * double-max precision integer (subtrahend);
+ * in this variant of `libj2_j2i_sub_ji`, the
+ * minuend (left-hand) is the second parameter
+ * and the subtrahend (right-hand) is the first
+ * parameter
+ *
+ * `libj2_j2i_rsub_ji(a, b, res)` implements `*a = b - *a`
+ *
+ * @param a The subtrahend (right-hand), also used as
+ * the output parameter for the difference
+ * @param b The minuend (left-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_rsub_ji(struct libj2_j2i *a, intmax_t b)
+{
+ libj2_ji_sub_j2i_to_j2i(b, a, a);
+}
+
+
+/**
+ * Calculate the difference between two signed
+ * max precision integers; in this variant of
+ * `libj2_j2i_sub_j2i`, the minuend (left-hand)
+ * is the second parameter and the subtrahend
+ * (right-hand) is the first parameter
+ *
+ * `libj2_j2i_rsub_j2i_overflow(a, b, res)`
+ * implements `*a = *b - *a` with overflow-detection
+ *
+ * @param a The subtrahend (right-hand), also used as
+ * the output parameter for the difference
+ * @param b The minuend (left-hand)
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_rsub_j2i_overflow(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ return libj2_j2i_sub_j2i_to_j2i_overflow(b, a, a);
+}
+
+
+/**
+ * Calculate the difference between a signed
+ * max precision integer (minuend) and a signed
+ * double-max precision integer (subtrahend);
+ * in this variant of `libj2_j2i_sub_ji`, the
+ * minuend (left-hand) is the second parameter
+ * and the subtrahend (right-hand) is the first
+ * parameter
+ *
+ * `libj2_j2i_rsub_ji_overflow(a, b, res)`
+ * implements `*a = b - *a` with overflow-detection
+ *
+ * @param a The subtrahend (right-hand), also used as
+ * the output parameter for the difference
+ * @param b The minuend (left-hand)
+ * @return +1 on positive overflow,
+ * -1 on negative overflow,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+inline int
+libj2_j2i_rsub_ji_overflow(struct libj2_j2i *a, intmax_t b)
+{
+ return libj2_ji_sub_j2i_to_j2i_overflow(b, a, a);
+}
+
+
+/**
+ * Predict whether `libj2_j2i_rsub_j2i_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_j2i_rsub_j2i_overflow_p(a, b)` implements
+ * `libj2_j2i_rsub_j2i_overflow(&(struct libj2_j2i){.high = a->high, .low = a->low}, b)`
+ * in an efficient manner
+ *
+ * @param a The subtrahend (right-hand)
+ * @param b The minuend (left-hand)
+ * @return +1 if the subtraction would overflow positively,
+ * -1 if the subtraction would overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline int
+libj2_j2i_rsub_j2i_overflow_p(const struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ return libj2_j2i_sub_j2i_overflow_p(b, a);
+}
+
+
+/**
+ * Predict whether `libj2_j2i_rsub_ji_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_j2i_rsub_ji_overflow_p(a, b)` implements
+ * `libj2_j2i_rsub_ji_overflow(&(struct libj2_j2i){.high = a->high, .low = a->low}, b)`
+ * in an efficient manner
+ *
+ * @param a The subtrahend (right-hand)
+ * @param b The minuend (left-hand)
+ * @return +1 if the subtraction would overflow positively,
+ * -1 if the subtraction would overflow negatively,
+ * 0 otherwise
+ *
+ * @since 1.1
+ */
+LIBJ2_PURE_ inline int
+libj2_j2i_rsub_ji_overflow_p(const struct libj2_j2i *a, intmax_t b)
+{
+ return libj2_ji_sub_j2i_overflow_p(b, a);
+}
diff --git a/libj2_j2i_add_j2i.c b/libj2_j2i_add_j2i.c
new file mode 100644
index 0000000..f1889d8
--- /dev/null
+++ b/libj2_j2i_add_j2i.c
@@ -0,0 +1,341 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_add_j2i(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#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_(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;
+
+ 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};
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i(&a, &b);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ r = (struct libj2_j2i){111, 222};
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_to_j2i(&a, &b, &r);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_to_j2i(&a, &b, &a);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_add_j2i_to_j2i(&a, &b, &b);
+ EXPECT(libj2_j2i_eq_j2i(&b, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2i_add_j2i_overflow(&a, &b) == r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+#if 0 /* TODO saturated addition */
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_sat_add_j2i(&a, &b);
+ EXPECT(r_overflow ? libj2_j2i_is_max(&a) : libj2_j2i_eq_j2i(&a, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+#endif
+
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2i_add_j2i_overflow_p((const struct libj2_j2i *)&a, (const struct libj2_j2i *)&b) == r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ r = (struct libj2_j2i){111, 222};
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2i_add_j2i_to_j2i_overflow(&a, &b, &r) == 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));
+
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2i_add_j2i_to_j2i_overflow(&a, &b, &a) == r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2i_add_j2i_to_j2i_overflow(&a, &b, &b) == r_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&b, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+#if 0 /* TODO saturated addition */
+ r = (struct libj2_j2i){111, 222};
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_sat_add_j2i_to_j2i(&a, &b, &r);
+ EXPECT(r_overflow ? libj2_j2i_is_max(&r) : libj2_j2i_eq_j2i(&r, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_sat_add_j2i_to_j2i(&a, &b, &a);
+ EXPECT(r_overflow ? libj2_j2i_is_max(&a) : libj2_j2i_eq_j2i(&a, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2i_sat_add_j2i_to_j2i(&a, &b, &b);
+ EXPECT(r_overflow ? libj2_j2i_is_max(&b) : libj2_j2i_eq_j2i(&b, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+#endif
+}
+
+
+static void
+check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low)
+{
+ uintmax_t a_neg = a_high >> (LIBJ2_JU_BIT - 1U);
+ uintmax_t b_neg = b_high >> (LIBJ2_JU_BIT - 1U);
+ uintmax_t r_high = 0, r_low = 0, carry = 0;
+ int r_overflow = 0;
+ unsigned i;
+
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ carry += (a_low >> i) & 1U;
+ carry += (b_low >> i) & 1U;
+ r_low |= (carry & 1U) << i;
+ carry >>= 1;
+ }
+
+ for (i = 0; i < LIBJ2_JU_BIT - 1U; i++) {
+ carry += (a_high >> i) & 1U;
+ carry += (b_high >> i) & 1U;
+ r_high |= (carry & 1U) << i;
+ carry >>= 1;
+ }
+
+ carry += (a_high >> i) & 1U;
+ carry += (b_high >> i) & 1U;
+ r_high |= (carry & 1U) << i;
+ carry >>= 1;
+
+ if (a_neg)
+ carry ^= 1U;
+
+ if (a_neg ^ b_neg)
+ r_overflow = 0;
+ else if (a_neg)
+ r_overflow = -!(r_high >> (LIBJ2_JU_BIT - 1U));
+ else
+ r_overflow = !!(r_high >> (LIBJ2_JU_BIT - 1U));
+
+ check_(a_high, a_low, b_high, b_low, r_high, r_low, r_overflow);
+}
+
+
+static void
+check_manual(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)
+{
+ check_(a_high, a_low, b_high, b_low, r_high, r_low, r_overflow);
+ check(a_high, a_low, b_high, b_low);
+}
+
+
+static void
+check_double(uintmax_t high, uintmax_t low)
+{
+ struct libj2_j2i a, r, a_saved, expected, b;
+ 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));
+
+ expected_overflow ^= expected_overflow >> 1;
+ expected_overflow &= 1;
+
+ if (high >> (LIBJ2_JU_BIT - 1U))
+ expected_overflow = -expected_overflow;
+
+ a_saved = (struct libj2_j2i){.high = high, .low = low};
+ expected = (struct libj2_j2i){.high = expected_high, .low = expected_low};
+
+ a = a_saved;
+ b = a_saved;
+ libj2_j2i_add_j2i(&a, &b);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected));
+
+ a = a_saved;
+ libj2_j2i_add_j2i(&a, &a);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected));
+
+ r = (struct libj2_j2i){111, 222};
+ a = a_saved;
+ libj2_j2i_add_j2i_to_j2i(&a, &a, &r);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ a = a_saved;
+ libj2_j2i_add_j2i_to_j2i(&a, &a, &a);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected));
+
+ a = a_saved;
+ EXPECT(libj2_j2i_add_j2i_overflow(&a, &a) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected));
+
+#if 0 /* TODO saturated addition */
+ a = a_saved;
+ libj2_j2i_sat_add_j2i(&a, &a);
+ EXPECT(expected_overflow ? libj2_j2i_is_max(&a) : libj2_j2i_eq_j2i(&a, &expected));
+#endif
+
+ a = a_saved;
+ EXPECT(libj2_j2i_add_j2i_overflow_p((const struct libj2_j2i *)&a, (const struct libj2_j2i *)&a) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ r = (struct libj2_j2i){111, 222};
+ a = a_saved;
+ EXPECT(libj2_j2i_add_j2i_to_j2i_overflow(&a, &a, &r) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ a = a_saved;
+ EXPECT(libj2_j2i_add_j2i_to_j2i_overflow(&a, &a, &a) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &expected));
+
+#if 0 /* TODO saturated addition */
+ r = (struct libj2_j2i){111, 222};
+ a = a_saved;
+ libj2_j2i_sat_add_j2i_to_j2i(&a, &a, &r);
+ EXPECT(expected_overflow ? libj2_j2i_is_max(&r) : libj2_j2i_eq_j2i(&r, &expected));
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ a = a_saved;
+ libj2_j2i_sat_add_j2i_to_j2i(&a, &a, &a);
+ EXPECT(expected_overflow ? libj2_j2i_is_max(&a) : libj2_j2i_eq_j2i(&a, &expected));
+#endif
+}
+
+
+int
+main(void)
+{
+ uintmax_t a, b, c, d, max, min, umax, vs[12];
+ unsigned i, ii, ij, jj, k;
+
+ srand((unsigned)time(NULL));
+
+ umax = UINTMAX_MAX;
+ max = umax >> 1;
+ min = ~max;
+
+ vs[0] = 0U;
+ vs[1] = 1U;
+ vs[2] = 2U;
+ vs[3] = umax - 0U;
+ vs[4] = umax - 1U;
+ vs[5] = umax - 2U;
+ vs[6] = max - 0U;
+ vs[7] = max - 1U;
+ vs[8] = max - 2U;
+ vs[9] = min + 0U;
+ vs[10] = min + 1U;
+ vs[11] = min + 2U;
+
+ check_manual(0, 0, 0, 0, 0, 0, 0);
+ check_manual(0, 1, 0, 1, 0, 2, 0);
+ check_manual(0, UINTMAX_MAX, 0, 1, 1, 0, 0);
+ check_manual(0, UINTMAX_MAX, 0, UINTMAX_MAX, 1, UINTMAX_MAX - 1U, 0);
+ check_manual(UINTMAX_MAX >> 1, UINTMAX_MAX, UINTMAX_MAX >> 1, UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX - 1U, +1);
+ check_manual((UINTMAX_MAX >> 1) + 1U, 0, (UINTMAX_MAX >> 1) + 1U, 0, 0, 0, -1);
+
+ for (i = 0; i < 256; i++)
+ check(random_ju() >> 1, random_ju(), random_ju() >> 1, random_ju());
+
+ check_double(0, 0);
+ check_double(0, UINTMAX_MAX);
+ check_double(UINTMAX_MAX, UINTMAX_MAX);
+ check_double(UINTMAX_MAX, 0);
+ check_double(UINTMAX_MAX >> 1, 0);
+ check_double(UINTMAX_MAX >> 1, UINTMAX_MAX);
+ check_double((UINTMAX_MAX >> 1) + 1U, 0);
+ for (i = 0; i < 256; i++) {
+ check_double(0, random_ju());
+ check_double(random_ju(), 0);
+ check_double(random_ju(), UINTMAX_MAX);
+ check_double(random_ju(), random_ju());
+ check_double(UINTMAX_MAX >> 1, random_ju());
+ check_double(UINTMAX_MAX, random_ju());
+ check_double((UINTMAX_MAX >> 1) + 1U, random_ju());
+ }
+
+ check_manual((UINTMAX_MAX >> 1) - 1U, UINTMAX_MAX - 1U, 1, 1, UINTMAX_MAX >> 1, UINTMAX_MAX, 0);
+ check_manual((UINTMAX_MAX >> 1) - 1U, UINTMAX_MAX - 1U, 1, 2, ~(uintmax_t)INTMAX_MAX, 0, 1);
+ check_manual((UINTMAX_MAX >> 1) - 1U, UINTMAX_MAX - 1U, 1, 3, ~(uintmax_t)INTMAX_MAX, 1, 1);
+
+ for (k = 0; k < 16U; k++) {
+ a = random_ju() >> 1;
+ b = random_ju() >> 1;
+ c = random_ju() >> 1;
+ d = random_ju() >> 1;
+ if (k & 1U) a = ~a;
+ if (k & 2U) b = ~b;
+ if (k & 4U) c = ~c;
+ if (k & 8U) d = ~d;
+ check(a, b, c, d);
+ for (i = 0; k < 8U && i < 12U; i++) {
+ check(a, b, c, vs[i]);
+ check(a, b, vs[i], c);
+ check(a, vs[i], b, c);
+ check(vs[i], a, b, c);
+ for (ii = 0; k < 4U && ii < 12U; ii++) {
+ check(a, b, vs[i], vs[ii]);
+ check(a, vs[i], b, vs[ii]);
+ check(a, vs[i], vs[ii], b);
+ check(vs[i], a, b, vs[ii]);
+ check(vs[i], a, vs[ii], b);
+ check(vs[i], vs[ii], a, b);
+ for (ij = 0; k < 2U && ij < 12U; ij++) {
+ check(vs[i], vs[ii], vs[ij], a);
+ check(vs[i], vs[ii], a, vs[ij]);
+ check(vs[i], a, vs[ii], vs[ij]);
+ check(a, vs[i], vs[ii], vs[ij]);
+ for (jj = 0; k < 1U && jj < 12U; jj++)
+ check(vs[i], vs[ii], vs[ij], vs[jj]);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2i_add_j2i_overflow.c b/libj2_j2i_add_j2i_overflow.c
new file mode 100644
index 0000000..02464d8
--- /dev/null
+++ b/libj2_j2i_add_j2i_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_add_j2i_overflow(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_add_j2i.c */
+
+#endif
diff --git a/libj2_j2i_add_j2i_overflow_p.c b/libj2_j2i_add_j2i_overflow_p.c
new file mode 100644
index 0000000..3b703be
--- /dev/null
+++ b/libj2_j2i_add_j2i_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_add_j2i_overflow_p(const struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_add_j2i.c */
+
+#endif
diff --git a/libj2_j2i_add_j2i_to_j2i.c b/libj2_j2i_add_j2i_to_j2i.c
new file mode 100644
index 0000000..259f91e
--- /dev/null
+++ b/libj2_j2i_add_j2i_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_add_j2i_to_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_add_j2i.c */
+
+#endif
diff --git a/libj2_j2i_add_j2i_to_j2i_overflow.c b/libj2_j2i_add_j2i_to_j2i_overflow.c
new file mode 100644
index 0000000..b36ac10
--- /dev/null
+++ b/libj2_j2i_add_j2i_to_j2i_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_add_j2i_to_j2i_overflow(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_add_j2i.c */
+
+#endif
diff --git a/libj2_j2i_add_ji.c b/libj2_j2i_add_ji.c
new file mode 100644
index 0000000..97880e2
--- /dev/null
+++ b/libj2_j2i_add_ji.c
@@ -0,0 +1,253 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_add_ji(struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#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
+self_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)
+{
+ uintmax_t a_neg = a_high >> (LIBJ2_JU_BIT - 1U);
+ uintmax_t b_neg = b_high >> (LIBJ2_JU_BIT - 1U);
+ uintmax_t carry = 0;
+ unsigned i;
+ int overflow;
+
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ carry += (a_low >> i) & 1U;
+ carry += (b_low >> i) & 1U;
+ EXPECT((carry & 1U) == ((r_low >> i) & 1U));
+ carry >>= 1;
+ }
+
+ for (i = 0; i < LIBJ2_JU_BIT - 1U; i++) {
+ carry += (a_high >> i) & 1U;
+ carry += (b_high >> i) & 1U;
+ EXPECT((carry & 1U) == ((r_high >> i) & 1U));
+ carry >>= 1;
+ }
+
+ carry += (a_high >> i) & 1U;
+ carry += (b_high >> i) & 1U;
+ r_high |= (carry & 1U) << i;
+ carry >>= 1;
+
+ if (a_neg)
+ carry ^= 1U;
+
+ if (a_neg ^ b_neg)
+ overflow = 0;
+ else if (a_neg)
+ overflow = -!(r_high >> (LIBJ2_JU_BIT - 1U));
+ else
+ overflow = !!(r_high >> (LIBJ2_JU_BIT - 1U));
+
+ EXPECT(r_overflow == overflow);
+}
+
+
+static void
+check(uintmax_t a_high, uintmax_t a_low, uintmax_t ub)
+{
+ intmax_t b = ub > (uintmax_t)INTMAX_MAX ? (intmax_t)ub : -(intmax_t)~ub - 1;
+ struct libj2_j2i a, r;
+ uintmax_t expected_high, expected_low;
+ int expected_overflow;
+
+#if INTMAX_MIN + 1 != -INTMAX_MAX
+ if (ub == ~(UINTMAX_MAX >> 1))
+ return;
+#endif
+
+ expected_high = a_high + (uintmax_t)(a_low > UINTMAX_MAX - ub);
+ expected_low = a_low + ub;
+ if (b < 0)
+ expected_high += UINTMAX_MAX;
+ if (a_high >> (LIBJ2_JU_BIT - 1U) && b < 0)
+ expected_overflow = expected_high >> (LIBJ2_JU_BIT - 1U) ? 0 : -1;
+ else if (b < 0 || a_high >> (LIBJ2_JU_BIT - 1U))
+ expected_overflow = 0;
+ else
+ expected_overflow = expected_high >> (LIBJ2_JU_BIT - 1U) ? +1 : 0;
+
+ self_check(a_high, a_low, b < 0 ? UINTMAX_MAX : 0U, ub, expected_high, expected_low, expected_overflow);
+
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ libj2_j2i_add_ji(&a, b);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ EXPECT(libj2_j2i_add_ji_overflow(&a, b) == expected_overflow);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+#if 0 /* TODO saturated addition */
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ libj2_j2i_sat_add_ji(&a, b);
+ EXPECT(a.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(a.low == (expected_overflow ? UINTMAX_MAX : expected_low));
+#endif
+
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ EXPECT(libj2_j2i_add_ji_overflow_p((const struct libj2_j2i *)&a, b) == expected_overflow);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+
+ r = (struct libj2_j2i){111, 222};
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ libj2_j2i_add_ji_to_j2i(&a, b, &r);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ libj2_j2i_add_ji_to_j2i(&a, b, &a);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+ r = (struct libj2_j2i){111, 222};
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ EXPECT(libj2_j2i_add_ji_to_j2i_overflow(&a, b, &r) == expected_overflow);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ EXPECT(libj2_j2i_add_ji_to_j2i_overflow(&a, b, &a) == expected_overflow);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+#if 0 /* TODO saturated addition */
+ r = (struct libj2_j2i){111, 222};
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ libj2_j2i_sat_add_ji_to_j2i(&a, b, &r);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(r.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(r.low == (expected_overflow ? UINTMAX_MAX : expected_low));
+
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ libj2_j2i_sat_add_ji_to_j2i(&a, b, &a);
+ EXPECT(a.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(a.low == (expected_overflow ? UINTMAX_MAX : expected_low));
+#endif
+
+ r = (struct libj2_j2i){111, 222};
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ libj2_ji_add_j2i_to_j2i(b, &a, &r);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ libj2_ji_add_j2i_to_j2i(b, &a, &a);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+ r = (struct libj2_j2i){111, 222};
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ EXPECT(libj2_ji_add_j2i_to_j2i_overflow(b, &a, &r) == expected_overflow);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ EXPECT(libj2_ji_add_j2i_to_j2i_overflow(b, &a, &a) == expected_overflow);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+#if 0 /* TODO saturated addition */
+ r = (struct libj2_j2i){111, 222};
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ libj2_ji_sat_add_j2i_to_j2i(b, &a, &r);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(r.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(r.low == (expected_overflow ? UINTMAX_MAX : expected_low));
+
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ libj2_ji_sat_add_j2i_to_j2i(b, &a, &a);
+ EXPECT(a.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(a.low == (expected_overflow ? UINTMAX_MAX : expected_low));
+#endif
+
+ a = (struct libj2_j2i){.high = a_high, .low = a_low};
+ EXPECT(libj2_ji_add_j2i_overflow_p(b, (const struct libj2_j2i *)&a) == expected_overflow);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+}
+
+
+int
+main(void)
+{
+ uintmax_t a, b, c, max, min, umax, vs[12];
+ unsigned i, j, k;
+
+ srand((unsigned)time(NULL));
+
+ umax = UINTMAX_MAX;
+ max = umax >> 1;
+ min = ~max;
+
+ vs[0] = 0U;
+ vs[1] = 1U;
+ vs[2] = 2U;
+ vs[3] = umax - 0U;
+ vs[4] = umax - 1U;
+ vs[5] = umax - 2U;
+ vs[6] = max - 0U;
+ vs[7] = max - 1U;
+ vs[8] = max - 2U;
+ vs[9] = min + 0U;
+ vs[10] = min + 1U;
+ vs[11] = min + 2U;
+
+ for (i = 0; i < 12U; i++)
+ for (j = 0; j < 12U; j++)
+ for (k = 0; k < 12U; k++)
+ check(vs[i], vs[j], vs[k]);
+
+ for (k = 0; k < 256; k++) {
+ a = random_ju();
+ b = random_ju();
+ c = random_ju();
+ for (i = 0; i < 12U; i++) {
+ for (j = 0; j < 12U; j++) {
+ check(a, vs[i], vs[j]);
+ check(vs[i], a, vs[j]);
+ check(vs[i], vs[j], a);
+ }
+ check(a, b, vs[i]);
+ check(a, vs[i], b);
+ check(vs[i], a, b);
+ }
+ check(a, b, c);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2i_add_ji_overflow.c b/libj2_j2i_add_ji_overflow.c
new file mode 100644
index 0000000..1686ae4
--- /dev/null
+++ b/libj2_j2i_add_ji_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_add_ji_overflow(struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_add_ji.c */
+
+#endif
diff --git a/libj2_j2i_add_ji_overflow_p.c b/libj2_j2i_add_ji_overflow_p.c
new file mode 100644
index 0000000..76fff49
--- /dev/null
+++ b/libj2_j2i_add_ji_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_add_ji_overflow_p(const struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_add_ji.c */
+
+#endif
diff --git a/libj2_j2i_add_ji_to_j2i.c b/libj2_j2i_add_ji_to_j2i.c
new file mode 100644
index 0000000..787b563
--- /dev/null
+++ b/libj2_j2i_add_ji_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_add_ji_to_j2i(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_add_ji.c */
+
+#endif
diff --git a/libj2_j2i_add_ji_to_j2i_overflow.c b/libj2_j2i_add_ji_to_j2i_overflow.c
new file mode 100644
index 0000000..9e813ac
--- /dev/null
+++ b/libj2_j2i_add_ji_to_j2i_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_add_ji_to_j2i_overflow(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_add_ji.c */
+
+#endif
diff --git a/libj2_j2i_div_j2i.c b/libj2_j2i_div_j2i.c
new file mode 100644
index 0000000..5b1658b
--- /dev/null
+++ b/libj2_j2i_div_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_div_j2i(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_div_j2i_return.c b/libj2_j2i_div_j2i_return.c
new file mode 100644
index 0000000..6385c20
--- /dev/null
+++ b/libj2_j2i_div_j2i_return.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline intmax_t libj2_j2i_div_j2i_return(const struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_div_j2i_to_j2i.c b/libj2_j2i_div_j2i_to_j2i.c
new file mode 100644
index 0000000..3b13ff0
--- /dev/null
+++ b/libj2_j2i_div_j2i_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_div_j2i_to_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_div_j2i_to_j2i_underflow.c b/libj2_j2i_div_j2i_to_j2i_underflow.c
new file mode 100644
index 0000000..4b89cb7
--- /dev/null
+++ b/libj2_j2i_div_j2i_to_j2i_underflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_div_j2i_to_j2i_underflow(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_div_j2i_underflow.c b/libj2_j2i_div_j2i_underflow.c
new file mode 100644
index 0000000..da18e18
--- /dev/null
+++ b/libj2_j2i_div_j2i_underflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_div_j2i_underflow(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_div_ji.c b/libj2_j2i_div_ji.c
new file mode 100644
index 0000000..7e8f0cc
--- /dev/null
+++ b/libj2_j2i_div_ji.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_div_ji(struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_div_ji_return.c b/libj2_j2i_div_ji_return.c
new file mode 100644
index 0000000..7afd6f0
--- /dev/null
+++ b/libj2_j2i_div_ji_return.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline intmax_t libj2_j2i_div_ji_return(const struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_div_ji_to_j2i.c b/libj2_j2i_div_ji_to_j2i.c
new file mode 100644
index 0000000..44c5051
--- /dev/null
+++ b/libj2_j2i_div_ji_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_div_ji_to_j2i(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_div_ji_to_j2i_underflow.c b/libj2_j2i_div_ji_to_j2i_underflow.c
new file mode 100644
index 0000000..1f07dc6
--- /dev/null
+++ b/libj2_j2i_div_ji_to_j2i_underflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_div_ji_to_j2i_underflow(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_div_ji_underflow.c b/libj2_j2i_div_ji_underflow.c
new file mode 100644
index 0000000..b610fd9
--- /dev/null
+++ b/libj2_j2i_div_ji_underflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_div_ji_underflow(struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_divmod_j2i.c b/libj2_j2i_divmod_j2i.c
new file mode 100644
index 0000000..dc6ef9a
--- /dev/null
+++ b/libj2_j2i_divmod_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline intmax_t libj2_j2i_divmod_j2i(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_divmod_j2i_to_j2i.c b/libj2_j2i_divmod_j2i_to_j2i.c
new file mode 100644
index 0000000..147fe0c
--- /dev/null
+++ b/libj2_j2i_divmod_j2i_to_j2i.c
@@ -0,0 +1,459 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_divmod_j2i_to_j2i(struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res_q);
+/* TODO Add man page */
+
+
+#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
+validate_result(const struct libj2_j2i *a, const struct libj2_j2i *b,
+ const struct libj2_j2i *q, const struct libj2_j2i *r)
+{
+ struct libj2_j2i v;
+ libj2_j2i_mul_j2i_to_j2i(q, b, &v);
+ libj2_j2i_add_j2i(&v, r);
+ EXPECT(libj2_j2i_eq_j2i(&v, a));
+
+ if (!a->high && !b->high) {
+ EXPECT(!q->high);
+ EXPECT(!r->high);
+ EXPECT(q->low == a->low / b->low);
+ EXPECT(r->low == a->low % b->low);
+ }
+}
+
+
+static void
+check_manual(const struct libj2_j2i *a, const struct libj2_j2i *b,
+ const struct libj2_j2i *expected_q, const struct libj2_j2i *expected_r)
+{
+ struct libj2_j2i a_saved = *a, b_saved = *b, q, r, eq, er;
+ intmax_t b_low_ji;
+ int underflow;
+
+ EXPECT(!libj2_j2i_is_zero(b));
+
+ r = (struct libj2_j2i){111, 222};
+ q = (struct libj2_j2i){333, 444};
+ libj2_j2i_divmod_j2i_to_j2i_j2i(a, b, &q, &r);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ if (expected_q) {
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ } else {
+ eq = q;
+ expected_q = &eq;
+ }
+ if (expected_r) {
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+ } else {
+ er = r;
+ expected_r = &er;
+ }
+ underflow = !libj2_j2i_is_zero(expected_r);
+
+ validate_result(a, b, expected_q, expected_r);
+
+ r = (struct libj2_j2i){111, 222};
+ q = *a;
+ libj2_j2i_divmod_j2i_to_j2i_j2i(&q, b, &q, &r);
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2i){333, 444};
+ libj2_j2i_divmod_j2i_to_j2i_j2i(&r, b, &q, &r);
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = (struct libj2_j2i){111, 222};
+ q = *b;
+ libj2_j2i_divmod_j2i_to_j2i_j2i(a, &q, &q, &r);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *b;
+ q = (struct libj2_j2i){333, 444};
+ libj2_j2i_divmod_j2i_to_j2i_j2i(a, &r, &q, &r);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *b;
+ q = *a;
+ libj2_j2i_divmod_j2i_to_j2i_j2i(&q, &r, &q, &r);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ q = *b;
+ libj2_j2i_divmod_j2i_to_j2i_j2i(&r, &q, &q, &r);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ q = (struct libj2_j2i){333, 444};
+ libj2_j2i_div_j2i_to_j2i(a, b, &q);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = *a;
+ libj2_j2i_div_j2i_to_j2i(&q, b, &q);
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = *b;
+ libj2_j2i_div_j2i_to_j2i(a, &q, &q);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = (struct libj2_j2i){333, 444};
+ EXPECT(libj2_j2i_div_j2i_to_j2i_underflow(a, b, &q) == underflow);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = *a;
+ EXPECT(libj2_j2i_div_j2i_to_j2i_underflow(&q, b, &q) == underflow);
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = *b;
+ EXPECT(libj2_j2i_div_j2i_to_j2i_underflow(a, &q, &q) == underflow);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_j2i_mod_j2i_to_j2i(a, b, &r);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ libj2_j2i_mod_j2i_to_j2i(&r, b, &r);
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *b;
+ libj2_j2i_mod_j2i_to_j2i(a, &r, &r);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2i){333, 444};
+ libj2_j2i_divmod_j2i_to_j2i(&r, b, &q);
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ q = *b;
+ libj2_j2i_divmod_j2i_to_j2i(&r, &q, &q);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ q = *a;
+ libj2_j2i_div_j2i(&q, b);
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = *a;
+ EXPECT(libj2_j2i_div_j2i_underflow(&q, b) == underflow);
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ r = *a;
+ libj2_j2i_mod_j2i(&r, b);
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *b;
+ q = (struct libj2_j2i){333, 444};
+ libj2_j2i_rdivmod_j2i_to_j2i(&r, a, &q);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *b;
+ q = *a;
+ libj2_j2i_rdivmod_j2i_to_j2i(&r, &q, &q);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ q = *b;
+ libj2_j2i_rdiv_j2i(&q, a);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = *b;
+ EXPECT(libj2_j2i_rdiv_j2i_underflow(&q, a) == underflow);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ r = *b;
+ libj2_j2i_rmod_j2i(&r, a);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ EXPECT(libj2_j2i_divmod_j2i(&r, b) == (intmax_t)expected_q->low);
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ EXPECT(libj2_j2i_div_j2i_return(a, b) == (intmax_t)expected_q->low);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(b, &b_saved));
+
+ if (!b->high && b->low <= (intmax_t)INTMAX_MAX) {
+ b_low_ji = (intmax_t)b->low;
+
+ r = (struct libj2_j2i){111, 222};
+ q = (struct libj2_j2i){333, 444};
+ libj2_j2i_divmod_ji_to_j2i_j2i(a, b_low_ji, &q, &r);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = (struct libj2_j2i){111, 222};
+ q = *a;
+ libj2_j2i_divmod_ji_to_j2i_j2i(&q, b_low_ji, &q, &r);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2i){333, 444};
+ libj2_j2i_divmod_ji_to_j2i_j2i(&r, b_low_ji, &q, &r);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ q = (struct libj2_j2i){333, 444};
+ libj2_j2i_div_ji_to_j2i(a, b_low_ji, &q);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = *a;
+ libj2_j2i_div_ji_to_j2i(&q, b_low_ji, &q);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = (struct libj2_j2i){333, 444};
+ EXPECT(libj2_j2i_div_ji_to_j2i_underflow(a, b_low_ji, &q) == underflow);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = *a;
+ EXPECT(libj2_j2i_div_ji_to_j2i_underflow(&q, b_low_ji, &q) == underflow);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_j2i_mod_ji_to_j2i(a, b_low_ji, &r);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ libj2_j2i_mod_ji_to_j2i(&r, b_low_ji, &r);
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2i){333, 444};
+ libj2_j2i_divmod_ji_to_j2i(&r, b_low_ji, &q);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ q = *a;
+ libj2_j2i_div_ji(&q, b_low_ji);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = *a;
+ EXPECT(libj2_j2i_div_ji_underflow(&q, b_low_ji) == underflow);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ r = *a;
+ libj2_j2i_mod_ji(&r, b_low_ji);
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *b;
+ EXPECT(libj2_j2i_rdivmod_j2i(&r, a) == (intmax_t)expected_q->low);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ EXPECT(libj2_j2i_divmod_ji(&r, b_low_ji) == (intmax_t)expected_q->low);
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ EXPECT(libj2_j2i_div_ji_return(a, b_low_ji) == (intmax_t)expected_q->low);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ }
+
+ if (a == b) {
+ r = (struct libj2_j2i){111, 222};
+ q = *a;
+ libj2_j2i_divmod_j2i_to_j2i_j2i(&q, &q, &q, &r);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2i){333, 444};
+ libj2_j2i_divmod_j2i_to_j2i_j2i(&r, &r, &q, &r);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ q = *a;
+ libj2_j2i_div_j2i_to_j2i(&q, &q, &q);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = *a;
+ EXPECT(libj2_j2i_div_j2i_to_j2i_underflow(&q, &q, &q) == underflow);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ r = *a;
+ libj2_j2i_mod_j2i_to_j2i(&r, &r, &r);
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2i){333, 444};
+ libj2_j2i_divmod_j2i_to_j2i(&r, &r, &q);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ q = *a;
+ libj2_j2i_div_j2i(&q, &q);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = *a;
+ EXPECT(libj2_j2i_div_j2i_underflow(&q, &q) == underflow);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ r = *a;
+ libj2_j2i_mod_j2i(&r, &r);
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2i){333, 444};
+ libj2_j2i_rdivmod_j2i_to_j2i(&r, &r, &q);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ q = *a;
+ libj2_j2i_rdiv_j2i(&q, &q);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ q = *a;
+ EXPECT(libj2_j2i_rdiv_j2i_underflow(&q, &q) == underflow);
+ EXPECT(libj2_j2i_eq_j2i(&q, expected_q));
+
+ r = *a;
+ libj2_j2i_rmod_j2i(&r, &r);
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+
+ r = *a;
+ EXPECT(libj2_j2i_divmod_j2i(&r, &r) == (intmax_t)expected_q->low);
+ EXPECT(libj2_j2i_eq_j2i(&r, expected_r));
+ }
+}
+
+
+static void
+check(const struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ struct libj2_j2i u, v;
+ if (!a) {
+ u.high = random_ju();
+ u.low = random_ju();
+ a = &u;
+ }
+ if (!b) {
+ do {
+ v.high = random_ju();
+ v.low = random_ju();
+ } while (!v.high && !v.low);
+ b = &u;
+ }
+ check_manual(a, b, NULL, NULL);
+}
+
+
+int
+main(void)
+{
+ struct libj2_j2i a = {0, 0}, b = {0, 0}, q = {0, 0}, r = {0, 0};
+ struct libj2_j2i zero = {0, 0}, one = {0, 0}, two = {0, 0}, minus_one;
+ unsigned i;
+
+ srand((unsigned)time(NULL));
+
+ one.low = 1;
+ two.low = 2;
+ libj2_ji_to_j2i(-1, &minus_one);
+
+ check_manual(&one, &one, &one, &zero);
+ check_manual(&two, &one, &two, &zero);
+ check_manual(&one, &two, &zero, &one);
+ check_manual(&zero, &one, &zero, &zero);
+
+ a.low = 35;
+ b.low = 4;
+ q.low = 8;
+ r.low = 3;
+ check_manual(&a, &b, &q, &r);
+
+ a.low = UINTMAX_C(0x14385c048097d350);
+ b.low = UINTMAX_C(0x1212734e33d9df1e);
+ r.low = a.low % b.low;
+ check(&a, &b);
+ check_manual(&a, &b, &one, &r);
+
+ for (i = 0; i < 2048; i++) {
+ a.high = b.high = 0;
+ a.low = random_ju();
+ b.low = random_ju();
+ check(NULL, NULL);
+ check(NULL, &a);
+ check(&a, NULL);
+ check(&a, &b);
+ a.high = b.low;
+ check(&a, &a);
+ if (!libj2_j2i_is_zero(&a))
+ check_manual(&zero, &a, &zero, &zero);
+ check_manual(&a, &one, &a, &zero);
+ b.high = a.high >> 1;
+ b.low = a.low >> 1;
+ b.low |= (a.high & 1U) << (LIBJ2_JU_BIT - 1U);
+ if (a.high & ((uintmax_t)INTMAX_MAX + 1U)) {
+ b.high |= (uintmax_t)INTMAX_MAX + 1U;
+ if (a.low & 1U) {
+ b.low += 1U;
+ if (b.low == 0U)
+ b.high += 1U;
+ check_manual(&a, &two, &b, &minus_one);
+ } else {
+ check_manual(&a, &two, &b, &zero);
+ }
+ } else {
+ check_manual(&a, &two, &b, (a.low & 1U) ? &one : &zero);
+ }
+ }
+
+ /* TODO test sign-issues in a better way, especially ji divisor */
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2i_divmod_j2i_to_j2i_j2i.c b/libj2_j2i_divmod_j2i_to_j2i_j2i.c
new file mode 100644
index 0000000..63587d6
--- /dev/null
+++ b/libj2_j2i_divmod_j2i_to_j2i_j2i.c
@@ -0,0 +1,14 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_divmod_j2i_to_j2i_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b,
+ struct libj2_j2i *res_q, struct libj2_j2i *res_r);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_divmod_ji.c b/libj2_j2i_divmod_ji.c
new file mode 100644
index 0000000..84f316b
--- /dev/null
+++ b/libj2_j2i_divmod_ji.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline intmax_t libj2_j2i_divmod_ji(struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_divmod_ji_to_j2i.c b/libj2_j2i_divmod_ji_to_j2i.c
new file mode 100644
index 0000000..1a7d64c
--- /dev/null
+++ b/libj2_j2i_divmod_ji_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_divmod_ji_to_j2i(struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res_q);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_divmod_ji_to_j2i_j2i.c b/libj2_j2i_divmod_ji_to_j2i_j2i.c
new file mode 100644
index 0000000..853f385
--- /dev/null
+++ b/libj2_j2i_divmod_ji_to_j2i_j2i.c
@@ -0,0 +1,14 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_divmod_ji_to_j2i_j2i(const struct libj2_j2i *a, intmax_t b,
+ struct libj2_j2i *res_q, struct libj2_j2i *res_r);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_max.c b/libj2_j2i_max.c
index 49de1f9..c751060 100644
--- a/libj2_j2i_max.c
+++ b/libj2_j2i_max.c
@@ -22,10 +22,8 @@ main(void)
EXPECT(value.high == (uintmax_t)INTMAX_MAX);
EXPECT(value.low == UINTMAX_MAX);
-#ifdef TODO /* requires libj2_j2i_add_ji */
libj2_j2i_add_ji(&value, 1);
EXPECT(libj2_j2i_is_min(&value));
-#endif
return 0;
}
diff --git a/libj2_j2i_min.c b/libj2_j2i_min.c
index 74b438b..201f69f 100644
--- a/libj2_j2i_min.c
+++ b/libj2_j2i_min.c
@@ -21,10 +21,8 @@ main(void)
EXPECT(value.high == (uintmax_t)INTMAX_MAX + 1U);
EXPECT(value.low == 0);
-#ifdef TODO /* requires libj2_j2i_sub_ji */
- libj2_j2i_sub_ji(&value, 1);
+ libj2_j2i_add_ji(&value, -1);
EXPECT(libj2_j2i_is_max(&value));
-#endif
return 0;
}
diff --git a/libj2_j2i_mod_j2i.c b/libj2_j2i_mod_j2i.c
new file mode 100644
index 0000000..aad06b6
--- /dev/null
+++ b/libj2_j2i_mod_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_mod_j2i(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_mod_j2i_to_j2i.c b/libj2_j2i_mod_j2i_to_j2i.c
new file mode 100644
index 0000000..2711b97
--- /dev/null
+++ b/libj2_j2i_mod_j2i_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_mod_j2i_to_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_mod_ji.c b/libj2_j2i_mod_ji.c
new file mode 100644
index 0000000..85ff995
--- /dev/null
+++ b/libj2_j2i_mod_ji.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_mod_ji(struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_mod_ji_to_j2i.c b/libj2_j2i_mod_ji_to_j2i.c
new file mode 100644
index 0000000..526fe0d
--- /dev/null
+++ b/libj2_j2i_mod_ji_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_mod_ji_to_j2i(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_mul_j2i.c b/libj2_j2i_mul_j2i.c
new file mode 100644
index 0000000..4794843
--- /dev/null
+++ b/libj2_j2i_mul_j2i.c
@@ -0,0 +1,14 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_mul_j2i(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; }
+/* TODO test libj2_j2i_mul_j2i, libj2_j2i_mul_j2i_to_j2i_overflow_p_quick, libj2_j2i_mul_j2i_to_j2i_overflow_p, libj2_j2i_mul_j2i_to_j2i_overflow, libj2_j2i_mul_j2i_overflow_p_quick, libj2_j2i_mul_j2i_overflow_p, libj2_j2i_mul_j2i_overflow */
+
+#endif
diff --git a/libj2_j2i_mul_j2i_overflow.c b/libj2_j2i_mul_j2i_overflow.c
new file mode 100644
index 0000000..c840edb
--- /dev/null
+++ b/libj2_j2i_mul_j2i_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_mul_j2i_overflow(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_j2i.c */
+
+#endif
diff --git a/libj2_j2i_mul_j2i_overflow_p.c b/libj2_j2i_mul_j2i_overflow_p.c
new file mode 100644
index 0000000..1c707f1
--- /dev/null
+++ b/libj2_j2i_mul_j2i_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_mul_j2i_overflow_p(const struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_j2i.c */
+
+#endif
diff --git a/libj2_j2i_mul_j2i_overflow_p_quick.c b/libj2_j2i_mul_j2i_overflow_p_quick.c
new file mode 100644
index 0000000..27b47b8
--- /dev/null
+++ b/libj2_j2i_mul_j2i_overflow_p_quick.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline enum libj2_overflow libj2_j2i_mul_j2i_overflow_p_quick(const struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_j2i.c */
+
+#endif
diff --git a/libj2_j2i_mul_j2i_to_j2i.c b/libj2_j2i_mul_j2i_to_j2i.c
new file mode 100644
index 0000000..678f02c
--- /dev/null
+++ b/libj2_j2i_mul_j2i_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_mul_j2i_to_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_j2i.c */
+
+#endif
diff --git a/libj2_j2i_mul_j2i_to_j2i_overflow.c b/libj2_j2i_mul_j2i_to_j2i_overflow.c
new file mode 100644
index 0000000..466763c
--- /dev/null
+++ b/libj2_j2i_mul_j2i_to_j2i_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_mul_j2i_to_j2i_overflow(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_j2i.c */
+
+#endif
diff --git a/libj2_j2i_mul_j2i_to_j2i_overflow_p.c b/libj2_j2i_mul_j2i_to_j2i_overflow_p.c
new file mode 100644
index 0000000..dea6e8d
--- /dev/null
+++ b/libj2_j2i_mul_j2i_to_j2i_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_mul_j2i_to_j2i_overflow_p(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res, int *res_set);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_j2i.c */
+
+#endif
diff --git a/libj2_j2i_mul_ji.c b/libj2_j2i_mul_ji.c
new file mode 100644
index 0000000..e1e25ff
--- /dev/null
+++ b/libj2_j2i_mul_ji.c
@@ -0,0 +1,373 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_mul_ji(struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+static uintmax_t
+random_small_ju(size_t bits)
+{
+ uintmax_t r = 0;
+ while (bits--)
+ if (rand() < rand())
+ r |= (uintmax_t)1 << bits;
+ return r;
+}
+
+static uintmax_t
+random_hju(void)
+{
+ return random_small_ju(LIBJ2_JU_BIT / 2U);
+}
+
+static uintmax_t
+random_ju(void)
+{
+ return random_small_ju(LIBJ2_JU_BIT);
+}
+
+
+static int
+refmul(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *expected)
+{
+ struct libj2_j2u u;
+ struct libj2_j2i c;
+ uintmax_t v;
+ unsigned i;
+ int neg, overflow = 0;
+
+ neg = libj2_j2i_is_negative(a) ^ (b < 0);
+ libj2_abs_j2i_to_j2u(a, &u);
+ v = b < 0 ? (uintmax_t)-(b + 1) + 1U : (uintmax_t)b;
+
+ libj2_j2i_zero(expected);
+ for (i = 0; i < LIBJ2_J2U_BIT; i++, v >>= 1) {
+ if (v & 1U) {
+ overflow |= libj2_j2i_lsh_to_j2i_overflow(a, i, &c);
+ libj2_j2i_add_j2i(expected, &c);
+ }
+ }
+
+ if (neg) {
+ overflow = -overflow;
+ libj2_minus_j2i(expected);
+ }
+
+ return overflow;
+}
+
+
+static void
+mul_(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *expected, int expect_overflow)
+{
+ struct libj2_j2i t, a_saved = *a, t_saved;
+ enum libj2_overflow ofp;
+ enum libj2_overflow unknown_overflow;
+ int set;
+
+ if (libj2_j2i_is_zero(a) || b == 0)
+ unknown_overflow = LIBJ2_NO_OVERFLOW;
+ else if (libj2_j2i_is_negative(a) ^ (b < 0))
+ unknown_overflow = LIBJ2_NEGATIVE_OVERFLOW_UNKNOWN;
+ else
+ unknown_overflow = LIBJ2_POSITIVE_OVERFLOW_UNKNOWN;
+
+ *expected = *a;
+ libj2_j2i_mul_ji(expected, b);
+
+ t = (struct libj2_j2i){111, 222};
+ libj2_j2i_mul_ji_to_j2i(a, b, &t);
+ EXPECT(libj2_j2i_eq_j2i(&t, expected));
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+
+ t = *a;
+ libj2_j2i_mul_ji_to_j2i(&t, b, &t);
+ EXPECT(libj2_j2i_eq_j2i(&t, expected));
+
+ t = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_j2i_to_j2i(b, a, &t);
+ EXPECT(libj2_j2i_eq_j2i(&t, expected));
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+
+ t = *a;
+ libj2_ji_mul_j2i_to_j2i(b, &t, &t);
+ EXPECT(libj2_j2i_eq_j2i(&t, expected));
+
+ t = *a;
+ EXPECT(libj2_j2i_mul_ji_overflow(&t, b) == expect_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&t, expected));
+
+#if 0 /* TODO saturated multiplication */
+ t = *a;
+ libj2_j2u_sat_mul_ju(&t, b);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
+#endif
+
+ t = *a;
+ EXPECT(libj2_j2i_mul_ji_overflow_p((const struct libj2_j2i *)&t, b) == expect_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&t, a));
+
+ t = *a;
+ ofp = libj2_j2i_mul_ji_overflow_p_quick((const struct libj2_j2i *)&t, b);
+ EXPECT(ofp == unknown_overflow || (int)ofp == expect_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&t, a));
+
+ set = 999;
+ t = (struct libj2_j2i){111, 222};
+ t_saved = t;
+ EXPECT(libj2_j2i_mul_ji_to_j2i_overflow_p((const struct libj2_j2i *)a, b, &t, &set) == expect_overflow);
+ EXPECT(set == 0 || set == 1);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&t, set ? expected : &t_saved));
+
+ set = 999;
+ t = *a;
+ EXPECT(libj2_j2i_mul_ji_to_j2i_overflow_p((const struct libj2_j2i *)&t, b, &t, &set) == expect_overflow);
+ EXPECT(set == 0 || set == 1);
+ EXPECT(libj2_j2i_eq_j2i(&t, set ? expected : a));
+
+ t = (struct libj2_j2i){111, 222};
+ EXPECT(libj2_j2i_mul_ji_to_j2i_overflow(a, b, &t) == expect_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&t, expected));
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+
+ t = *a;
+ EXPECT(libj2_j2i_mul_ji_to_j2i_overflow(&t, b, &t) == expect_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&t, expected));
+
+#if 0 /* TODO saturated multiplication */
+ t = (struct libj2_j2u){111, 222};
+ libj2_j2u_sat_mul_ju_to_j2u(a, b, &t);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+
+ t = *a;
+ libj2_j2u_sat_mul_ju_to_j2u(&t, b, &t);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
+#endif
+
+ t = (struct libj2_j2i){111, 222};
+ EXPECT(libj2_ji_mul_j2i_to_j2i_overflow(b, a, &t) == expect_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&t, expected));
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+
+ t = *a;
+ EXPECT(libj2_ji_mul_j2i_to_j2i_overflow(b, &t, &t) == expect_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&t, expected));
+
+#if 0 /* TODO saturated multiplication */
+ t = (struct libj2_j2u){111, 222};
+ libj2_ju_sat_mul_j2u_to_j2u(b, a, &t);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+
+ t = *a;
+ libj2_ju_sat_mul_j2u_to_j2u(b, &t, &t);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
+#endif
+
+ set = 999;
+ t = (struct libj2_j2i){111, 222};
+ t_saved = t;
+ EXPECT(libj2_ji_mul_j2i_to_j2i_overflow_p(b, a, &t, &set) == expect_overflow);
+ EXPECT(set == 0 || set == 1);
+ EXPECT(libj2_j2i_eq_j2i(&t, set ? expected : &t_saved));
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+
+ set = 999;
+ t = *a;
+ EXPECT(libj2_ji_mul_j2i_to_j2i_overflow_p(b, &t, &t, &set) == expect_overflow);
+ EXPECT(set == 0 || set == 1);
+ EXPECT(libj2_j2i_eq_j2i(&t, set ? expected : a));
+
+ EXPECT(libj2_ji_mul_j2i_overflow_p(b, (const struct libj2_j2i *)a) == expect_overflow);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+
+ ofp = libj2_ji_mul_j2i_overflow_p_quick(b, (const struct libj2_j2i *)a);
+ EXPECT(ofp == unknown_overflow || (int)ofp == expect_overflow);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+}
+
+
+static void
+mul(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *expected, int expect_overflow)
+{
+ struct libj2_j2i r, neg_a, e;
+ struct libj2_j2u u;
+
+ libj2_minus_j2i_to_j2i(a, &neg_a);
+ libj2_j2i_to_j2u(a, &u);
+
+
+ mul_(a, b, expected, expect_overflow);
+
+ mul_(&neg_a, -b, &r, expect_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, expected));
+
+ mul_(&neg_a, b, &r, -expect_overflow);
+ libj2_minus_j2i(&r);
+ EXPECT(libj2_j2i_eq_j2i(&r, expected));
+
+ mul_(a, -b, &r, -expect_overflow);
+ libj2_minus_j2i(&r);
+ EXPECT(libj2_j2i_eq_j2i(&r, expected));
+
+
+ expect_overflow = libj2_j2u_mul_ju_to_j2u_overflow(&u, (uintmax_t)b + 1U, (void *)&e);
+ if (libj2_j2i_is_negative(&e))
+ expect_overflow = 1;
+
+ mul_(&neg_a, -b - 1, &r, expect_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, &e));
+
+ mul_(a, -b - 1, &r, -expect_overflow);
+ libj2_minus_j2i(&r);
+ EXPECT(libj2_j2i_eq_j2i(&r, &e));
+
+
+ libj2_j2u_add_ju(&u, 1U);
+ libj2_j2i_add_ji(&neg_a, -1);
+ expect_overflow = libj2_j2u_mul_ju_to_j2u_overflow(&u, (uintmax_t)b, (void *)&e);
+ if (libj2_j2i_is_negative(&e))
+ expect_overflow = 1;
+
+ mul_(&neg_a, b, &r, -expect_overflow);
+ libj2_minus_j2i(&r);
+ EXPECT(libj2_j2i_eq_j2i(&r, &e));
+
+
+ expect_overflow = libj2_j2u_mul_ju_to_j2u_overflow(&u, (uintmax_t)b + 1U, (void *)&e);
+ if (libj2_j2i_is_negative(&e))
+ expect_overflow = 1;
+
+ mul_(&neg_a, -b - 1, &r, expect_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, &e));
+}
+
+
+int
+main(void)
+{
+ struct libj2_j2i r, expected;
+ intmax_t u, v;
+ uintmax_t w;
+ unsigned i;
+ int expect_overflow;
+
+ srand((unsigned)time(NULL));
+
+ /* self-check */
+ r = (struct libj2_j2i){111, 222};
+ EXPECT(refmul(&(struct libj2_j2i){.high = UINTMAX_MAX >> 1, .low = UINTMAX_MAX}, INTMAX_MAX, &r) == 1);
+ EXPECT(r.high == UINTMAX_MAX >> 1);
+ EXPECT(r.low == 2 + (uintmax_t)INTMAX_MAX);
+
+ r = (struct libj2_j2i){111, 222};
+ mul_(&(struct libj2_j2i){.high = (UINTMAX_MAX >> 2) + 1U, .low = 0}, 2, &r, 1);
+ EXPECT(r.high == (UINTMAX_MAX >> 1) + 1U);
+ EXPECT(r.low == 0);
+
+ r = (struct libj2_j2i){111, 222};
+ mul_(&(struct libj2_j2i){.high = (UINTMAX_MAX >> 2) + 1U, .low = 0}, -2, &r, 0);
+ EXPECT(r.high == (UINTMAX_MAX >> 1) + 1U);
+ EXPECT(r.low == 0);
+
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){.high = 0, .low = 0}, 0, &r, 0);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){.high = 0, .low = 0}, 1, &r, 0);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){.high = 0, .low = 0}, INTMAX_MAX, &r, 0);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){.high = 0, .low = 1}, 0, &r, 0);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){.high = 0, .low = UINTMAX_MAX}, 0, &r, 0);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ for (i = 0; i < 32; i++) {
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){.high = 0, .low = 0}, (intmax_t)(random_ju() >> 1), &r, 0);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){.high = 0, .low = random_ju()}, 0, &r, 0);
+ EXPECT(libj2_j2i_is_zero(&r));
+ }
+
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){.high = 0, .low = 1}, 1, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == 1);
+
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){.high = 0, .low = 4}, 4, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == 16);
+
+ for (i = 0; i < 32; i++) {
+ r = (struct libj2_j2i){111, 222};
+ v = (intmax_t)(random_ju() >> 1);
+ mul(&(struct libj2_j2i){.high = 0, .low = 1}, v, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == (uintmax_t)v);
+
+ r = (struct libj2_j2i){111, 222};
+ v = (intmax_t)(random_ju() >> 1);
+ mul(&(struct libj2_j2i){.high = 0, .low = (uintmax_t)v}, 1, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == (uintmax_t)v);
+ }
+
+ for (i = 0; i < 32; i++) {
+ u = (intmax_t)random_hju();
+ v = (intmax_t)random_hju();
+
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){.high = 0, .low = (uintmax_t)u}, v, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == (uintmax_t)u * (uintmax_t)v);
+
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){.high = 0, .low = (uintmax_t)v}, u, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == (uintmax_t)u * (uintmax_t)v);
+ }
+
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){.high = 0, .low = UINTMAX_MAX >> 1}, INTMAX_MAX, &r, 0);
+ EXPECT(r.high == UINTMAX_MAX >> 2);
+ EXPECT(r.low == 1);
+
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){.high = UINTMAX_MAX >> 1, .low = UINTMAX_MAX}, INTMAX_MAX, &r, 1);
+ EXPECT(r.high == UINTMAX_MAX >> 1);
+ EXPECT(r.low == 2 + (uintmax_t)INTMAX_MAX);
+
+ for (i = 0; i < 256; i++) {
+ u = (intmax_t)(random_ju() >> 1);
+ v = (intmax_t)(random_ju() >> 1);
+ w = random_ju();
+
+ expect_overflow = refmul(&(struct libj2_j2i){(uintmax_t)u, w}, v, &expected);
+
+ r = (struct libj2_j2i){111, 222};
+ mul(&(struct libj2_j2i){(uintmax_t)u, w}, v, &r, expect_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2i_mul_ji_overflow.c b/libj2_j2i_mul_ji_overflow.c
new file mode 100644
index 0000000..c4ea82a
--- /dev/null
+++ b/libj2_j2i_mul_ji_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_mul_ji_overflow(struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_ji.c */
+
+#endif
diff --git a/libj2_j2i_mul_ji_overflow_p.c b/libj2_j2i_mul_ji_overflow_p.c
new file mode 100644
index 0000000..f0fe02f
--- /dev/null
+++ b/libj2_j2i_mul_ji_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_mul_ji_overflow_p(const struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_ji.c */
+
+#endif
diff --git a/libj2_j2i_mul_ji_overflow_p_quick.c b/libj2_j2i_mul_ji_overflow_p_quick.c
new file mode 100644
index 0000000..de2bc83
--- /dev/null
+++ b/libj2_j2i_mul_ji_overflow_p_quick.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline enum libj2_overflow libj2_j2i_mul_ji_overflow_p_quick(const struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_ji.c */
+
+#endif
diff --git a/libj2_j2i_mul_ji_to_j2i.c b/libj2_j2i_mul_ji_to_j2i.c
new file mode 100644
index 0000000..16a50f9
--- /dev/null
+++ b/libj2_j2i_mul_ji_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_mul_ji_to_j2i(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_ji.c */
+
+#endif
diff --git a/libj2_j2i_mul_ji_to_j2i_overflow.c b/libj2_j2i_mul_ji_to_j2i_overflow.c
new file mode 100644
index 0000000..210c8ee
--- /dev/null
+++ b/libj2_j2i_mul_ji_to_j2i_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_mul_ji_to_j2i_overflow(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_ji.c */
+
+#endif
diff --git a/libj2_j2i_mul_ji_to_j2i_overflow_p.c b/libj2_j2i_mul_ji_to_j2i_overflow_p.c
new file mode 100644
index 0000000..e8b481a
--- /dev/null
+++ b/libj2_j2i_mul_ji_to_j2i_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_mul_ji_to_j2i_overflow_p(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res, int *res_set);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_ji.c */
+
+#endif
diff --git a/libj2_j2i_rdiv_j2i.c b/libj2_j2i_rdiv_j2i.c
new file mode 100644
index 0000000..893c33b
--- /dev/null
+++ b/libj2_j2i_rdiv_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_rdiv_j2i(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_rdiv_j2i_underflow.c b/libj2_j2i_rdiv_j2i_underflow.c
new file mode 100644
index 0000000..c32f7b5
--- /dev/null
+++ b/libj2_j2i_rdiv_j2i_underflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_rdiv_j2i_underflow(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_rdivmod_j2i.c b/libj2_j2i_rdivmod_j2i.c
new file mode 100644
index 0000000..8b1bd41
--- /dev/null
+++ b/libj2_j2i_rdivmod_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline intmax_t libj2_j2i_rdivmod_j2i(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_rdivmod_j2i_to_j2i.c b/libj2_j2i_rdivmod_j2i_to_j2i.c
new file mode 100644
index 0000000..60fc71f
--- /dev/null
+++ b/libj2_j2i_rdivmod_j2i_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_rdivmod_j2i_to_j2i(struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res_q);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_rmod_j2i.c b/libj2_j2i_rmod_j2i.c
new file mode 100644
index 0000000..0c6c990
--- /dev/null
+++ b/libj2_j2i_rmod_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_rmod_j2i(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_divmod_j2i_to_j2i.c */
+
+#endif
diff --git a/libj2_j2i_rsub_j2i.c b/libj2_j2i_rsub_j2i.c
new file mode 100644
index 0000000..ba68d80
--- /dev/null
+++ b/libj2_j2i_rsub_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_rsub_j2i(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_j2i.c */
+
+#endif
diff --git a/libj2_j2i_rsub_j2i_overflow.c b/libj2_j2i_rsub_j2i_overflow.c
new file mode 100644
index 0000000..9840a41
--- /dev/null
+++ b/libj2_j2i_rsub_j2i_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_rsub_j2i_overflow(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_j2i.c */
+
+#endif
diff --git a/libj2_j2i_rsub_j2i_overflow_p.c b/libj2_j2i_rsub_j2i_overflow_p.c
new file mode 100644
index 0000000..a45675c
--- /dev/null
+++ b/libj2_j2i_rsub_j2i_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_rsub_j2i_overflow_p(const struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_j2i.c */
+
+#endif
diff --git a/libj2_j2i_rsub_ji.c b/libj2_j2i_rsub_ji.c
new file mode 100644
index 0000000..eb99109
--- /dev/null
+++ b/libj2_j2i_rsub_ji.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_rsub_ji(struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_ji.c */
+
+#endif
diff --git a/libj2_j2i_rsub_ji_overflow.c b/libj2_j2i_rsub_ji_overflow.c
new file mode 100644
index 0000000..1fd1346
--- /dev/null
+++ b/libj2_j2i_rsub_ji_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_rsub_ji_overflow(struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_ji.c */
+
+#endif
diff --git a/libj2_j2i_rsub_ji_overflow_p.c b/libj2_j2i_rsub_ji_overflow_p.c
new file mode 100644
index 0000000..bad6009
--- /dev/null
+++ b/libj2_j2i_rsub_ji_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_rsub_ji_overflow_p(const struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_ji.c */
+
+#endif
diff --git a/libj2_j2i_sub_j2i.c b/libj2_j2i_sub_j2i.c
new file mode 100644
index 0000000..d26c290
--- /dev/null
+++ b/libj2_j2i_sub_j2i.c
@@ -0,0 +1,244 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_sub_j2i(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#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
+validate(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)
+{
+ int a_neg, b_neg, overflow;
+ struct libj2_j2u a, b;
+ struct libj2_j2i t, r;
+
+ t = (struct libj2_j2i){.high = a_high, .low = a_low};
+ if ((a_neg = libj2_j2i_is_negative(&t)))
+ libj2_minus_j2i_to_j2u(&t, &a);
+ else
+ libj2_j2i_to_j2u(&t, &a);
+
+ t = (struct libj2_j2i){.high = b_high, .low = b_low};
+ if ((b_neg = libj2_j2i_is_negative(&t)))
+ libj2_minus_j2i_to_j2u(&t, &b);
+ else
+ libj2_j2i_to_j2u(&t, &b);
+
+ if (a_neg && b_neg) {
+ overflow = 0;
+ libj2_minus_j2u(&a);
+ libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, (void *)&r);
+ } else if (a_neg) {
+ overflow = -libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, (void *)&r);
+ libj2_minus_j2i(&r);
+ if (!libj2_j2i_is_negative(&r))
+ overflow = -1;
+ } else if (b_neg) {
+ overflow = +libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, (void *)&r);
+ if (!libj2_j2i_is_positive(&r))
+ overflow = +1;
+ } else {
+ overflow = 0;
+ libj2_minus_j2u(&b);
+ libj2_j2u_add_j2u_to_j2u(&a, &b, (void *)&r);
+ }
+
+ EXPECT(r.high == r_high);
+ EXPECT(r.low == r_low);
+ EXPECT(overflow == r_overflow);
+}
+
+
+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;
+
+ a.high = a_high;
+ a.low = a_low;
+ b.high = b_high;
+ b.low = b_low;
+ a_saved = a;
+ b_saved = b;
+
+#define CONST_ARG (const struct libj2_j2i *)
+
+ expected = (struct libj2_j2i){111, 222};
+ expected_overflow = libj2_j2i_sub_j2i_to_j2i_overflow(CONST_ARG &a, CONST_ARG &b, &expected);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+ EXPECT(libj2_j2i_ne_j2i(&expected, &(struct libj2_j2i){111, 222}));
+
+ validate(a.high, a.low, b.high, b.low, expected.high, expected.low, expected_overflow);
+
+ r = a;
+ EXPECT(libj2_j2i_sub_j2i_to_j2i_overflow(CONST_ARG &r, CONST_ARG &b, &r) == 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));
+
+ r = b;
+ EXPECT(libj2_j2i_sub_j2i_to_j2i_overflow(CONST_ARG &a, CONST_ARG &r, &r) == 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));
+
+ r = a;
+ EXPECT(libj2_j2i_sub_j2i_to_j2i_overflow(CONST_ARG &r, CONST_ARG &r, &r) == 0);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_j2i_sub_j2i_to_j2i(CONST_ARG &a, CONST_ARG &b, &r);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ libj2_j2i_sub_j2i_to_j2i(CONST_ARG &r, CONST_ARG &b, &r);
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ r = b;
+ libj2_j2i_sub_j2i_to_j2i(CONST_ARG &a, CONST_ARG &r, &r);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ libj2_j2i_sub_j2i_to_j2i(CONST_ARG &r, CONST_ARG &r, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ EXPECT(libj2_j2i_sub_j2i_overflow_p(CONST_ARG &a, CONST_ARG &b) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ EXPECT(libj2_j2i_sub_j2i_overflow_p(CONST_ARG &a, CONST_ARG &a) == 0);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ r = a;
+ EXPECT(libj2_j2i_sub_j2i_overflow(&r, CONST_ARG &b) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ EXPECT(libj2_j2i_sub_j2i_overflow(&r, CONST_ARG &r) == 0);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = a;
+ libj2_j2i_sub_j2i(&r, CONST_ARG &b);
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ libj2_j2i_sub_j2i(&r, CONST_ARG &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ EXPECT(libj2_j2i_rsub_j2i_overflow_p(&b, CONST_ARG &a) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ EXPECT(libj2_j2i_rsub_j2i_overflow_p(&a, CONST_ARG &a) == 0);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+
+ r = b;
+ EXPECT(libj2_j2i_rsub_j2i_overflow(&r, CONST_ARG &a) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ EXPECT(libj2_j2i_rsub_j2i_overflow(&r, CONST_ARG &r) == 0);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = b;
+ libj2_j2i_rsub_j2i(&r, CONST_ARG &a);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ libj2_j2i_rsub_j2i(&r, CONST_ARG &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+}
+
+
+int
+main(void)
+{
+ uintmax_t a, b, c, d, max, min, umax, vs[12];
+ unsigned i, ii, iii, iv, k, j;
+
+ srand((unsigned)time(NULL));
+
+ umax = UINTMAX_MAX;
+ max = umax >> 1;
+ min = ~max;
+
+ vs[0] = 0U;
+ vs[1] = 1U;
+ vs[2] = 2U;
+ vs[3] = umax - 0U;
+ vs[4] = umax - 1U;
+ vs[5] = umax - 2U;
+ vs[6] = max - 0U;
+ vs[7] = max - 1U;
+ vs[8] = max - 2U;
+ vs[9] = min + 0U;
+ vs[10] = min + 1U;
+ vs[11] = min + 2U;
+
+ for (j = 0; j < 128U; j++) {
+ for (k = 0; k < 16U; k++) {
+ a = random_ju() >> 1;
+ b = random_ju() >> 1;
+ c = random_ju() >> 1;
+ d = random_ju() >> 1;
+ if (k & 1U) a = ~a;
+ if (k & 2U) b = ~b;
+ if (k & 4U) c = ~c;
+ if (k & 8U) d = ~d;
+ check(a, b, c, d);
+ for (i = 0; k < 8U && i < 12U; i++) {
+ check(vs[i], a, b, c);
+ check(a, vs[i], b, c);
+ check(a, b, vs[i], c);
+ check(a, b, c, vs[i]);
+ for (ii = 0; k < 4U && ii < 12U; ii++) {
+ check(vs[i], vs[ii], a, b);
+ check(vs[i], a, vs[ii], b);
+ check(vs[i], a, b, vs[ii]);
+ check(a, vs[i], vs[ii], b);
+ check(a, vs[i], b, vs[ii]);
+ check(a, b, vs[i], vs[ii]);
+ for (iii = 0; k < 2U && iii < 12U; iii++) {
+ check(vs[i], vs[ii], vs[iii], a);
+ check(vs[i], vs[ii], a, vs[iii]);
+ check(vs[i], a, vs[ii], vs[iii]);
+ check(a, vs[i], vs[ii], vs[iii]);
+ for (iv = 0; !j && k < 1U && iv < 12U; iv++)
+ check(vs[i], vs[ii], vs[iii], vs[iv]);
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2i_sub_j2i_overflow.c b/libj2_j2i_sub_j2i_overflow.c
new file mode 100644
index 0000000..17275f2
--- /dev/null
+++ b/libj2_j2i_sub_j2i_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_sub_j2i_overflow(struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_j2i.c */
+
+#endif
diff --git a/libj2_j2i_sub_j2i_overflow_p.c b/libj2_j2i_sub_j2i_overflow_p.c
new file mode 100644
index 0000000..0df616b
--- /dev/null
+++ b/libj2_j2i_sub_j2i_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_sub_j2i_overflow_p(const struct libj2_j2i *a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_j2i.c */
+
+#endif
diff --git a/libj2_j2i_sub_j2i_to_j2i.c b/libj2_j2i_sub_j2i_to_j2i.c
new file mode 100644
index 0000000..5522262
--- /dev/null
+++ b/libj2_j2i_sub_j2i_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_sub_j2i_to_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_j2i.c */
+
+#endif
diff --git a/libj2_j2i_sub_j2i_to_j2i_overflow.c b/libj2_j2i_sub_j2i_to_j2i_overflow.c
new file mode 100644
index 0000000..db703c9
--- /dev/null
+++ b/libj2_j2i_sub_j2i_to_j2i_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_sub_j2i_to_j2i_overflow(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_j2i.c */
+
+#endif
diff --git a/libj2_j2i_sub_ji.c b/libj2_j2i_sub_ji.c
new file mode 100644
index 0000000..b65d6ae
--- /dev/null
+++ b/libj2_j2i_sub_ji.c
@@ -0,0 +1,201 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_sub_ji(struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#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
+validate(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)
+{
+ int a_neg, b_neg, overflow;
+ struct libj2_j2u a, b;
+ struct libj2_j2i t, r;
+
+ t = (struct libj2_j2i){.high = a_high, .low = a_low};
+ if ((a_neg = libj2_j2i_is_negative(&t)))
+ libj2_minus_j2i_to_j2u(&t, &a);
+ else
+ libj2_j2i_to_j2u(&t, &a);
+
+ t = (struct libj2_j2i){.high = b_high, .low = b_low};
+ if ((b_neg = libj2_j2i_is_negative(&t)))
+ libj2_minus_j2i_to_j2u(&t, &b);
+ else
+ libj2_j2i_to_j2u(&t, &b);
+
+ if (a_neg && b_neg) {
+ overflow = 0;
+ libj2_minus_j2u(&a);
+ libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, (void *)&r);
+ } else if (a_neg) {
+ overflow = -libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, (void *)&r);
+ libj2_minus_j2i(&r);
+ if (!libj2_j2i_is_negative(&r))
+ overflow = -1;
+ } else if (b_neg) {
+ overflow = +libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, (void *)&r);
+ if (!libj2_j2i_is_positive(&r))
+ overflow = +1;
+ } else {
+ overflow = 0;
+ libj2_minus_j2u(&b);
+ libj2_j2u_add_j2u_to_j2u(&a, &b, (void *)&r);
+ }
+
+ EXPECT(r.high == r_high);
+ EXPECT(r.low == r_low);
+ EXPECT(overflow == r_overflow);
+}
+
+
+static void
+check(uintmax_t a_high, uintmax_t a_low, uintmax_t ub)
+{
+ intmax_t b = ub >> (LIBJ2_JU_BIT - 1U) ? -(intmax_t)~ub - 1 : (intmax_t)ub;
+ struct libj2_j2i a, a_saved, r, expected;
+ int expected_overflow;
+
+#if INTMAX_MIN + 1 != -INTMAX_MAX
+ if (ub == (UINTMAX >> 1) + 1U)
+ return;
+#endif
+
+ a.high = a_high;
+ a.low = a_low;
+ a_saved = a;
+ expected = (struct libj2_j2i){111, 222};
+ expected_overflow = libj2_j2i_sub_ji_to_j2i_overflow((const struct libj2_j2i *)&a, b, &expected);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_ne_j2i(&expected, &(struct libj2_j2i){111, 222}));
+
+ validate(a.high, a.low, b < 0 ? UINTMAX_MAX : 0U, ub, expected.high, expected.low, expected_overflow);
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_j2i_sub_ji_to_j2i((const struct libj2_j2i *)&a, b, &r);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ libj2_j2i_sub_ji_to_j2i((const struct libj2_j2i *)&r, b, &r);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ a_saved = a;
+ EXPECT(libj2_j2i_sub_ji_overflow_p((const struct libj2_j2i *)&a, b) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ r = a;
+ EXPECT(libj2_j2i_sub_ji_overflow(&r, b) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ libj2_j2i_sub_ji(&r, b);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ libj2_minus_j2i(&expected);
+
+ a = a_saved;
+ r = (struct libj2_j2i){111, 222};
+ expected_overflow = libj2_ji_sub_j2i_to_j2i_overflow(b, (const struct libj2_j2i *)&a, &r);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ validate(b < 0 ? UINTMAX_MAX : 0U, ub, a.high, a.low, expected.high, expected.low, expected_overflow);
+
+ EXPECT(libj2_ji_sub_j2i_overflow_p(b, (const struct libj2_j2i *)&a) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_sub_j2i_to_j2i(b, (const struct libj2_j2i *)&a, &r);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ libj2_ji_sub_j2i_to_j2i(b, (const struct libj2_j2i *)&r, &r);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ EXPECT(libj2_ji_sub_j2i_to_j2i_overflow(b, (const struct libj2_j2i *)&r, &r) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ EXPECT(libj2_j2i_rsub_ji_overflow(&r, b) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ EXPECT(libj2_j2i_rsub_ji_overflow_p((const struct libj2_j2i *)&a, b) == expected_overflow);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+
+ r = a;
+ libj2_j2i_rsub_ji(&r, b);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+}
+
+
+int
+main(void)
+{
+ uintmax_t a, b, c, max, min, umax, vs[12];
+ unsigned i, ii, iii, k, j;
+
+ srand((unsigned)time(NULL));
+
+ umax = UINTMAX_MAX;
+ max = umax >> 1;
+ min = ~max;
+
+ vs[0] = 0U;
+ vs[1] = 1U;
+ vs[2] = 2U;
+ vs[3] = umax - 0U;
+ vs[4] = umax - 1U;
+ vs[5] = umax - 2U;
+ vs[6] = max - 0U;
+ vs[7] = max - 1U;
+ vs[8] = max - 2U;
+ vs[9] = min + 0U;
+ vs[10] = min + 1U;
+ vs[11] = min + 2U;
+
+ for (j = 0; j < 128U; j++) {
+ for (k = 0; k < 8U; k++) {
+ a = random_ju() >> 1;
+ b = random_ju() >> 1;
+ c = random_ju() >> 1;
+ if (k & 1U) a = ~a;
+ if (k & 2U) b = ~b;
+ if (k & 4U) c = ~c;
+ check(a, b, c);
+ for (i = 0; k < 4U && i < 12U; i++) {
+ check(a, b, vs[i]);
+ check(a, vs[i], b);
+ check(vs[i], a, b);
+ for (ii = 0; k < 2U && ii < 12U; ii++) {
+ check(vs[i], vs[ii], a);
+ check(vs[i], a, vs[ii]);
+ check(a, vs[i], vs[ii]);
+ for (iii = 0; !j && k < 1U && iii < 12U; iii++)
+ check(vs[i], vs[ii], vs[iii]);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2i_sub_ji_overflow.c b/libj2_j2i_sub_ji_overflow.c
new file mode 100644
index 0000000..d8201be
--- /dev/null
+++ b/libj2_j2i_sub_ji_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_sub_ji_overflow(struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_ji.c */
+
+#endif
diff --git a/libj2_j2i_sub_ji_overflow_p.c b/libj2_j2i_sub_ji_overflow_p.c
new file mode 100644
index 0000000..1c07791
--- /dev/null
+++ b/libj2_j2i_sub_ji_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_sub_ji_overflow_p(const struct libj2_j2i *a, intmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_ji.c */
+
+#endif
diff --git a/libj2_j2i_sub_ji_to_j2i.c b/libj2_j2i_sub_ji_to_j2i.c
new file mode 100644
index 0000000..4c06968
--- /dev/null
+++ b/libj2_j2i_sub_ji_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_sub_ji_to_j2i(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_ji.c */
+
+#endif
diff --git a/libj2_j2i_sub_ji_to_j2i_overflow.c b/libj2_j2i_sub_ji_to_j2i_overflow.c
new file mode 100644
index 0000000..52b2d2f
--- /dev/null
+++ b/libj2_j2i_sub_ji_to_j2i_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2i_sub_ji_to_j2i_overflow(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_ji.c */
+
+#endif
diff --git a/libj2_ji_add_j2i_overflow_p.c b/libj2_ji_add_j2i_overflow_p.c
new file mode 100644
index 0000000..82ccd0a
--- /dev/null
+++ b/libj2_ji_add_j2i_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ji_add_j2i_overflow_p(intmax_t a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Test in libj2_j2i_add_ji.c */
+
+#endif
diff --git a/libj2_ji_add_j2i_to_j2i.c b/libj2_ji_add_j2i_to_j2i.c
new file mode 100644
index 0000000..dafa114
--- /dev/null
+++ b/libj2_ji_add_j2i_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ji_add_j2i_to_j2i(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_add_ji.c */
+
+#endif
diff --git a/libj2_ji_add_j2i_to_j2i_overflow.c b/libj2_ji_add_j2i_to_j2i_overflow.c
new file mode 100644
index 0000000..bbdbd95
--- /dev/null
+++ b/libj2_ji_add_j2i_to_j2i_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ji_add_j2i_to_j2i_overflow(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_add_ji.c */
+
+#endif
diff --git a/libj2_ji_add_ji_to_j2i.c b/libj2_ji_add_ji_to_j2i.c
new file mode 100644
index 0000000..08bf2e1
--- /dev/null
+++ b/libj2_ji_add_ji_to_j2i.c
@@ -0,0 +1,153 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ji_add_ji_to_j2i(intmax_t a, intmax_t b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+static intmax_t
+random_ji(void)
+{
+ size_t n = LIBJ2_JU_BIT - 1U;
+ intmax_t r = 0;
+ while (n--)
+ if (rand() < rand())
+ r |= (intmax_t)1 << n;
+ if (rand() < rand()) {
+ r = -r;
+#if INTMAX_MIN + 1 == -INTMAX_MAX
+ r -= 1;
+#endif
+ }
+ return r;
+}
+
+
+static void
+get_expected(intmax_t a, intmax_t b, uintmax_t *expected_high, uintmax_t *expected_low)
+{
+ uintmax_t pos, neg;
+ if (a >= 0 && b >= 0) {
+ *expected_high = 0;
+ *expected_low = (uintmax_t)a + (uintmax_t)b;
+ } else if (a <= 0 && b <= 0) {
+ *expected_high = UINTMAX_MAX;
+ *expected_low = (uintmax_t)a + (uintmax_t)b;
+ } else if (a < 0) {
+ pos = (uintmax_t)b;
+ neg = (uintmax_t)-(a + 1) + 1U;
+ goto pos_neg;
+ } else {
+ pos = (uintmax_t)a;
+ neg = (uintmax_t)-(b + 1) + 1U;
+ pos_neg:
+ if (pos >= neg)
+ *expected_high = 0;
+ else
+ *expected_high = UINTMAX_MAX;
+ *expected_low = pos - neg;
+ }
+}
+
+
+static void
+check(intmax_t a, intmax_t b)
+{
+ struct libj2_j2i r;
+ uintmax_t expected_high, expected_low;
+
+ get_expected(a, b, &expected_high, &expected_low);
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_add_ji_to_j2i(a, b, &r);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+
+#if INTMAX_MIN + 1 == -INTMAX_MAX
+ if (a == INTMAX_MIN || b == INTMAX_MIN)
+ return;
+#endif
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_add_ji_to_j2i(-a, -b, &r);
+ libj2_minus_j2i(&r);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+}
+
+
+static void
+check_manual(intmax_t a, intmax_t b, uintmax_t expected_high, uintmax_t expected_low)
+{
+ struct libj2_j2i r;
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_add_ji_to_j2i(a, b, &r);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+
+#if INTMAX_MIN + 1 == -INTMAX_MAX
+ if (a == INTMAX_MIN || b == INTMAX_MIN)
+ goto check;
+#endif
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_add_ji_to_j2i(-a, -b, &r);
+ libj2_minus_j2i(&r);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+
+check:
+ check(a, b);
+}
+
+
+int
+main(void)
+{
+ unsigned i;
+
+ srand((unsigned)time(NULL));
+
+ check_manual(0, 0, 0, 0);
+ check_manual(0, INTMAX_MAX, 0, (uintmax_t)INTMAX_MAX);
+ check_manual(INTMAX_MAX, 0, 0, (uintmax_t)INTMAX_MAX);
+ check_manual(INTMAX_MAX, 1, 0, UINTMAX_MAX ^ (UINTMAX_MAX >> 1));
+ check_manual(1, INTMAX_MAX, 0, UINTMAX_MAX ^ (UINTMAX_MAX >> 1));
+ check_manual(INTMAX_MAX, INTMAX_MAX, 0, (uintmax_t)INTMAX_MAX << 1);
+
+ check_manual(0, -INTMAX_MAX, UINTMAX_MAX, (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)) + 1U);
+ check_manual(-INTMAX_MAX, 0, UINTMAX_MAX, (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)) + 1U);
+ check_manual(INTMAX_MAX, -1, 0, (uintmax_t)INTMAX_MAX - 1U);
+ check_manual(-1, INTMAX_MAX, 0, (uintmax_t)INTMAX_MAX - 1U);
+ check_manual(-INTMAX_MAX, 1, UINTMAX_MAX, (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)) + 2U);
+ check_manual(1, -INTMAX_MAX, UINTMAX_MAX, (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)) + 2U);
+ check_manual(INTMAX_MAX, -INTMAX_MAX, 0, 0);
+
+#if INTMAX_MIN + 1 == -INTMAX_MAX
+ check_manual(0, INTMAX_MIN, UINTMAX_MAX, UINTMAX_MAX ^ (UINTMAX_MAX >> 1));
+ check_manual(INTMAX_MIN, 0, UINTMAX_MAX, UINTMAX_MAX ^ (UINTMAX_MAX >> 1));
+ check_manual(INTMAX_MIN, 1, UINTMAX_MAX, (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)) + 1U);
+ check_manual(1, INTMAX_MIN, UINTMAX_MAX, (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)) + 1U);
+ check_manual(INTMAX_MIN, INTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX);
+ check_manual(INTMAX_MIN, -INTMAX_MAX, UINTMAX_MAX, 1);
+ check_manual(INTMAX_MIN, INTMAX_MIN, UINTMAX_MAX, 0);
+#endif
+
+ for (i = 0; i < 256; i++) {
+ check(0, random_ji());
+ check(1, random_ji());
+ check(random_ji(), 0);
+ check(random_ji(), 1);
+ check(random_ji(), random_ji());
+ check(random_ji(), INTMAX_MAX);
+ check(INTMAX_MAX, random_ji());
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_ji_mul_j2i_overflow_p.c b/libj2_ji_mul_j2i_overflow_p.c
new file mode 100644
index 0000000..07dec59
--- /dev/null
+++ b/libj2_ji_mul_j2i_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ji_mul_j2i_overflow_p(intmax_t a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_ji.c */
+
+#endif
diff --git a/libj2_ji_mul_j2i_overflow_p_quick.c b/libj2_ji_mul_j2i_overflow_p_quick.c
new file mode 100644
index 0000000..84e4c35
--- /dev/null
+++ b/libj2_ji_mul_j2i_overflow_p_quick.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline enum libj2_overflow libj2_ji_mul_j2i_overflow_p_quick(intmax_t a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_ji.c */
+
+#endif
diff --git a/libj2_ji_mul_j2i_to_j2i.c b/libj2_ji_mul_j2i_to_j2i.c
new file mode 100644
index 0000000..6fba771
--- /dev/null
+++ b/libj2_ji_mul_j2i_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ji_mul_j2i_to_j2i(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_ji.c */
+
+#endif
diff --git a/libj2_ji_mul_j2i_to_j2i_overflow.c b/libj2_ji_mul_j2i_to_j2i_overflow.c
new file mode 100644
index 0000000..3288e54
--- /dev/null
+++ b/libj2_ji_mul_j2i_to_j2i_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ji_mul_j2i_to_j2i_overflow(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_ji.c */
+
+#endif
diff --git a/libj2_ji_mul_j2i_to_j2i_overflow_p.c b/libj2_ji_mul_j2i_to_j2i_overflow_p.c
new file mode 100644
index 0000000..2b02413
--- /dev/null
+++ b/libj2_ji_mul_j2i_to_j2i_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ji_mul_j2i_to_j2i_overflow_p(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res, int *res_set);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_ji.c */
+
+#endif
diff --git a/libj2_ji_mul_ji_to_j2i.c b/libj2_ji_mul_ji_to_j2i.c
new file mode 100644
index 0000000..ada66cc
--- /dev/null
+++ b/libj2_ji_mul_ji_to_j2i.c
@@ -0,0 +1,221 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ji_mul_ji_to_j2i(intmax_t a, intmax_t b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+static uintmax_t
+random_small_ju(size_t bits)
+{
+ uintmax_t r = 0;
+ while (bits--)
+ if (rand() < rand())
+ r |= (uintmax_t)1 << bits;
+ return r;
+}
+
+static uintmax_t
+random_hju(void)
+{
+ return random_small_ju(LIBJ2_JU_BIT / 2U);
+}
+
+static uintmax_t
+random_ju(void)
+{
+ return random_small_ju(LIBJ2_JU_BIT);
+}
+
+static intmax_t
+random_ji(void)
+{
+ uintmax_t u;
+ u = random_small_ju(LIBJ2_JU_BIT);
+ if (u >> (LIBJ2_JU_BIT - 1U))
+ return (intmax_t)u;
+ return (intmax_t)~u - 1;
+}
+
+
+static void
+mul(intmax_t a, intmax_t b, struct libj2_j2i *expected)
+{
+ int neg = (a < 0) ^ (b < 0);
+ uintmax_t u = a < 0 ? (uintmax_t)-(a + 1U) + 1U : (uintmax_t)a;
+ uintmax_t v = b < 0 ? (uintmax_t)-(b + 1U) + 1U : (uintmax_t)b;
+ struct libj2_j2u c;
+ libj2_ju_mul_ju_to_j2u(u, v, &c);
+ libj2_j2u_to_j2i(&c, expected);
+ if (neg)
+ libj2_minus_j2i(expected);
+}
+
+
+int
+main(void)
+{
+ struct libj2_j2i r, expected;
+ intmax_t u, v;
+ unsigned i;
+
+ srand((unsigned)time(NULL));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(0, 0, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(0, 1, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(0, -1, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(0, INTMAX_MAX, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(0, -INTMAX_MAX, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(0, INTMAX_MIN, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(1, 0, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(-1, 0, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(INTMAX_MAX, 0, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(-INTMAX_MAX, 0, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(INTMAX_MIN, 0, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ for (i = 0; i < 32; i++) {
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(0, random_ji(), &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(random_ji(), 0, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+ }
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(1, 1, &r);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == 1);
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(4, 4, &r);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == 16);
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(2, 3, &r);
+ EXPECT(libj2_j2i_eq_ji(&r, 6));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(2, -3, &r);
+ EXPECT(libj2_j2i_eq_ji(&r, -6));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(-2, 3, &r);
+ EXPECT(libj2_j2i_eq_ji(&r, -6));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(-2, -3, &r);
+ EXPECT(libj2_j2i_eq_ji(&r, 6));
+
+ for (i = 0; i < 32; i++) {
+ r = (struct libj2_j2i){111, 222};
+ v = (intmax_t)(random_ju() >> 1);
+ libj2_ji_mul_ji_to_j2i(1, v, &r);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == (uintmax_t)v);
+
+ r = (struct libj2_j2i){111, 222};
+ v = (intmax_t)(random_ju() >> 1);
+ libj2_ji_mul_ji_to_j2i(v, 1, &r);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == (uintmax_t)v);
+ }
+
+ for (i = 0; i < 32; i++) {
+ u = (intmax_t)random_hju();
+ v = (intmax_t)random_hju();
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(u, v, &r);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == (uintmax_t)u * (uintmax_t)v);
+
+ libj2_ji_mul_ji_to_j2i(v, u, &r);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == (uintmax_t)u * (uintmax_t)v);
+ }
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(INTMAX_MAX, INTMAX_MAX, &r);
+ EXPECT(r.high == (uintmax_t)INTMAX_MAX >> 1);
+ EXPECT(r.low == 1);
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(INTMAX_MAX, -INTMAX_MAX, &r);
+ libj2_minus_j2i(&r);
+ EXPECT(r.high == (uintmax_t)INTMAX_MAX >> 1);
+ EXPECT(r.low == 1);
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(-INTMAX_MAX, INTMAX_MAX, &r);
+ libj2_minus_j2i(&r);
+ EXPECT(r.high == (uintmax_t)INTMAX_MAX >> 1);
+ EXPECT(r.low == 1);
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(-INTMAX_MAX, -INTMAX_MAX, &r);
+ EXPECT(r.high == (uintmax_t)INTMAX_MAX >> 1);
+ EXPECT(r.low == 1);
+
+#if INTMAX_MIN + 1 == -INTMAX_MAX
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(INTMAX_MIN, INTMAX_MIN, &r);
+ EXPECT(r.high == ((uintmax_t)INTMAX_MAX + 1U) >> 1);
+ EXPECT(r.low == 0);
+#endif
+
+ for (i = 0; i < 256; i++) {
+ u = random_ji();
+ v = random_ji();
+
+ mul(u, v, &expected);
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_mul_ji_to_j2i(u, v, &r);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ libj2_ji_mul_ji_to_j2i(v, u, &r);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_ji_sub_j2i_overflow_p.c b/libj2_ji_sub_j2i_overflow_p.c
new file mode 100644
index 0000000..afd2d4d
--- /dev/null
+++ b/libj2_ji_sub_j2i_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ji_sub_j2i_overflow_p(intmax_t a, const struct libj2_j2i *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_ji.c */
+
+#endif
diff --git a/libj2_ji_sub_j2i_to_j2i.c b/libj2_ji_sub_j2i_to_j2i.c
new file mode 100644
index 0000000..d77aca3
--- /dev/null
+++ b/libj2_ji_sub_j2i_to_j2i.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ji_sub_j2i_to_j2i(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_ji.c */
+
+#endif
diff --git a/libj2_ji_sub_j2i_to_j2i_overflow.c b/libj2_ji_sub_j2i_to_j2i_overflow.c
new file mode 100644
index 0000000..ff8a3a4
--- /dev/null
+++ b/libj2_ji_sub_j2i_to_j2i_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ji_sub_j2i_to_j2i_overflow(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested libj2_j2i_sub_ji.c */
+
+#endif
diff --git a/libj2_ji_sub_ji_to_j2i.c b/libj2_ji_sub_ji_to_j2i.c
new file mode 100644
index 0000000..018c93c
--- /dev/null
+++ b/libj2_ji_sub_ji_to_j2i.c
@@ -0,0 +1,94 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ji_sub_ji_to_j2i(intmax_t a, intmax_t b, struct libj2_j2i *res);
+/* TODO Add man page */
+
+
+#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(uintmax_t ua, uintmax_t ub)
+{
+ intmax_t a = ua >> (LIBJ2_JU_BIT - 1U) ? -(intmax_t)~ua - 1 : (intmax_t)ua;
+ intmax_t b = ub >> (LIBJ2_JU_BIT - 1U) ? -(intmax_t)~ub - 1 : (intmax_t)ub;
+ struct libj2_j2i r, expected;
+ struct libj2_j2u wa, wb;
+
+#if INTMAX_MIN + 1 != -INTMAX_MAX
+ if (ua == (UINTMAX >> 1) + 1U || ub == (UINTMAX >> 1) + 1U)
+ return;
+#endif
+
+ wa.low = ua;
+ wb.low = ub;
+
+ wa.high = a < 0 ? UINTMAX_MAX : 0;
+ wb.high = b < 0 ? UINTMAX_MAX : 0;
+
+ libj2_minus_j2u(&wb);
+ libj2_j2u_add_j2u_to_j2u(&wa, &wb, (void *)&expected);
+ libj2_ji_sub_ji_to_j2i(a, b, &r);
+ EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+}
+
+
+int
+main(void)
+{
+ uintmax_t a, b, max, min, umax, vs[12];
+ unsigned i, j, k;
+
+ srand((unsigned)time(NULL));
+
+ umax = UINTMAX_MAX;
+ max = umax >> 1;
+ min = ~max;
+
+ vs[0] = 0U;
+ vs[1] = 1U;
+ vs[2] = 2U;
+ vs[3] = umax - 0U;
+ vs[4] = umax - 1U;
+ vs[5] = umax - 2U;
+ vs[6] = max - 0U;
+ vs[7] = max - 1U;
+ vs[8] = max - 2U;
+ vs[9] = min + 0U;
+ vs[10] = min + 1U;
+ vs[11] = min + 2U;
+
+ for (i = 0; i < 12U; i++)
+ for (j = 0; j < 12U; j++)
+ check(vs[i], vs[j]);
+ for (j = 0; j < 256U; j++) {
+ for (k = 0; k < 4U; k++) {
+ a = random_ju() >> 1;
+ b = random_ju() >> 1;
+ if (k & 1U) a = ~a;
+ if (k & 2U) b = ~b;
+ check(a, b);
+ for (i = 0; k < 2U && i < 12U; i++) {
+ check(a, vs[i]);
+ check(vs[i], a);
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_ju_mul_ju_to_j2u.c b/libj2_ju_mul_ju_to_j2u.c
index 11daad4..4a4faf7 100644
--- a/libj2_ju_mul_ju_to_j2u.c
+++ b/libj2_ju_mul_ju_to_j2u.c
@@ -129,6 +129,11 @@ main(void)
EXPECT(r.high == UINTMAX_MAX - 1U);
EXPECT(r.low == 1);
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_ju_to_j2u(UINTMAX_MAX >> 1, UINTMAX_MAX >> 1, &r);
+ EXPECT(r.high == UINTMAX_MAX >> 2);
+ EXPECT(r.low == 1);
+
for (i = 0; i < 256; i++) {
u = random_ju();
v = random_ju();
diff --git a/libj2_minus_j2i.c b/libj2_minus_j2i.c
index bac519f..805afde 100644
--- a/libj2_minus_j2i.c
+++ b/libj2_minus_j2i.c
@@ -73,7 +73,6 @@ main(void)
EXPECT(a.low == 0U - v);
}
-#ifdef TODO /* requires libj2_j2i_add_j2i */
for (i = 0; i < 256; i++) {
a.high = b.high = random_ju() >> 1;
a.low = b.low = random_ju();
@@ -87,7 +86,6 @@ main(void)
libj2_j2i_add_j2i(&a, &b);
EXPECT(libj2_j2i_is_zero(&a));
}
-#endif
return 0;
}
diff --git a/libj2_vmax_j2i_to_j2i.c b/libj2_vmax_j2i_to_j2i.c
index 712cb9f..3606393 100644
--- a/libj2_vmax_j2i_to_j2i.c
+++ b/libj2_vmax_j2i_to_j2i.c
@@ -8,6 +8,6 @@ extern inline void libj2_vmax_j2i_to_j2i(const struct libj2_j2i *a, va_list args
#else
-CONST int main(void) { return 0; } /* Tested via libj2_vmax_j2i_to_j2i */
+CONST int main(void) { return 0; } /* Tested via libj2_max_j2i_to_j2i */
#endif
diff --git a/libj2_vmax_j2u_to_j2u.c b/libj2_vmax_j2u_to_j2u.c
index 9b421dc..616c196 100644
--- a/libj2_vmax_j2u_to_j2u.c
+++ b/libj2_vmax_j2u_to_j2u.c
@@ -8,6 +8,6 @@ extern inline void libj2_vmax_j2u_to_j2u(const struct libj2_j2u *a, va_list args
#else
-CONST int main(void) { return 0; } /* Tested via libj2_vmax_j2u_to_j2u */
+CONST int main(void) { return 0; } /* Tested via libj2_max_j2u_to_j2u */
#endif
diff --git a/libj2_vmin_j2i_to_j2i.c b/libj2_vmin_j2i_to_j2i.c
index 3ab12d5..ba8d4ed 100644
--- a/libj2_vmin_j2i_to_j2i.c
+++ b/libj2_vmin_j2i_to_j2i.c
@@ -8,6 +8,6 @@ extern inline void libj2_vmin_j2i_to_j2i(const struct libj2_j2i *a, va_list args
#else
-CONST int main(void) { return 0; } /* Tested via libj2_vmin_j2i_to_j2i */
+CONST int main(void) { return 0; } /* Tested via libj2_min_j2i_to_j2i */
#endif
diff --git a/libj2_vmin_j2u_to_j2u.c b/libj2_vmin_j2u_to_j2u.c
index 021e5ee..2cd4460 100644
--- a/libj2_vmin_j2u_to_j2u.c
+++ b/libj2_vmin_j2u_to_j2u.c
@@ -8,6 +8,6 @@ extern inline void libj2_vmin_j2u_to_j2u(const struct libj2_j2u *a, va_list args
#else
-CONST int main(void) { return 0; } /* Tested via libj2_vmin_j2u_to_j2u */
+CONST int main(void) { return 0; } /* Tested via libj2_min_j2u_to_j2u */
#endif