aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2025-12-04 19:25:47 +0100
committerMattias Andrée <m@maandree.se>2025-12-04 19:25:47 +0100
commit2bf851de6dd3a64f91a72a9afba2b3637dbbe154 (patch)
tree5326b90653cb19bbe3749522c95d33ac736167bf
downloadlibj2-2bf851de6dd3a64f91a72a9afba2b3637dbbe154.tar.gz
libj2-2bf851de6dd3a64f91a72a9afba2b3637dbbe154.tar.bz2
libj2-2bf851de6dd3a64f91a72a9afba2b3637dbbe154.tar.xz
First commit
Signed-off-by: Mattias Andrée <m@maandree.se>
-rw-r--r--.gitignore15
-rw-r--r--LICENSE15
-rw-r--r--Makefile300
-rw-r--r--README15
-rw-r--r--common.h29
-rw-r--r--config.mk8
-rw-r--r--libj2.720
-rw-r--r--libj2.h62
-rw-r--r--libj2/addition.h313
-rw-r--r--libj2/bit-shifting.h573
-rw-r--r--libj2/bitwise-logic.h980
-rw-r--r--libj2/constants.h94
-rw-r--r--libj2/constructors.h24
-rw-r--r--libj2/division.h534
-rw-r--r--libj2/multiplication.h366
-rw-r--r--libj2/sign-shifting.h43
-rw-r--r--libj2/signum.h45
-rw-r--r--libj2/subtraction.h493
-rw-r--r--libj2/unsigned-comparsion.h774
-rw-r--r--libj2_j2u_add_j2u.c201
-rw-r--r--libj2_j2u_add_j2u_overflow.c13
-rw-r--r--libj2_j2u_add_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_add_j2u_to_j2u_overflow.c13
-rw-r--r--libj2_j2u_add_ju.c301
-rw-r--r--libj2_j2u_add_ju_overflow.c13
-rw-r--r--libj2_j2u_add_ju_to_j2u.c13
-rw-r--r--libj2_j2u_add_ju_to_j2u_overflow.c13
-rw-r--r--libj2_j2u_and_j2u.c140
-rw-r--r--libj2_j2u_and_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_and_ju.c13
-rw-r--r--libj2_j2u_and_ju_to_j2u.c13
-rw-r--r--libj2_j2u_cmp_j2u.c200
-rw-r--r--libj2_j2u_cmp_ju.c145
-rw-r--r--libj2_j2u_div_j2u.c13
-rw-r--r--libj2_j2u_div_j2u_return.c13
-rw-r--r--libj2_j2u_div_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_div_ju.c13
-rw-r--r--libj2_j2u_div_ju_return.c13
-rw-r--r--libj2_j2u_div_ju_to_j2u.c13
-rw-r--r--libj2_j2u_divmod_j2u.c13
-rw-r--r--libj2_j2u_divmod_j2u_to_j2u.c389
-rw-r--r--libj2_j2u_divmod_j2u_to_j2u_j2u.c14
-rw-r--r--libj2_j2u_divmod_ju.c13
-rw-r--r--libj2_j2u_divmod_ju_to_j2u.c13
-rw-r--r--libj2_j2u_divmod_ju_to_j2u_j2u.c13
-rw-r--r--libj2_j2u_eq_j2u.c13
-rw-r--r--libj2_j2u_eq_ju.c13
-rw-r--r--libj2_j2u_ge_j2u.c13
-rw-r--r--libj2_j2u_ge_ju.c13
-rw-r--r--libj2_j2u_gt_j2u.c13
-rw-r--r--libj2_j2u_gt_ju.c13
-rw-r--r--libj2_j2u_if_j2u.c140
-rw-r--r--libj2_j2u_if_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_if_ju.c13
-rw-r--r--libj2_j2u_if_ju_to_j2u.c13
-rw-r--r--libj2_j2u_imply_j2u.c140
-rw-r--r--libj2_j2u_imply_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_imply_ju.c13
-rw-r--r--libj2_j2u_imply_ju_to_j2u.c13
-rw-r--r--libj2_j2u_is_max.c197
-rw-r--r--libj2_j2u_is_min.c197
-rw-r--r--libj2_j2u_is_positive.c197
-rw-r--r--libj2_j2u_is_zero.c197
-rw-r--r--libj2_j2u_le_j2u.c13
-rw-r--r--libj2_j2u_le_ju.c13
-rw-r--r--libj2_j2u_lrot.c81
-rw-r--r--libj2_j2u_lrot_to_j2u.c13
-rw-r--r--libj2_j2u_lsh.c172
-rw-r--r--libj2_j2u_lsh_overflow.c13
-rw-r--r--libj2_j2u_lsh_to_j2u.c13
-rw-r--r--libj2_j2u_lsh_to_j2u_overflow.c13
-rw-r--r--libj2_j2u_lt_j2u.c13
-rw-r--r--libj2_j2u_lt_ju.c13
-rw-r--r--libj2_j2u_max.c27
-rw-r--r--libj2_j2u_max_j2u.c13
-rw-r--r--libj2_j2u_max_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_max_ju.c13
-rw-r--r--libj2_j2u_max_ju_to_j2u.c13
-rw-r--r--libj2_j2u_min.c27
-rw-r--r--libj2_j2u_min_j2u.c13
-rw-r--r--libj2_j2u_min_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_min_ju.c13
-rw-r--r--libj2_j2u_min_ju_to_j2u.c13
-rw-r--r--libj2_j2u_mod_j2u.c13
-rw-r--r--libj2_j2u_mod_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_mod_ju.c13
-rw-r--r--libj2_j2u_mod_ju_to_j2u.c13
-rw-r--r--libj2_j2u_mul_j2u.c13
-rw-r--r--libj2_j2u_mul_j2u_destructive.c267
-rw-r--r--libj2_j2u_mul_j2u_overflow.c13
-rw-r--r--libj2_j2u_mul_j2u_overflow_destructive.c13
-rw-r--r--libj2_j2u_mul_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_mul_j2u_to_j2u_overflow.c13
-rw-r--r--libj2_j2u_mul_ju.c197
-rw-r--r--libj2_j2u_mul_ju_overflow.c13
-rw-r--r--libj2_j2u_mul_ju_to_j2u.c13
-rw-r--r--libj2_j2u_mul_ju_to_j2u_overflow.c13
-rw-r--r--libj2_j2u_nand_j2u.c143
-rw-r--r--libj2_j2u_nand_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_nand_ju.c13
-rw-r--r--libj2_j2u_nand_ju_to_j2u.c13
-rw-r--r--libj2_j2u_ne_j2u.c13
-rw-r--r--libj2_j2u_ne_ju.c13
-rw-r--r--libj2_j2u_nif_j2u.c140
-rw-r--r--libj2_j2u_nif_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_nif_ju.c13
-rw-r--r--libj2_j2u_nif_ju_to_j2u.c13
-rw-r--r--libj2_j2u_nimply_j2u.c140
-rw-r--r--libj2_j2u_nimply_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_nimply_ju.c13
-rw-r--r--libj2_j2u_nimply_ju_to_j2u.c13
-rw-r--r--libj2_j2u_nor_j2u.c143
-rw-r--r--libj2_j2u_nor_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_nor_ju.c13
-rw-r--r--libj2_j2u_nor_ju_to_j2u.c13
-rw-r--r--libj2_j2u_or_j2u.c140
-rw-r--r--libj2_j2u_or_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_or_ju.c13
-rw-r--r--libj2_j2u_or_ju_to_j2u.c13
-rw-r--r--libj2_j2u_rdiv_j2u.c13
-rw-r--r--libj2_j2u_rdivmod_j2u.c13
-rw-r--r--libj2_j2u_rdivmod_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_rmod_j2u.c13
-rw-r--r--libj2_j2u_rrot.c13
-rw-r--r--libj2_j2u_rrot_to_j2u.c13
-rw-r--r--libj2_j2u_rsh.c129
-rw-r--r--libj2_j2u_rsh_to_j2u.c13
-rw-r--r--libj2_j2u_rsh_to_j2u_underflow.c13
-rw-r--r--libj2_j2u_rsh_underflow.c13
-rw-r--r--libj2_j2u_rsub_j2u.c13
-rw-r--r--libj2_j2u_rsub_j2u_overflow.c13
-rw-r--r--libj2_j2u_rsub_ju.c13
-rw-r--r--libj2_j2u_rsub_ju_overflow.c13
-rw-r--r--libj2_j2u_sub_j2u.c213
-rw-r--r--libj2_j2u_sub_j2u_overflow.c13
-rw-r--r--libj2_j2u_sub_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_sub_j2u_to_j2u_overflow.c13
-rw-r--r--libj2_j2u_sub_ju.c142
-rw-r--r--libj2_j2u_sub_ju_overflow.c13
-rw-r--r--libj2_j2u_sub_ju_to_j2u.c13
-rw-r--r--libj2_j2u_sub_ju_to_j2u_overflow.c13
-rw-r--r--libj2_j2u_test_bit.c39
-rw-r--r--libj2_j2u_test_high_ju.c35
-rw-r--r--libj2_j2u_test_j2u.c90
-rw-r--r--libj2_j2u_test_ju.c35
-rw-r--r--libj2_j2u_xnor_j2u.c140
-rw-r--r--libj2_j2u_xnor_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_xnor_ju.c13
-rw-r--r--libj2_j2u_xnor_ju_to_j2u.c13
-rw-r--r--libj2_j2u_xor_j2u.c140
-rw-r--r--libj2_j2u_xor_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_xor_ju.c13
-rw-r--r--libj2_j2u_xor_ju_to_j2u.c13
-rw-r--r--libj2_j2u_zero.c27
-rw-r--r--libj2_ju_add_j2u_to_j2u.c13
-rw-r--r--libj2_ju_add_j2u_to_j2u_overflow.c13
-rw-r--r--libj2_ju_add_ju_to_j2u.c95
-rw-r--r--libj2_ju_and_j2u_to_j2u.c13
-rw-r--r--libj2_ju_cmp_j2u.c13
-rw-r--r--libj2_ju_eq_j2u.c13
-rw-r--r--libj2_ju_ge_j2u.c13
-rw-r--r--libj2_ju_gt_j2u.c13
-rw-r--r--libj2_ju_if_j2u_to_j2u.c13
-rw-r--r--libj2_ju_imply_j2u_to_j2u.c13
-rw-r--r--libj2_ju_le_j2u.c13
-rw-r--r--libj2_ju_lrot_to_j2u.c64
-rw-r--r--libj2_ju_lsh_to_j2u.c171
-rw-r--r--libj2_ju_lsh_to_j2u_overflow.c13
-rw-r--r--libj2_ju_lt_j2u.c13
-rw-r--r--libj2_ju_mul_j2u_to_j2u.c13
-rw-r--r--libj2_ju_mul_j2u_to_j2u_overflow.c13
-rw-r--r--libj2_ju_mul_ju_to_j2u.c149
-rw-r--r--libj2_ju_nand_j2u_to_j2u.c13
-rw-r--r--libj2_ju_ne_j2u.c13
-rw-r--r--libj2_ju_nif_j2u_to_j2u.c13
-rw-r--r--libj2_ju_nimply_j2u_to_j2u.c13
-rw-r--r--libj2_ju_nor_j2u_to_j2u.c13
-rw-r--r--libj2_ju_or_j2u_to_j2u.c13
-rw-r--r--libj2_ju_rrot_to_j2u.c13
-rw-r--r--libj2_ju_rsh_to_j2u.c121
-rw-r--r--libj2_ju_rsh_to_j2u_underflow.c13
-rw-r--r--libj2_ju_sub_j2u_to_j2u.c13
-rw-r--r--libj2_ju_sub_j2u_to_j2u_overflow.c13
-rw-r--r--libj2_ju_sub_ju_to_j2u.c64
-rw-r--r--libj2_ju_sub_ju_to_j2u_overflow.c13
-rw-r--r--libj2_ju_to_j2u.c29
-rw-r--r--libj2_ju_xnor_j2u_to_j2u.c13
-rw-r--r--libj2_ju_xor_j2u_to_j2u.c13
-rw-r--r--libj2_max_j2u.c177
-rw-r--r--libj2_max_j2u_return.c13
-rw-r--r--libj2_max_j2u_to_j2u.c13
-rw-r--r--libj2_min_j2u.c189
-rw-r--r--libj2_min_j2u_return.c13
-rw-r--r--libj2_min_j2u_to_j2u.c13
-rw-r--r--libj2_minus_j2u.c79
-rw-r--r--libj2_minus_j2u_to_j2u.c13
-rw-r--r--libj2_not_j2u.c34
-rw-r--r--libj2_not_j2u_to_j2u.c46
-rw-r--r--libj2_not_ju_to_j2u.c34
-rw-r--r--libj2_sgn_j2u.c197
-rw-r--r--libj2_vmax_j2u.c13
-rw-r--r--libj2_vmax_j2u_return.c13
-rw-r--r--libj2_vmax_j2u_to_j2u.c13
-rw-r--r--libj2_vmin_j2u.c13
-rw-r--r--libj2_vmin_j2u_return.c13
-rw-r--r--libj2_vmin_j2u_to_j2u.c13
-rw-r--r--mk/linux.mk6
-rw-r--r--mk/macos.mk6
-rw-r--r--mk/windows.mk6
209 files changed, 12902 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..63f1b10
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+*\#*
+*~
+*.o
+*.a
+*.lo
+*.su
+*.so
+*.so.*
+*.dll
+*.dylib
+*.gch
+*.gcov
+*.gcno
+*.gcda
+*.t
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..0e6be1c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+© 2025 Mattias Andrée <m@maandree.se>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..482e2b3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,300 @@
+.POSIX:
+
+CONFIGFILE = config.mk
+include $(CONFIGFILE)
+
+OS = linux
+# Linux: linux
+# Mac OS: macos
+# Windows: windows
+include mk/$(OS).mk
+
+
+LIB_MAJOR = 1
+LIB_MINOR = 0
+LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR)
+LIB_NAME = j2
+
+
+OBJ =\
+ libj2_j2u_add_j2u.o\
+ libj2_j2u_add_j2u_overflow.o\
+ libj2_j2u_add_j2u_to_j2u.o\
+ libj2_j2u_add_j2u_to_j2u_overflow.o\
+ libj2_j2u_add_ju.o\
+ libj2_j2u_add_ju_overflow.o\
+ libj2_j2u_add_ju_to_j2u.o\
+ libj2_j2u_add_ju_to_j2u_overflow.o\
+ libj2_j2u_and_j2u.o\
+ libj2_j2u_and_j2u_to_j2u.o\
+ libj2_j2u_and_ju.o\
+ libj2_j2u_and_ju_to_j2u.o\
+ libj2_j2u_cmp_j2u.o\
+ libj2_j2u_cmp_ju.o\
+ libj2_j2u_div_j2u.o\
+ libj2_j2u_div_j2u_return.o\
+ libj2_j2u_div_j2u_to_j2u.o\
+ libj2_j2u_div_ju.o\
+ libj2_j2u_div_ju_return.o\
+ libj2_j2u_div_ju_to_j2u.o\
+ libj2_j2u_divmod_j2u.o\
+ libj2_j2u_divmod_j2u_to_j2u.o\
+ libj2_j2u_divmod_j2u_to_j2u_j2u.o\
+ libj2_j2u_divmod_ju.o\
+ libj2_j2u_divmod_ju_to_j2u.o\
+ libj2_j2u_divmod_ju_to_j2u_j2u.o\
+ libj2_j2u_eq_j2u.o\
+ libj2_j2u_eq_ju.o\
+ libj2_j2u_ge_j2u.o\
+ libj2_j2u_ge_ju.o\
+ libj2_j2u_gt_j2u.o\
+ libj2_j2u_gt_ju.o\
+ libj2_j2u_if_j2u.o\
+ libj2_j2u_if_j2u_to_j2u.o\
+ libj2_j2u_if_ju.o\
+ libj2_j2u_if_ju_to_j2u.o\
+ libj2_j2u_imply_j2u.o\
+ libj2_j2u_imply_j2u_to_j2u.o\
+ libj2_j2u_imply_ju.o\
+ libj2_j2u_imply_ju_to_j2u.o\
+ libj2_j2u_is_max.o\
+ libj2_j2u_is_min.o\
+ libj2_j2u_is_positive.o\
+ libj2_j2u_is_zero.o\
+ libj2_j2u_le_j2u.o\
+ libj2_j2u_le_ju.o\
+ libj2_j2u_lrot.o\
+ libj2_j2u_lrot_to_j2u.o\
+ libj2_j2u_lsh.o\
+ libj2_j2u_lsh_overflow.o\
+ libj2_j2u_lsh_to_j2u.o\
+ libj2_j2u_lsh_to_j2u_overflow.o\
+ libj2_j2u_lt_j2u.o\
+ libj2_j2u_lt_ju.o\
+ libj2_j2u_max.o\
+ libj2_j2u_max_j2u.o\
+ libj2_j2u_max_j2u_to_j2u.o\
+ libj2_j2u_max_ju.o\
+ libj2_j2u_max_ju_to_j2u.o\
+ libj2_j2u_min.o\
+ libj2_j2u_min_j2u.o\
+ libj2_j2u_min_j2u_to_j2u.o\
+ libj2_j2u_min_ju.o\
+ libj2_j2u_min_ju_to_j2u.o\
+ libj2_j2u_mod_j2u.o\
+ libj2_j2u_mod_j2u_to_j2u.o\
+ libj2_j2u_mod_ju.o\
+ libj2_j2u_mod_ju_to_j2u.o\
+ libj2_j2u_mul_j2u.o\
+ libj2_j2u_mul_j2u_destructive.o\
+ libj2_j2u_mul_j2u_overflow.o\
+ libj2_j2u_mul_j2u_overflow_destructive.o\
+ libj2_j2u_mul_j2u_to_j2u.o\
+ libj2_j2u_mul_j2u_to_j2u_overflow.o\
+ libj2_j2u_mul_ju.o\
+ libj2_j2u_mul_ju_overflow.o\
+ libj2_j2u_mul_ju_to_j2u.o\
+ libj2_j2u_mul_ju_to_j2u_overflow.o\
+ libj2_j2u_nand_j2u.o\
+ libj2_j2u_nand_j2u_to_j2u.o\
+ libj2_j2u_nand_ju.o\
+ libj2_j2u_nand_ju_to_j2u.o\
+ libj2_j2u_ne_j2u.o\
+ libj2_j2u_ne_ju.o\
+ libj2_j2u_nif_j2u.o\
+ libj2_j2u_nif_j2u_to_j2u.o\
+ libj2_j2u_nif_ju.o\
+ libj2_j2u_nif_ju_to_j2u.o\
+ libj2_j2u_nimply_j2u.o\
+ libj2_j2u_nimply_j2u_to_j2u.o\
+ libj2_j2u_nimply_ju.o\
+ libj2_j2u_nimply_ju_to_j2u.o\
+ libj2_j2u_nor_j2u.o\
+ libj2_j2u_nor_j2u_to_j2u.o\
+ libj2_j2u_nor_ju.o\
+ libj2_j2u_nor_ju_to_j2u.o\
+ libj2_j2u_or_j2u.o\
+ libj2_j2u_or_j2u_to_j2u.o\
+ libj2_j2u_or_ju.o\
+ libj2_j2u_or_ju_to_j2u.o\
+ libj2_j2u_rdiv_j2u.o\
+ libj2_j2u_rdivmod_j2u.o\
+ libj2_j2u_rdivmod_j2u_to_j2u.o\
+ libj2_j2u_rmod_j2u.o\
+ libj2_j2u_rrot.o\
+ libj2_j2u_rrot_to_j2u.o\
+ libj2_j2u_rsh.o\
+ libj2_j2u_rsh_to_j2u.o\
+ libj2_j2u_rsh_to_j2u_underflow.o\
+ libj2_j2u_rsh_underflow.o\
+ libj2_j2u_rsub_j2u.o\
+ libj2_j2u_rsub_j2u_overflow.o\
+ libj2_j2u_rsub_ju.o\
+ libj2_j2u_rsub_ju_overflow.o\
+ libj2_j2u_sub_j2u.o\
+ libj2_j2u_sub_j2u_overflow.o\
+ libj2_j2u_sub_j2u_to_j2u.o\
+ libj2_j2u_sub_j2u_to_j2u_overflow.o\
+ libj2_j2u_sub_ju.o\
+ libj2_j2u_sub_ju_overflow.o\
+ libj2_j2u_sub_ju_to_j2u.o\
+ libj2_j2u_sub_ju_to_j2u_overflow.o\
+ libj2_j2u_test_bit.o\
+ libj2_j2u_test_high_ju.o\
+ libj2_j2u_test_j2u.o\
+ libj2_j2u_test_ju.o\
+ libj2_j2u_xnor_j2u.o\
+ libj2_j2u_xnor_j2u_to_j2u.o\
+ libj2_j2u_xnor_ju.o\
+ libj2_j2u_xnor_ju_to_j2u.o\
+ libj2_j2u_xor_j2u.o\
+ libj2_j2u_xor_j2u_to_j2u.o\
+ libj2_j2u_xor_ju.o\
+ libj2_j2u_xor_ju_to_j2u.o\
+ libj2_j2u_zero.o\
+ libj2_ju_add_j2u_to_j2u.o\
+ libj2_ju_add_j2u_to_j2u_overflow.o\
+ libj2_ju_add_ju_to_j2u.o\
+ libj2_ju_and_j2u_to_j2u.o\
+ libj2_ju_cmp_j2u.o\
+ libj2_ju_eq_j2u.o\
+ libj2_ju_ge_j2u.o\
+ libj2_ju_gt_j2u.o\
+ libj2_ju_if_j2u_to_j2u.o\
+ libj2_ju_imply_j2u_to_j2u.o\
+ libj2_ju_le_j2u.o\
+ libj2_ju_lrot_to_j2u.o\
+ libj2_ju_lsh_to_j2u.o\
+ libj2_ju_lsh_to_j2u_overflow.o\
+ libj2_ju_lt_j2u.o\
+ libj2_ju_mul_j2u_to_j2u.o\
+ libj2_ju_mul_j2u_to_j2u_overflow.o\
+ libj2_ju_mul_ju_to_j2u.o\
+ libj2_ju_nand_j2u_to_j2u.o\
+ libj2_ju_ne_j2u.o\
+ libj2_ju_nif_j2u_to_j2u.o\
+ libj2_ju_nimply_j2u_to_j2u.o\
+ libj2_ju_nor_j2u_to_j2u.o\
+ libj2_ju_or_j2u_to_j2u.o\
+ libj2_ju_rrot_to_j2u.o\
+ libj2_ju_rsh_to_j2u.o\
+ libj2_ju_rsh_to_j2u_underflow.o\
+ libj2_ju_sub_j2u_to_j2u.o\
+ libj2_ju_sub_j2u_to_j2u_overflow.o\
+ libj2_ju_sub_ju_to_j2u.o\
+ libj2_ju_sub_ju_to_j2u_overflow.o\
+ libj2_ju_to_j2u.o\
+ libj2_ju_xnor_j2u_to_j2u.o\
+ libj2_ju_xor_j2u_to_j2u.o\
+ libj2_max_j2u.o\
+ libj2_max_j2u_return.o\
+ libj2_max_j2u_to_j2u.o\
+ libj2_min_j2u.o\
+ libj2_min_j2u_return.o\
+ libj2_min_j2u_to_j2u.o\
+ libj2_minus_j2u.o\
+ libj2_minus_j2u_to_j2u.o\
+ libj2_not_j2u.o\
+ libj2_not_j2u_to_j2u.o\
+ libj2_not_ju_to_j2u.o\
+ libj2_sgn_j2u.o\
+ libj2_vmax_j2u.o\
+ libj2_vmax_j2u_return.o\
+ libj2_vmax_j2u_to_j2u.o\
+ libj2_vmin_j2u.o\
+ libj2_vmin_j2u_return.o\
+ libj2_vmin_j2u_to_j2u.o
+
+SUBHDR =\
+ libj2/constants.h\
+ libj2/signum.h\
+ libj2/constructors.h\
+ libj2/unsigned-comparsion.h\
+ libj2/bitwise-logic.h\
+ libj2/bit-shifting.h\
+ libj2/sign-shifting.h\
+ libj2/addition.h\
+ libj2/subtraction.h\
+ libj2/multiplication.h\
+ libj2/division.h
+
+HDR =\
+ $(SUBHDR)\
+ libj2.h\
+ common.h
+
+LOBJ = $(OBJ:.o=.lo)
+TOBJ = $(OBJ:.o=.to)
+TEST = $(OBJ:.o=.t)
+
+MAN7 = libj2.7
+
+
+all: libj2.a libj2.$(LIBEXT) $(TEST)
+$(OBJ): $(HDR)
+$(LOBJ): $(HDR)
+$(TOBJ): $(HDR)
+$(TEST): libj2.a
+
+.c.o:
+ $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS)
+
+.c.to:
+ $(CC) -c -o $@ $< -DTEST $(CFLAGS) $(CPPFLAGS)
+
+.to.t:
+ $(CC) -o $@ $< libj2.a $(LDFLAGS)
+
+.c.t:
+ $(CC) -o $@ $< libj2.a -DTEST $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)
+
+.c.lo:
+ $(CC) -fPIC -c -o $@ $< $(CFLAGS) $(CPPFLAGS)
+
+libj2.a: $(OBJ)
+ @rm -f -- $@
+ $(AR) rc $@ $(OBJ)
+ $(AR) ts $@ > /dev/null
+
+libj2.$(LIBEXT): $(LOBJ)
+ $(CC) $(LIBFLAGS) -o $@ $(LOBJ) $(LDFLAGS)
+
+check: $(TEST)
+ @set -e;\
+ for t in $(TEST); do\
+ printf '%s ' $(CHECK_PREFIX) "./$$t"; printf '\n';\
+ $(CHECK_PREFIX) ./"$$t";\
+ done
+
+install: libj2.a libj2.$(LIBEXT)
+ mkdir -p -- "$(DESTDIR)$(PREFIX)/lib"
+ mkdir -p -- "$(DESTDIR)$(PREFIX)/include/libj2"
+ mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man7"
+ cp -- libj2.a "$(DESTDIR)$(PREFIX)/lib/"
+ cp -- libj2.$(LIBEXT) "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBMINOREXT)"
+ $(FIX_INSTALL_NAME) "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBMINOREXT)"
+ ln -sf -- libj2.$(LIBMINOREXT) "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBMAJOREXT)"
+ ln -sf -- libj2.$(LIBMAJOREXT) "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBEXT)"
+ cp -- libj2.h "$(DESTDIR)$(PREFIX)/include/"
+ cp -- $(SUBHDR) "$(DESTDIR)$(PREFIX)/include/libj2/"
+ cp -- $(MAN7) "$(DESTDIR)$(MANPREFIX)/man7/"
+
+uninstall:
+ -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libj2.a"
+ -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBMAJOREXT)"
+ -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBMINOREXT)"
+ -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBEXT)"
+ -rm -f -- "$(DESTDIR)$(PREFIX)/include/libj2.h"
+ -cd -- "$(DESTDIR)$(PREFIX)/include/" && rm -f -- $(SUBHDR)
+ -rmdir -- "$(DESTDIR)$(PREFIX)/include/libj2"
+ -cd -- "$(DESTDIR)$(MANPREFIX)/man7/" && rm -f -- $(MAN7)
+
+clean:
+ -rm -f -- *.o *.a *.lo *.su *.so *.so.* *.dll *.dylib
+ -rm -f -- *.gch *.gcov *.gcno *.gcda *.$(LIBEXT)
+ -rm -f -- *.to *.t
+
+.SUFFIXES:
+.SUFFIXES: .lo .o .c .to .t
+
+.PHONY: all install uninstall clean
diff --git a/README b/README
new file mode 100644
index 0000000..3ccbf85
--- /dev/null
+++ b/README
@@ -0,0 +1,15 @@
+NAME
+ libj2 - Double-max precision integers
+
+SYNOPSIS
+ #include <libj2.h>
+
+ Link with -lj2.
+
+DESCRIPTION
+ libj2 provides integer data types with double the width of
+ uintmax_t, along with functions for preforming standard
+ integer operations, with optional overflow-detection.
+
+SEE ALSO
+ libzahl(7)
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..876d2ef
--- /dev/null
+++ b/common.h
@@ -0,0 +1,29 @@
+/* See LICENSE file for copyright and license details. */
+#include "libj2.h"
+
+#if defined(__GNUC__)
+# define CONST __attribute__((__const__))
+# define PURE __attribute__((__pure__))
+#else
+# define CONST
+# define PURE
+#endif
+
+#if defined(__clang__)
+# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* broken warning, spams false positives */
+# pragma clang diagnostic ignored "-Wimplicit-void-ptr-cast" /* C++-incompatiblity warning, bad idea, specially in non-header files */
+#endif
+
+#ifdef TEST
+# include <stdlib.h>
+# include <stdio.h>
+# include <string.h>
+# include <time.h>
+# define EXPECT(EXPR)\
+ do {\
+ if (EXPR)\
+ break;\
+ fprintf(stderr, "Assertion failed at %s:%i: %s\n", __FILE__, __LINE__, #EXPR);\
+ exit(1);\
+ } while (0)
+#endif
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..f4adf12
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,8 @@
+PREFIX = /usr
+MANPREFIX = $(PREFIX)/share/man
+
+CC = c99
+
+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE
+CFLAGS =
+LDFLAGS =
diff --git a/libj2.7 b/libj2.7
new file mode 100644
index 0000000..2346eba
--- /dev/null
+++ b/libj2.7
@@ -0,0 +1,20 @@
+.TH LIBJ2 7 LIBJ2
+.SH NAME
+libj2 \- Double-max precision integers
+
+.SH SYNOPSIS
+.nf #include <libj2.h>
+.fi
+.PP
+Link with
+.IR -lj2 .
+
+.SH DESCRIPTION
+.B libj2
+provides integer data types with double the width of
+.BR uintmax_t ,
+along with functions for preforming standard
+integer operations, with optional overflow-detection.
+
+.SH SEE ALSO
+.BR libzahl (7)
diff --git a/libj2.h b/libj2.h
new file mode 100644
index 0000000..0c3d882
--- /dev/null
+++ b/libj2.h
@@ -0,0 +1,62 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBJ2_H
+#define LIBJ2_H
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#if 1
+# if defined(__GNUC__)
+# define LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_
+# endif
+#endif
+
+
+/**
+ * The number of bits in an `uintmax_t`
+ */
+#define LIBJ2_JU_BIT ((unsigned)CHAR_BIT * (unsigned)sizeof(uintmax_t))
+
+/**
+ * The number of bits in an `struct libj2_j2u`
+ */
+#define LIBJ2_J2U_BIT (2U * LIBJ2_JU_BIT)
+
+
+/**
+ * Unsigned double-maximum precision integer
+ *
+ * If `uintmax_t` is a 64-bit type, this `struct` is a 128-bit type
+ */
+struct libj2_j2u {
+ /**
+ * Most significant half
+ */
+ uintmax_t high;
+
+ /**
+ * Least significant half
+ */
+ uintmax_t low;
+};
+
+
+#include "libj2/constants.h"
+#include "libj2/signum.h"
+#include "libj2/constructors.h"
+#include "libj2/unsigned-comparsion.h"
+#include "libj2/bitwise-logic.h"
+#include "libj2/bit-shifting.h"
+#include "libj2/sign-shifting.h"
+#include "libj2/addition.h"
+#include "libj2/subtraction.h"
+#include "libj2/multiplication.h"
+#include "libj2/division.h"
+
+
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+# undef LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_
+#endif
+
+#endif
diff --git a/libj2/addition.h b/libj2/addition.h
new file mode 100644
index 0000000..d900622
--- /dev/null
+++ b/libj2/addition.h
@@ -0,0 +1,313 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBJ2_H
+# error Do not include this header directly, include <libj2.h> instead
+#endif
+
+
+/**
+ * Calculate the sum of an unsigned double-max precision
+ * integer and an unsigned max precision integer
+ *
+ * `libj2_j2u_add_ju(a, b)` implements `*a += b`
+ *
+ * @param a The augend, and output parameter for the sum
+ * @param b The addend
+ */
+inline void
+libj2_j2u_add_ju(struct libj2_j2u *a, uintmax_t b)
+{
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_add_overflow(a->low, b, &a->low))
+ a->high += 1U;
+#else
+ if (a->low > UINTMAX_MAX - b)
+ a->high += 1U;
+ a->low += b;
+#endif
+}
+
+
+/**
+ * Calculate the sum of an unsigned double-max precision
+ * integer and an unsigned max precision integer
+ *
+ * `libj2_j2u_add_ju_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 overflow (the highest set bit in the sum
+ * cannot be stored in the result), 0 otherwise
+ */
+inline int
+libj2_j2u_add_ju_overflow(struct libj2_j2u *a, uintmax_t b)
+{
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_add_overflow(a->low, b, &a->low))
+ return __builtin_add_overflow(a->high, 1U, &a->high);
+ return 0;
+#else
+ int overflow = 0;
+ if (a->low > UINTMAX_MAX - b) {
+ if (a->high == UINTMAX_MAX)
+ overflow = 1;
+ a->high += 1U;
+ }
+ a->low += b;
+ return overflow;
+#endif
+}
+
+
+/**
+ * Calculate the sum of an unsigned double-max precision
+ * integer and an unsigned max precision integer
+ *
+ * `libj2_j2u_add_ju_to_j2u(a, b, res)` implements
+ * `*res = *a + b`
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ */
+inline void
+libj2_j2u_add_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ res->high = a->high;
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_add_overflow(a->low, b, &res->low))
+ res->high += 1U;
+#else
+ if (a->low > UINTMAX_MAX - b)
+ res->high += 1U;
+ res->low = a->low + b;
+#endif
+}
+
+
+/**
+ * Calculate the sum of an unsigned max precision
+ * integer and an unsigned double-max precision integer
+ *
+ * `libj2_ju_add_j2u_to_j2u(a, b, res)` implements
+ * `*res = a + *b`
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ */
+inline void
+libj2_ju_add_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_add_ju_to_j2u(b, a, res);
+}
+
+
+/**
+ * Calculate the sum of an unsigned double-max precision
+ * integer and an unsigned max precision integer
+ *
+ * `libj2_j2u_add_ju_to_j2u_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 overflow (the highest set bit in the sum
+ * cannot be stored in the result), 0 otherwise
+ */
+inline int
+libj2_j2u_add_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_add_overflow(a->low, b, &res->low))
+ return __builtin_add_overflow(a->high, 1U, &res->high);
+ res->high = a->high;
+ return 0;
+#else
+ int overflow = 0;
+ res->high = a->high;
+ if (a->low > UINTMAX_MAX - b) {
+ if (a->high == UINTMAX_MAX)
+ overflow = 1;
+ res->high += 1U;
+ }
+ res->low = a->low + b;
+ return overflow;
+#endif
+}
+
+
+/**
+ * Calculate the sum of an unsigned max precision
+ * integer and an unsigned double-max precision integer
+ *
+ * `libj2_ju_add_j2u_to_j2u_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 overflow (the highest set bit in the sum
+ * cannot be stored in the result), 0 otherwise
+ */
+inline int
+libj2_ju_add_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ return libj2_j2u_add_ju_to_j2u_overflow(b, a, res);
+}
+
+
+/**
+ * Calculate the sum, as an unsigned double-max precision
+ * integer, of two unsigned double-max precision integers
+ *
+ * `libj2_ju_add_ju_to_j2u(a, b, res)` implements
+ * `*res = a + b`, where `a` and `b` are converted to
+ * `struct libj2_j2u`'s
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ */
+inline void
+libj2_ju_add_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *res)
+{
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ res->high = __builtin_add_overflow(a, b, &res->low) ? 1U : 0U;
+#else
+ res->high = (a > UINTMAX_MAX - b);
+ res->low = a + b;
+#endif
+}
+
+
+/**
+ * Calculate the sum of two unsigned double-max precision
+ * integers
+ *
+ * `libj2_j2u_add_j2u(a, b)` implements `*a += *b`
+ *
+ * @param a The augend, and output parameter for the sum
+ * @param b The addend
+ */
+inline void
+libj2_j2u_add_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ if (a == b) {
+ a->high <<= 1;
+ a->high |= a->low >> (LIBJ2_JU_BIT - 1U);
+ a->low <<= 1;
+ } else {
+ libj2_j2u_add_ju(a, b->low);
+ a->high += b->high;
+ }
+}
+
+
+/**
+ * Calculate the sum of two unsigned double-max precision
+ * integers
+ *
+ * `libj2_j2u_add_j2u_to_j2u(a, b, res)` implements `*res = *a + *b`
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ */
+inline void
+libj2_j2u_add_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ if (a == b) {
+ res->high = a->high << 1;
+ res->high |= a->low >> (LIBJ2_JU_BIT - 1U);
+ res->low = a->low << 1;
+ } else if (b == res) {
+ libj2_j2u_add_ju_to_j2u(b, a->low, res);
+ res->high += a->high;
+ } else {
+ libj2_j2u_add_ju_to_j2u(a, b->low, res);
+ res->high += b->high;
+ }
+}
+
+
+/**
+ * Calculate the sum of two unsigned double-max precision
+ * integers
+ *
+ * `libj2_j2u_add_j2u_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 overflow (the highest set bit in the sum
+ * cannot be stored in the result), 0 otherwise
+ */
+inline int
+libj2_j2u_add_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ if (a == b) {
+ int overflow = (int)(a->high >> (LIBJ2_JU_BIT - 1U));
+ a->high <<= 1;
+ a->high |= a->low >> (LIBJ2_JU_BIT - 1U);
+ a->low <<= 1;
+ return overflow;
+ } else {
+ int overflow = libj2_j2u_add_ju_overflow(a, b->low);
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ return __builtin_add_overflow(a->high, b->high, &a->high) || overflow;
+#else
+ if (a->high > UINTMAX_MAX - b->high)
+ overflow = 1;
+ a->high += b->high;
+ return overflow;
+#endif
+ }
+}
+
+
+/**
+ * Calculate the sum of two unsigned double-max precision
+ * integers
+ *
+ * `libj2_j2u_add_j2u_to_j2u_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 overflow (the highest set bit in the sum
+ * cannot be stored in the result), 0 otherwise
+ */
+inline int
+libj2_j2u_add_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ if (a == b) {
+ int overflow = (int)(a->high >> (LIBJ2_JU_BIT - 1U));
+ res->high = a->high << 1;
+ res->high |= a->low >> (LIBJ2_JU_BIT - 1U);
+ res->low = a->low << 1;
+ return overflow;
+ } else if (b == res) {
+ int overflow = libj2_j2u_add_ju_to_j2u_overflow(b, a->low, res);
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ return __builtin_add_overflow(res->high, a->high, &res->high) || overflow;
+#else
+ if (res->high > UINTMAX_MAX - a->high)
+ overflow = 1;
+ res->high += a->high;
+ return overflow;
+#endif
+ } else {
+ int overflow = libj2_j2u_add_ju_to_j2u_overflow(a, b->low, res);
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ return __builtin_add_overflow(res->high, b->high, &res->high) || overflow;
+#else
+ if (res->high > UINTMAX_MAX - b->high)
+ overflow = 1;
+ res->high += b->high;
+ return overflow;
+#endif
+ }
+}
diff --git a/libj2/bit-shifting.h b/libj2/bit-shifting.h
new file mode 100644
index 0000000..a0c36d1
--- /dev/null
+++ b/libj2/bit-shifting.h
@@ -0,0 +1,573 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBJ2_H
+# error Do not include this header directly, include <libj2.h> instead
+#endif
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer to more signficant positions (left-shift)
+ *
+ * Bits shifted out of precision will be discarded,
+ * and positions without any new bit will be assigned
+ * the bit value 0
+ *
+ * `libj2_j2u_lsh(a, b)` implements `*a <<= b`
+ *
+ * This is equivalent to multiplying `a` by the `b`th
+ * power of 2
+ *
+ * @param a The integer to shift, also used as the
+ * output parameter for the result
+ * @param b The number of positions to shift each bit
+ */
+inline void
+libj2_j2u_lsh(struct libj2_j2u *a, unsigned b)
+{
+ if (b >= LIBJ2_JU_BIT) {
+ if (b >= LIBJ2_J2U_BIT)
+ a->high = 0;
+ else
+ a->high = a->low << (b - LIBJ2_JU_BIT);
+ a->low = 0U;
+ } else if (b) {
+ a->high <<= b;
+ a->high |= a->low >> (LIBJ2_JU_BIT - b);
+ a->low <<= b;
+ }
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer to more signficant positions (left-shift)
+ *
+ * Bits shifted out of precision will be discarded,
+ * and positions without any new bit will be assigned
+ * the bit value 0
+ *
+ * `libj2_j2u_lsh_to_j2u(a, b, res)` implements `*res = *a << b`
+ *
+ * This is equivalent to multiplying `a` by the `b`th
+ * power of 2
+ *
+ * @param a The integer to shift
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_lsh_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res)
+{
+ *res = *a;
+ libj2_j2u_lsh(res, b);
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer, represented by an unsigned max precision
+ * integer and whose high part is treated as having
+ * the value 0, to more signficant positions (left-shift)
+ *
+ * Bits shifted out of precision will be discarded,
+ * and positions without any new bit will be assigned
+ * the bit value 0
+ *
+ * `libj2_ju_lsh_to_j2u(a, b, res)` implements `*res = a << b`,
+ * where `a` is converted to a `struct libj2_j2u`
+ *
+ * This is equivalent to multiplying `a` by the `b`th
+ * power of 2
+ *
+ * You can rely on `libj2_ju_lsh_to_j2u(1, LIBJ2_J2U_BIT, res)`
+ * overflowing and assigning 0 to `*res`, and thus, subtracting
+ * 1 from `*res` afterwards will set all bits; and so,
+ * `libj2_ju_lsh_to_j2u(1, n, a), libj2_j2u_sub_j2(a, 1)` will
+ * always set the `n` least significant bits in `a` and clear
+ * all other bits
+ *
+ * @param a The integer to shift
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_lsh_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res)
+{
+ libj2_ju_to_j2u(a, res);
+ libj2_j2u_lsh(res, b);
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer to more signficant positions (left-shift)
+ *
+ * Bits shifted out of precision will be discarded,
+ * and positions without any new bit will be assigned
+ * the bit value 0
+ *
+ * `libj2_j2u_lsh_overflow(a, b)` implements
+ * `(*a << b) >> b == *a ? (*a <<= b, 0) : (*a <<= b, 1)`
+ *
+ * This is equivalent to multiplying `a` by the `b`th
+ * power of 2
+ *
+ * @param a The integer to shift, also used as the
+ * output parameter for the result
+ * @param b The number of positions to shift each bit
+ * @return 1 if any set bit was discarded because
+ * it was shifted out, 0 otherwise
+ */
+inline int
+libj2_j2u_lsh_overflow(struct libj2_j2u *a, unsigned b)
+{
+ if (b >= LIBJ2_J2U_BIT) {
+ int overflow = a->high || a->low;
+ a->high = 0;
+ a->low = 0;
+ return overflow;
+ } else if (b > LIBJ2_JU_BIT) {
+ int overflow = a->high || a->low >> (LIBJ2_J2U_BIT - b);
+ a->high = a->low << (b - LIBJ2_JU_BIT);
+ a->low = 0U;
+ return overflow;
+ } else if (b == LIBJ2_JU_BIT) {
+ int overflow = !!a->high;
+ a->high = a->low;
+ a->low = 0U;
+ return overflow;
+ } else if (b) {
+ int overflow = !!(a->high >> (LIBJ2_JU_BIT - b));
+ a->high <<= b;
+ a->high |= a->low >> (LIBJ2_JU_BIT - b);
+ a->low <<= b;
+ return overflow;
+ } else {
+ return 0;
+ }
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer to more signficant positions (left-shift)
+ *
+ * Bits shifted out of precision will be discarded,
+ * and positions without any new bit will be assigned
+ * the bit value 0
+ *
+ * `libj2_j2u_lsh_to_j2u_overflow(a, b, res)` implements
+ * `*res = *a << b, a != *res >> b`
+ *
+ * This is equivalent to multiplying `a` by the `b`th
+ * power of 2
+ *
+ * @param a The integer to shift
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ * @return 1 if any set bit was discarded because
+ * it was shifted out, 0 otherwise
+ */
+inline int
+libj2_j2u_lsh_to_j2u_overflow(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res)
+{
+ *res = *a;
+ return libj2_j2u_lsh_overflow(res, b);
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer, represented by an unsigned max precision
+ * integer and whose high part is treated as having
+ * the value 0, to more signficant positions (left-shift)
+ *
+ * Bits shifted out of precision will be discarded,
+ * and positions without any new bit will be assigned
+ * the bit value 0
+ *
+ * `libj2_ju_lsh_to_j2u_overflow(a, b, res)` implements
+ * `*res = a << b, a != *res >> b`, where `a` is converted
+ * to a `struct libj2_j2u`
+ *
+ * This is equivalent to multiplying `a` by the `b`th
+ * power of 2
+ *
+ * @param a The integer to shift
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ * @return 1 if any set bit was discarded because
+ * it was shifted out, 0 otherwise
+ */
+inline int
+libj2_ju_lsh_to_j2u_overflow(uintmax_t a, unsigned b, struct libj2_j2u *res)
+{
+ libj2_ju_to_j2u(a, res);
+ return libj2_j2u_lsh_overflow(res, b);
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer to less signficant positions (right-shift)
+ *
+ * Bits shifted out of precision will be discarded,
+ * and positions without any new bit will be assigned
+ * the bit value 0
+ *
+ * `libj2_j2u_rsh(a, b)` implements `*a >>= b`
+ *
+ * This is equivalent to dividing `a` by the `b`th
+ * power of 2
+ *
+ * @param a The integer to shift, also used as the
+ * output parameter for the result
+ * @param b The number of positions to shift each bit
+ */
+inline void
+libj2_j2u_rsh(struct libj2_j2u *a, unsigned b)
+{
+ if (b >= LIBJ2_JU_BIT) {
+ if (b >= LIBJ2_J2U_BIT)
+ a->low = 0;
+ else
+ a->low = a->high >> (b - LIBJ2_JU_BIT);
+ a->high = 0U;
+ } else if (b) {
+ a->low >>= b;
+ a->low |= a->high << (LIBJ2_JU_BIT - b);
+ a->high >>= b;
+ }
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer to less signficant positions (right-shift)
+ *
+ * Bits shifted out of precision will be discarded,
+ * and positions without any new bit will be assigned
+ * the bit value 0
+ *
+ * `libj2_j2u_rsh_to_j2u(a, b, res)` implements `*res = *a >> b`
+ *
+ * This is equivalent to dividing `a` by the `b`th
+ * power of 2
+ *
+ * @param a The integer to shift
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_rsh_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res)
+{
+ *res = *a;
+ libj2_j2u_rsh(res, b);
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer, represented by an unsigned max precision
+ * integer and whose high part is treated as having
+ * the value 0, to less signficant positions (right-shift)
+ *
+ * Bits shifted out of precision will be discarded,
+ * and positions without any new bit will be assigned
+ * the bit value 0
+ *
+ * `libj2_ju_rsh_to_j2u(a, b, res)` implements `*res = a >> b`,
+ * where `a` is converted to a `struct libj2_j2u`
+ *
+ * This is equivalent to dividing `a` by the `b`th
+ * power of 2
+ *
+ * @param a The integer to shift
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_rsh_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res)
+{
+ libj2_ju_to_j2u(a, res);
+ libj2_j2u_rsh(res, b);
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer to less signficant positions (right-shift)
+ *
+ * Bits shifted out of precision will be discarded,
+ * and positions without any new bit will be assigned
+ * the bit value 0
+ *
+ * `libj2_j2u_rsh_underflow(a, b)` implements
+ * `(*a >> b) << b == *a ? (*a >>= b, 0) : (*a >>= b, 1)`
+ *
+ * This is equivalent to dividing `a` by the `b`th
+ * power of 2
+ *
+ * @param a The integer to shift, also used as the
+ * output parameter for the result
+ * @param b The number of positions to shift each bit
+ * @return 1 if any set bit was discarded because
+ * it was shifted out, 0 otherwise
+ */
+inline int
+libj2_j2u_rsh_underflow(struct libj2_j2u *a, unsigned b)
+{
+ if (b >= LIBJ2_J2U_BIT) {
+ int underflow = a->high || a->low;
+ a->high = 0;
+ a->low = 0;
+ return underflow;
+ } else if (b > LIBJ2_JU_BIT) {
+ int underflow = a->low || a->high >> (LIBJ2_J2U_BIT - b);
+ a->low = a->high >> (b - LIBJ2_JU_BIT);
+ a->high = 0U;
+ return underflow;
+ } else if (b == LIBJ2_JU_BIT) {
+ int underflow = !!a->low;
+ a->low = a->high;
+ a->high = 0U;
+ return underflow;
+ } else if (b) {
+ int underflow = !!(a->low << (LIBJ2_JU_BIT - b));
+ a->low >>= b;
+ a->low |= a->high << (LIBJ2_JU_BIT - b);
+ a->high >>= b;
+ return underflow;
+ } else {
+ return 0;
+ }
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer to less signficant positions (right-shift)
+ *
+ * Bits shifted out of precision will be discarded,
+ * and positions without any new bit will be assigned
+ * the bit value 0
+ *
+ * `libj2_j2u_rsh_to_j2u_underflow(a, b, res)` implements
+ * `*res = *a >> b, a != *res << b`
+ *
+ * This is equivalent to dividing `a` by the `b`th
+ * power of 2
+ *
+ * @param a The integer to shift
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ * @return 1 if any set bit was discarded because
+ * it was shifted out, 0 otherwise
+ */
+inline int
+libj2_j2u_rsh_to_j2u_underflow(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res)
+{
+ *res = *a;
+ return libj2_j2u_rsh_underflow(res, b);
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer, represented by an unsigned max precision
+ * integer and whose high part is treated as having
+ * the value 0, to less signficant positions (right-shift)
+ *
+ * Bits shifted out of precision will be discarded,
+ * and positions without any new bit will be assigned
+ * the bit value 0
+ *
+ * `libj2_ju_rsh_to_j2u_underflow(a, b, res)` implements
+ * `*res = a >> b, a != *res << b`, where `a` is converted
+ * to a `struct libj2_j2u`
+ *
+ * This is equivalent to dividing `a` by the `b`th
+ * power of 2
+ *
+ * @param a The integer to shift
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ * @return 1 if any set bit was discarded because
+ * it was shifted out, 0 otherwise
+ */
+inline int
+libj2_ju_rsh_to_j2u_underflow(uintmax_t a, unsigned b, struct libj2_j2u *res)
+{
+ libj2_ju_to_j2u(a, res);
+ return libj2_j2u_rsh_underflow(res, b);
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer to more signficant positions
+ *
+ * Bits shifted out of precision are wrapped around
+ * to the other edge of the bit array
+ *
+ * `libj2_j2u_lrot(a, b)` implements
+ * `*a = (*a << b) | (*a >> (n - b))`, where
+ * `n` is the number of bits in `*a`
+ *
+ * @param a The integer to rotate, also used as the
+ * output parameter for the result
+ * @param b The number of positions to shift each bit
+ */
+inline void
+libj2_j2u_lrot(struct libj2_j2u *a, unsigned b)
+{
+ uintmax_t c;
+ b %= LIBJ2_J2U_BIT;
+ if (b >= LIBJ2_JU_BIT) {
+ b -= LIBJ2_JU_BIT;
+ c = a->high;
+ a->high = a->low;
+ a->low = c;
+ }
+ if (b) {
+ c = a->high;
+ a->high <<= b;
+ a->high |= a->low >> (LIBJ2_JU_BIT - b);
+ a->low <<= b;
+ a->low |= c >> (LIBJ2_JU_BIT - b);
+ }
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer to more signficant positions
+ *
+ * Bits shifted out of precision are wrapped around
+ * to the other edge of the bit array
+ *
+ * `libj2_j2u_lrot_to_j2u(a, b, res)` implements
+ * `*res = (*a << b) | (*a >> (n - b))`, where
+ * `n` is the number of bits in `*a`
+ *
+ * @param a The integer to rotate
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_lrot_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res)
+{
+ *res = *a;
+ libj2_j2u_lrot(res, b);
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer, represented by an unsigned max precision
+ * integer and whose high part is treated as having
+ * the value 0, to more signficant positions
+ *
+ * Bits shifted out of precision are wrapped around
+ * to the other edge of the bit array
+ *
+ * `libj2_ju_lrot_to_j2u(a, b, res)` implements
+ * `*res = (a << b) | (a >> (n - b))`, where
+ * `n` is the number of bits in `a`, and where
+ * `a` is converted to a `struct libj2_j2u`
+ *
+ * @param a The integer to rotate
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_lrot_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res)
+{
+ libj2_ju_to_j2u(a, res);
+ libj2_j2u_lrot(res, b);
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer to less signficant positions
+ *
+ * Bits shifted out of precision are wrapped around
+ * to the other edge of the bit array
+ *
+ * `libj2_j2u_rrot(a, b)` implements
+ * `*a = (*a >> b) | (*a << (n - b))`, where
+ * `n` is the number of bits in `*a`
+ *
+ * @param a The integer to rotate, also used as the
+ * output parameter for the result
+ * @param b The number of positions to shift each bit
+ */
+inline void
+libj2_j2u_rrot(struct libj2_j2u *a, unsigned b)
+{
+ uintmax_t c;
+ b %= LIBJ2_J2U_BIT;
+ if (b >= LIBJ2_JU_BIT) {
+ b -= LIBJ2_JU_BIT;
+ c = a->high;
+ a->high = a->low;
+ a->low = c;
+ }
+ if (b) {
+ c = a->high;
+ a->high >>= b;
+ a->high |= a->low << (LIBJ2_JU_BIT - b);
+ a->low >>= b;
+ a->low |= c << (LIBJ2_JU_BIT - b);
+ }
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer to less signficant positions
+ *
+ * Bits shifted out of precision are wrapped around
+ * to the other edge of the bit array
+ *
+ * `libj2_j2u_rrot_to_j2u(a, b, res)` implements
+ * `*res = (*a >> b) | (*a << (n - b))`, where
+ * `n` is the number of bits in `*a`
+ *
+ * @param a The integer to rotate
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_rrot_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res)
+{
+ *res = *a;
+ libj2_j2u_rrot(res, b);
+}
+
+
+/**
+ * Shift the bits an unsigned double-max precision
+ * integer, represented by an unsigned max precision
+ * integer and whose high part is treated as having
+ * the value 0, to less signficant positions
+ *
+ * Bits shifted out of precision are wrapped around
+ * to the other edge of the bit array
+ *
+ * `libj2_ju_rrot_to_j2u(a, b, res)` implements
+ * `*res = (a >> b) | (a << (n - b))`, where
+ * `n` is the number of bits in `a`, and where
+ * `a` is converted to a `struct libj2_j2u`
+ *
+ * @param a The integer to rotate
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_rrot_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res)
+{
+ libj2_ju_to_j2u(a, res);
+ libj2_j2u_rrot(res, b);
+}
diff --git a/libj2/bitwise-logic.h b/libj2/bitwise-logic.h
new file mode 100644
index 0000000..6ec362e
--- /dev/null
+++ b/libj2/bitwise-logic.h
@@ -0,0 +1,980 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBJ2_H
+# error Do not include this header directly, include <libj2.h> instead
+#endif
+
+
+/**
+ * Test whether a specific bit in an unsigned
+ * double-max precision integer is set
+ *
+ * @param a The integer to inspect
+ * @param b The index of the bit to test,
+ * 0 for the least significant bit
+ * @return 1 if the bit is set, 0 otherwise
+ */
+inline int
+libj2_j2u_test_bit(const struct libj2_j2u *a, unsigned b)
+{
+ if (b >= LIBJ2_J2U_BIT)
+ return 0;
+ else if (b >= LIBJ2_JU_BIT)
+ return (int)((a->high >> (b - LIBJ2_JU_BIT)) & 1U);
+ else
+ return (int)((a->low >> b) & 1U);
+}
+
+
+/**
+ * Test whether two unsigned double-max precision
+ * integers have commonly set bits
+ *
+ * @param a One of the integers
+ * @param b The other integer
+ * @return 1 if the two integers have set bits
+ * in common, 0 otherwise
+ */
+inline int
+libj2_j2u_test_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ return (a->high & b->high) || (a->low & b->low);
+}
+
+
+/**
+ * Test whether an unsigned double-max precision
+ * integer have commonly set bits with an unsigned
+ * max precision integer
+ *
+ * @param a The double-max precision integer
+ * @param b The max precision integer
+ * @return 1 if the two integers have set bits
+ * in common, 0 otherwise
+ */
+inline int
+libj2_j2u_test_ju(const struct libj2_j2u *a, uintmax_t b)
+{
+ return !!(a->low & b);
+}
+
+
+/**
+ * Test whether the high part of an unsigned double-max
+ * precision integer have commonly set bits with an unsigned
+ * max precision integer
+ *
+ * @param a The double-max precision integer
+ * @param b The max precision integer
+ * @return 1 if high part of `a` have set bits
+ * in common with `b`, 0 otherwise
+ */
+inline int
+libj2_j2u_test_high_ju(const struct libj2_j2u *a, uintmax_t b)
+{
+ return !!(a->high & b);
+}
+
+
+/**
+ * Calculate the bitwise NOT of an unsigned
+ * double-max precision integer
+ *
+ * @param a The integer, also used as output
+ * parameter for the result
+ */
+inline void
+libj2_not_j2u(struct libj2_j2u *a)
+{
+ a->high = ~a->high;
+ a->low = ~a->low;
+}
+
+
+/**
+ * Calculate the bitwise NOT of an unsigned
+ * double-max precision integer
+ *
+ * @param a The integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_not_j2u_to_j2u(const struct libj2_j2u *a, struct libj2_j2u *res)
+{
+ res->high = ~a->high;
+ res->low = ~a->low;
+}
+
+
+/**
+ * Calculate the bitwise NOT of an unsigned double-max
+ * precision integer represented by an unsigned max
+ * precision integer (the high part is of the unsigned
+ * double-max precision integer is treated as 0)
+ *
+ * @param a The integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_not_ju_to_j2u(uintmax_t a, struct libj2_j2u *res)
+{
+ res->high = UINTMAX_MAX;
+ res->low = ~a;
+}
+
+
+/**
+ * Calculate the bitwise AND of two unsigned double-max
+ * precision integers
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_and_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ a->high &= b->high;
+ a->low &= b->low;
+}
+
+
+/**
+ * Calculate the bitwise AND of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_and_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ a->high = 0;
+ a->low &= b;
+}
+
+
+/**
+ * Calculate the bitwise AND of two unsigned double-max
+ * precision integers
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_and_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ res->high = a->high & b->high;
+ res->low = a->low & b->low;
+}
+
+
+/**
+ * Calculate the bitwise AND of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_and_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ res->high = 0;
+ res->low = a->low & b;
+}
+
+
+/**
+ * Calculate the bitwise AND of an unsigned max
+ * precision integer (left-hand) and an unsigned
+ * double-max precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_and_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_and_ju_to_j2u(b, a, res);
+}
+
+
+/**
+ * Calculate the bitwise OR of two unsigned double-max
+ * precision integers
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_or_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ a->high |= b->high;
+ a->low |= b->low;
+}
+
+
+/**
+ * Calculate the bitwise OR of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_or_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ a->low |= b;
+}
+
+
+/**
+ * Calculate the bitwise OR of two unsigned double-max
+ * precision integers
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_or_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ res->high = a->high | b->high;
+ res->low = a->low | b->low;
+}
+
+
+/**
+ * Calculate the bitwise OR of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_or_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ res->high = a->high;
+ res->low = a->low | b;
+}
+
+
+/**
+ * Calculate the bitwise OR of an unsigned max
+ * precision integer (left-hand) and an unsigned
+ * double-max precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_or_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_or_ju_to_j2u(b, a, res);
+}
+
+
+/**
+ * Calculate the bitwise XOR of two unsigned double-max
+ * precision integers
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_xor_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ a->high ^= b->high;
+ a->low ^= b->low;
+}
+
+
+/**
+ * Calculate the bitwise XOR of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_xor_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ a->low ^= b;
+}
+
+
+/**
+ * Calculate the bitwise XOR of two unsigned double-max
+ * precision integers
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_xor_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ res->high = a->high ^ b->high;
+ res->low = a->low ^ b->low;
+}
+
+
+/**
+ * Calculate the bitwise XOR of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_xor_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ res->high = a->high;
+ res->low = a->low ^ b;
+}
+
+
+/**
+ * Calculate the bitwise XOR of an unsigned max
+ * precision integer (left-hand) and an unsigned
+ * double-max precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_xor_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_xor_ju_to_j2u(b, a, res);
+}
+
+
+/**
+ * Calculate the bitwise NAND of two unsigned double-max
+ * precision integers
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_nand_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ libj2_j2u_and_j2u(a, b);
+ libj2_not_j2u(a);
+}
+
+
+/**
+ * Calculate the bitwise NAND of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_nand_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ libj2_j2u_and_ju(a, b);
+ libj2_not_j2u(a);
+}
+
+
+/**
+ * Calculate the bitwise NAND of two unsigned double-max
+ * precision integers
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_nand_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_and_j2u_to_j2u(a, b, res);
+ libj2_not_j2u(res);
+}
+
+
+/**
+ * Calculate the bitwise NAND of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_nand_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ libj2_j2u_and_ju_to_j2u(a, b, res);
+ libj2_not_j2u(res);
+}
+
+
+/**
+ * Calculate the bitwise NAND of an unsigned max
+ * precision integer (left-hand) and an unsigned
+ * double-max precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_nand_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_nand_ju_to_j2u(b, a, res);
+}
+
+
+/**
+ * Calculate the bitwise NOR of two unsigned double-max
+ * precision integers
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_nor_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ libj2_j2u_or_j2u(a, b);
+ libj2_not_j2u(a);
+}
+
+
+/**
+ * Calculate the bitwise NOR of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_nor_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ libj2_j2u_or_ju(a, b);
+ libj2_not_j2u(a);
+}
+
+
+/**
+ * Calculate the bitwise NOR of two unsigned double-max
+ * precision integers
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_nor_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_or_j2u_to_j2u(a, b, res);
+ libj2_not_j2u(res);
+}
+
+
+/**
+ * Calculate the bitwise NOR of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_nor_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ libj2_j2u_or_ju_to_j2u(a, b, res);
+ libj2_not_j2u(res);
+}
+
+
+/**
+ * Calculate the bitwise NOR of an unsigned max
+ * precision integer (left-hand) and an unsigned
+ * double-max precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_nor_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_nor_ju_to_j2u(b, a, res);
+}
+
+
+/**
+ * Calculate the bitwise XNOR of two unsigned double-max
+ * precision integers
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_xnor_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ libj2_j2u_xor_j2u(a, b);
+ libj2_not_j2u(a);
+}
+
+
+/**
+ * Calculate the bitwise XNOR of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_xnor_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ libj2_j2u_xor_ju(a, b);
+ libj2_not_j2u(a);
+}
+
+
+/**
+ * Calculate the bitwise XNOR of two unsigned double-max
+ * precision integers
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_xnor_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_xor_j2u_to_j2u(a, b, res);
+ libj2_not_j2u(res);
+}
+
+
+/**
+ * Calculate the bitwise XNOR of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_xnor_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ libj2_j2u_xor_ju_to_j2u(a, b, res);
+ libj2_not_j2u(res);
+}
+
+
+/**
+ * Calculate the bitwise XNOR of an unsigned max
+ * precision integer (left-hand) and an unsigned
+ * double-max precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_xnor_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_xnor_ju_to_j2u(b, a, res);
+}
+
+
+/**
+ * Calculate the bitwise IMPLY of two unsigned double-max
+ * precision integers
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_imply_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ if (a == b) {
+ libj2_j2u_max(a);
+ } else {
+ libj2_not_j2u(a);
+ libj2_j2u_or_j2u(a, b);
+ }
+}
+
+
+/**
+ * Calculate the bitwise IMPLY of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_imply_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ libj2_not_j2u(a);
+ libj2_j2u_or_ju(a, b);
+}
+
+
+/**
+ * Calculate the bitwise IMPLY of two unsigned
+ * double-max precision integers
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_imply_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ if (a == b) {
+ res->high = UINTMAX_MAX;
+ res->low = UINTMAX_MAX;
+ } else if (res == b) {
+ struct libj2_j2u c;
+ libj2_not_j2u_to_j2u(a, &c);
+ libj2_j2u_or_j2u(res, &c);
+ } else {
+ libj2_not_j2u_to_j2u(a, res);
+ libj2_j2u_or_j2u(res, b);
+ }
+}
+
+
+/**
+ * Calculate the bitwise IMPLY of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_imply_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ libj2_not_j2u_to_j2u(a, res);
+ libj2_j2u_or_ju(res, b);
+}
+
+
+/**
+ * Calculate the bitwise IF of two unsigned
+ * double-max precision integers
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_if_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ struct libj2_j2u c;
+ libj2_not_j2u_to_j2u(b, &c);
+ libj2_j2u_or_j2u(a, &c);
+}
+
+
+/**
+ * Calculate the bitwise NIF of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_if_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ struct libj2_j2u c;
+ libj2_not_ju_to_j2u(b, &c);
+ libj2_j2u_or_j2u(a, &c);
+}
+
+
+/**
+ * Calculate the bitwise IF of two unsigned
+ * double-max precision integers
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_if_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_imply_j2u_to_j2u(b, a, res);
+}
+
+
+/**
+ * Calculate the bitwise IF of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_if_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ if (res == a) {
+ struct libj2_j2u c;
+ libj2_not_ju_to_j2u(b, &c);
+ libj2_j2u_or_j2u(res, &c);
+ } else {
+ libj2_not_ju_to_j2u(b, res);
+ libj2_j2u_or_j2u(res, a);
+ }
+}
+
+
+/**
+ * Calculate the bitwise IMPLY of an unsigned max
+ * precision integer (left-hand) and an unsigned
+ * double-max precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_imply_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_if_ju_to_j2u(b, a, res);
+}
+
+
+/**
+ * Calculate the bitwise IF of an unsigned max
+ * precision integer (left-hand) and an unsigned
+ * double-max precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_if_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_imply_ju_to_j2u(b, a, res);
+}
+
+
+/**
+ * Calculate the bitwise NIMPLY of two unsigned
+ * double-max precision integers
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_nimply_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ struct libj2_j2u c;
+ libj2_not_j2u_to_j2u(b, &c);
+ libj2_j2u_and_j2u(a, &c);
+}
+
+
+/**
+ * Calculate the bitwise NIMPLY of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_nimply_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ struct libj2_j2u c;
+ libj2_not_ju_to_j2u(b, &c);
+ libj2_j2u_and_j2u(a, &c);
+}
+
+
+/**
+ * Calculate the bitwise NIMPLY of two unsigned
+ * double-max precision integers
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_nimply_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ if (a == b) {
+ res->high = 0;
+ res->low = 0;
+ } else if (res == a) {
+ struct libj2_j2u c;
+ libj2_not_j2u_to_j2u(b, &c);
+ libj2_j2u_and_j2u(res, &c);
+ } else {
+ libj2_not_j2u_to_j2u(b, res);
+ libj2_j2u_and_j2u(res, a);
+ }
+}
+
+
+/**
+ * Calculate the bitwise NIMPLY of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_nimply_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ if (res == a) {
+ struct libj2_j2u c;
+ libj2_not_ju_to_j2u(b, &c);
+ libj2_j2u_and_j2u(res, &c);
+ } else {
+ libj2_not_ju_to_j2u(b, res);
+ libj2_j2u_and_j2u(res, a);
+ }
+}
+
+
+/**
+ * Calculate the bitwise NIF of two unsigned
+ * double-max precision integers
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_nif_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ if (a == b) {
+ libj2_j2u_zero(a);
+ } else {
+ libj2_not_j2u(a);
+ libj2_j2u_and_j2u(a, b);
+ }
+}
+
+
+/**
+ * Calculate the bitwise NIF of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer, also used as the
+ * output parameter for result
+ * @param b The right-hand integer
+ */
+inline void
+libj2_j2u_nif_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ libj2_not_j2u(a);
+ libj2_j2u_and_ju(a, b);
+}
+
+
+/**
+ * Calculate the bitwise NIF of two unsigned
+ * double-max precision integers
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_nif_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_nimply_j2u_to_j2u(b, a, res);
+}
+
+
+/**
+ * Calculate the bitwise NIF of an unsigned double-max
+ * precision integer (left-hand) and an unsigned max
+ * precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_j2u_nif_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ libj2_not_j2u_to_j2u(a, res);
+ libj2_j2u_and_ju(res, b);
+}
+
+
+/**
+ * Calculate the bitwise NIMPLY of an unsigned max
+ * precision integer (left-hand) and an unsigned
+ * double-max precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_nimply_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_nif_ju_to_j2u(b, a, res);
+}
+
+
+/**
+ * Calculate the bitwise NIF of an unsigned max
+ * precision integer (left-hand) and an unsigned
+ * double-max precision integer (right-hand)
+ *
+ * @param a The left-hand integer
+ * @param b The right-hand integer
+ * @param res Output parameter for the result
+ */
+inline void
+libj2_ju_nif_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ libj2_j2u_nimply_ju_to_j2u(b, a, res);
+}
diff --git a/libj2/constants.h b/libj2/constants.h
new file mode 100644
index 0000000..e33fbff
--- /dev/null
+++ b/libj2/constants.h
@@ -0,0 +1,94 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBJ2_H
+# error Do not include this header directly, include <libj2.h> instead
+#endif
+
+
+/**
+ * Check whether an unsigned double-max precision integer has
+ * the value 0 (or equivalently, a non-positive value)
+ *
+ * `libj2_j2u_is_zero(a)` implements `*a == 0`
+ *
+ * @param a The integer to inspect
+ * @return 1 if `a` has the value 0, 0 otherwise
+ */
+inline int
+libj2_j2u_is_zero(const struct libj2_j2u *a)
+{
+ return !a->high && !a->low;
+}
+
+
+/**
+ * Assign the value 0 to unsigned double-max precision integer
+ *
+ * `libj2_j2u_zero(res)` implements `(void)(*res = 0)`
+ *
+ * @param res The integer to assign the value 0 to
+ */
+inline void
+libj2_j2u_zero(struct libj2_j2u *res)
+{
+ res->high = res->low = 0;
+}
+
+
+/**
+ * Check whether an unsigned double-max precision integer has
+ * the highest representable value
+ *
+ * @param a The integer to inspect
+ * @return 1 if `a` has highest representable value, 0 otherwise
+ */
+inline int
+libj2_j2u_is_max(const struct libj2_j2u *a)
+{
+ return a->high == UINTMAX_MAX && a->low == UINTMAX_MAX;
+}
+
+
+/**
+ * Assign the highest representable value to unsigned double-max
+ * precision integer
+ *
+ * @param res The integer to assign the value to
+ */
+inline void
+libj2_j2u_max(struct libj2_j2u *res)
+{
+ res->high = res->low = UINTMAX_MAX;
+}
+
+
+/**
+ * Check whether an unsigned double-max precision integer has
+ * the lowest representable value
+ *
+ * Since the integer type is unsigned, this function
+ * does the same thing as `libj2_j2u_is_zero(a)`
+ *
+ * @param a The integer to inspect
+ * @return 1 if `a` has lowest representable value, 0 otherwise
+ */
+inline int
+libj2_j2u_is_min(const struct libj2_j2u *a)
+{
+ return libj2_j2u_is_zero(a);
+}
+
+
+/**
+ * Assign the lowest representable value to unsigned double-max
+ * precision integer
+ *
+ * Since the integer type is unsigned, this function
+ * does the same thing as `libj2_j2u_zero(res)`
+ *
+ * @param res The integer to assign the value to
+ */
+inline void
+libj2_j2u_min(struct libj2_j2u *res)
+{
+ libj2_j2u_zero(res);
+}
diff --git a/libj2/constructors.h b/libj2/constructors.h
new file mode 100644
index 0000000..3f2b8fe
--- /dev/null
+++ b/libj2/constructors.h
@@ -0,0 +1,24 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBJ2_H
+# error Do not include this header directly, include <libj2.h> instead
+#endif
+
+
+/**
+ * Cast an unsigned max precision integer to an unsigned
+ * double-max precision integer
+ *
+ * `libj2_ju_to_j2u(a, res)` implements `*res = a`
+ *
+ * @param a The value to assign to `*res`
+ * @param res The integer to assign the value `a` to
+ */
+inline void
+libj2_ju_to_j2u(uintmax_t a, struct libj2_j2u *res)
+{
+ res->high = 0;
+ res->low = a;
+}
+
+
+/* libj2_j2u_zero, libj2_j2u_max, libj2_j2u_min are located in constants.h */
diff --git a/libj2/division.h b/libj2/division.h
new file mode 100644
index 0000000..9607b1b
--- /dev/null
+++ b/libj2/division.h
@@ -0,0 +1,534 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBJ2_H
+# error Do not include this header directly, include <libj2.h> instead
+#endif
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of two unsigned
+ * double-max precision integers
+ *
+ * `libj2_j2u_divmod_j2u_to_j2u(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
+ *
+ * @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
+ */
+inline void
+libj2_j2u_divmod_j2u_to_j2u(struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res_q)
+{
+ struct libj2_j2u q = {0, 0};
+ struct libj2_j2u c;
+ const struct libj2_j2u d = *b;
+ unsigned e = LIBJ2_J2U_BIT;
+ int cmp = libj2_j2u_cmp_j2u(a, b);
+
+ if (cmp <= 0) {
+ if (cmp == 0) {
+ q.low = 1U;
+ libj2_j2u_zero(a);
+ }
+ goto out;
+ }
+
+ /* TODO e = leading_zeroes(a) - leading_zeroes(b) + 1 */
+
+ while (!libj2_j2u_is_zero(a) && e--) {
+ if (libj2_j2u_lsh_to_j2u_overflow(&d, e, &c))
+ continue;
+ if (libj2_j2u_gt_j2u(&c, a))
+ continue;
+ if (e < LIBJ2_JU_BIT)
+ q.low |= (uintmax_t)1 << e;
+ else
+ q.high |= (uintmax_t)1 << (e - LIBJ2_JU_BIT);
+ libj2_j2u_sub_j2u(a, &c);
+ }
+
+out:
+ *res_q = q;
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of two unsigned
+ * double-max precision integers
+ *
+ * `libj2_j2u_divmod_j2u_to_j2u_j2u(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
+ *
+ * @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
+ */
+inline void
+libj2_j2u_divmod_j2u_to_j2u_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b,
+ struct libj2_j2u *res_q, struct libj2_j2u *res_r)
+{
+ if (res_r == b) {
+ struct libj2_j2u r = *a;
+ libj2_j2u_divmod_j2u_to_j2u(&r, b, res_q);
+ *res_r = r;
+ } else {
+ *res_r = *a;
+ libj2_j2u_divmod_j2u_to_j2u(res_r, b, res_q);
+ }
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of two unsigned
+ * double-max precision integers
+ *
+ * `libj2_j2u_divmod_j2u(a, b)` implements
+ * `t = (uintmax_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
+ *
+ * @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
+ */
+inline uintmax_t
+libj2_j2u_divmod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ struct libj2_j2u res;
+ libj2_j2u_divmod_j2u_to_j2u(a, b, &res);
+ return res.low;
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of an unsigned
+ * double-max precision integer (dividend) and
+ * an unsigned max precision integer (divisor)
+ *
+ * `libj2_j2u_divmod_ju(a, b)` implements
+ * `t = (uintmax_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
+ *
+ * @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
+ */
+inline uintmax_t
+libj2_j2u_divmod_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ uintmax_t q = 0;
+ struct libj2_j2u c;
+ unsigned e = LIBJ2_J2U_BIT;
+ a->high %= b;
+ while (a->high && e--) {
+ if (libj2_ju_lsh_to_j2u_overflow(b, e, &c))
+ continue;
+ if (libj2_j2u_gt_j2u(&c, a))
+ continue;
+ q |= (uintmax_t)1 << e;
+ libj2_j2u_sub_j2u(a, &c);
+ }
+ q += a->low / b;
+ a->low %= b;
+ return q;
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of an unsigned
+ * double-max precision integer (dividend) and
+ * an unsigned max precision integer (divisor)
+ *
+ * `libj2_j2u_divmod_ju_to_j2u(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
+ *
+ * @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
+ */
+inline void
+libj2_j2u_divmod_ju_to_j2u(struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res_q)
+{
+ res_q->high = a->high / b;
+ res_q->low = libj2_j2u_divmod_ju(a, b);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of an unsigned
+ * double-max precision integer (dividend) and
+ * an unsigned max precision integer (divisor)
+ *
+ * `libj2_j2u_divmod_ju_to_j2u_j2u(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
+ *
+ * @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
+ */
+inline void
+libj2_j2u_divmod_ju_to_j2u_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res_q, struct libj2_j2u *res_r)
+{
+ *res_r = *a;
+ res_q->high = res_r->high / b;
+ res_q->low = libj2_j2u_divmod_ju(res_r, b);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of two unsigned
+ * double-max precision integers; in this variant
+ * of `libj2_j2u_rdivmod_j2u_to_j2u`, the dividend
+ * (left-hand) is the second parameter and the
+ * divisor (right-hand) is the first parameter
+ *
+ * `libj2_j2u_rdivmod_j2u_to_j2u(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
+ *
+ * @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
+ */
+inline void
+libj2_j2u_rdivmod_j2u_to_j2u(struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res_q)
+{
+ struct libj2_j2u res_r;
+ libj2_j2u_divmod_j2u_to_j2u_j2u(b, a, res_q, &res_r);
+ *a = res_r;
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, and remainder of two unsigned
+ * double-max precision integers; in this variant
+ * of `libj2_j2u_rdivmod_j2u_to_j2u`, the dividend
+ * (left-hand) is the second parameter and the
+ * divisor (right-hand) is the first parameter
+ *
+ * `libj2_j2u_rdivmod_j2u(a, b)` implements
+ * `t = (uintmax_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
+ *
+ * @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
+ */
+inline uintmax_t
+libj2_j2u_rdivmod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ struct libj2_j2u q;
+ libj2_j2u_divmod_j2u_to_j2u_j2u(b, a, &q, a);
+ return q.low;
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_div_j2u(a, b)` implements `*a /= *b`
+ *
+ * @param a The dividend (left-hand), also used as
+ * the output parameter for the quotient
+ * @param b The divisor (right-hand)
+ */
+inline void
+libj2_j2u_div_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ struct libj2_j2u c = *a;
+ libj2_j2u_divmod_j2u_to_j2u(&c, b, a);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_div_j2u_to_j2u(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 quotient
+ */
+inline void
+libj2_j2u_div_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ struct libj2_j2u c = *a;
+ libj2_j2u_divmod_j2u_to_j2u(&c, b, res);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_div_j2u_return(a, b)`
+ * implements `(uintmax_t)(*a / *b)`
+ *
+ * @param a The dividend (left-hand)
+ * @param b The divisor (right-hand)
+ * @return The low half of the quotient
+ */
+inline uintmax_t
+libj2_j2u_div_j2u_return(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ struct libj2_j2u c = *a;
+ return libj2_j2u_divmod_j2u(&c, b);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of two unsigned double-max
+ * precision integers; in this variant
+ * of `libj2_j2u_div_j2u`, the dividend
+ * (left-hand) is the second parameter and the
+ * divisor (right-hand) is the first parameter
+ *
+ * `libj2_j2u_rdiv_j2u(a, b)` implements `*a = *b / *a`
+ *
+ * @param a The divisor (right-hand), also used as
+ * the output parameter for the quotient
+ * @param b The dividend (left-hand)
+ */
+inline void
+libj2_j2u_rdiv_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ struct libj2_j2u c = *b;
+ libj2_j2u_divmod_j2u_to_j2u(&c, a, a);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of an unsigned double-max
+ * precision integer (dividend) and an
+ * unsigned max precision integer (divisor)
+ *
+ * `libj2_j2u_div_ju(a, b)` implements `*a /= b`
+ *
+ * @param a The dividend (left-hand), also used as
+ * the output parameter for the quotient
+ * @param b The divisor (right-hand)
+ */
+inline void
+libj2_j2u_div_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ struct libj2_j2u c = *a;
+ libj2_j2u_divmod_ju_to_j2u(&c, b, a);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of an unsigned double-max
+ * precision integer (dividend) and an
+ * unsigned max precision integer (divisor)
+ *
+ * `libj2_j2u_div_ju_to_j2u(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 quotient
+ */
+inline void
+libj2_j2u_div_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ struct libj2_j2u c = *a;
+ libj2_j2u_divmod_ju_to_j2u(&c, b, res);
+}
+
+
+/**
+ * Calculate the integer quotient, rounded
+ * towards zero, of an unsigned double-max
+ * precision integer (dividend) and an
+ * unsigned max precision integer (divisor)
+ *
+ * `libj2_j2u_div_ju_return(a, b)`
+ * implements `(uintmax_t)(*a / b)`
+ *
+ * @param a The dividend (left-hand)
+ * @param b The divisor (right-hand)
+ * @return The low half of the quotient
+ */
+inline uintmax_t
+libj2_j2u_div_ju_return(const struct libj2_j2u *a, uintmax_t b)
+{
+ struct libj2_j2u c = *a;
+ return libj2_j2u_divmod_ju(&c, b);
+}
+
+
+/**
+ * Calculate the integer remainder, for integer
+ * division with the quotient rounded towards zero,
+ * of two unsigned double-max precision integers
+ *
+ * `libj2_j2u_mod_j2u(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)
+ */
+inline void
+libj2_j2u_mod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ (void) libj2_j2u_divmod_j2u(a, b);
+}
+
+
+/**
+ * Calculate the integer remainder, for integer
+ * division with the quotient rounded towards zero,
+ * of two unsigned double-max precision integers
+ *
+ * `libj2_j2u_mod_j2u_to_j2u(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
+ */
+inline void
+libj2_j2u_mod_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ if (res == b) {
+ struct libj2_j2u r = *a;
+ libj2_j2u_mod_j2u(&r, b);
+ *res = r;
+ } else {
+ *res = *a;
+ libj2_j2u_mod_j2u(res, b);
+ }
+}
+
+
+/**
+ * Calculate the integer remainder, for integer
+ * division with the quotient rounded towards zero,
+ * of two unsigned double-max precision integers;
+ * in this variant of `libj2_j2u_mod_j2u`, the
+ * dividend (left-hand) is the second parameter
+ * and the divisor (right-hand) is the first parameter
+ *
+ * `libj2_j2u_rmod_j2u_to_j2u(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)
+ */
+inline void
+libj2_j2u_rmod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ libj2_j2u_mod_j2u_to_j2u(b, a, a);
+}
+
+
+/**
+ * Calculate the integer remainder, for integer
+ * division with the quotient rounded towards zero,
+ * of an unsigned double-max precision integer
+ * (dividend) and an unsigned max precision
+ * integer (divisor)
+ *
+ * `libj2_j2u_mod_ju(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)
+ */
+inline void
+libj2_j2u_mod_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ struct libj2_j2u c;
+ unsigned e = LIBJ2_JU_BIT;
+ a->high %= b;
+ while (a->high && e--) {
+ libj2_ju_lsh_to_j2u(b, e, &c);
+ if (libj2_j2u_gt_j2u(&c, a))
+ continue;
+ libj2_j2u_sub_j2u(a, &c);
+ }
+ a->low %= b;
+}
+
+
+/**
+ * Calculate the integer remainder, for integer
+ * division with the quotient rounded towards zero,
+ * of an unsigned double-max precision integer
+ * (dividend) and an unsigned max precision
+ * integer (divisor)
+ *
+ * `libj2_j2u_mod_ju_to_j2u(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
+ */
+inline void
+libj2_j2u_mod_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ *res = *a;
+ libj2_j2u_mod_ju(res, b);
+}
diff --git a/libj2/multiplication.h b/libj2/multiplication.h
new file mode 100644
index 0000000..005fa5d
--- /dev/null
+++ b/libj2/multiplication.h
@@ -0,0 +1,366 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBJ2_H
+# error Do not include this header directly, include <libj2.h> instead
+#endif
+
+
+/**
+ * Calculate the unsigned double-max precision integer
+ * product of two unsigned double-max precision integers
+ *
+ * `libj2_ju_mul_ju_to_j2u(a, b, res)` implements
+ * `*res = a * b`, where `a` and `b` are converted
+ * into `struct libj2_j2u`'s
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ */
+inline void
+libj2_ju_mul_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *res)
+{
+ const int n = (int)LIBJ2_JU_BIT / 2;
+ uintmax_t a1, a2, b1, b2, c, c1, c2;
+
+ a1 = a >> n;
+ b1 = b >> n;
+ a2 = a ^ (a1 << n);
+ b2 = b ^ (b1 << n);
+
+ res->high = a1 * b1;
+ res->low = a2 * b2;
+
+ c = a1 * b2;
+ c1 = c >> n;
+ c2 = c ^ (c1 << n);
+ c2 <<= n;
+ res->high += c1;
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_add_overflow(res->low, c2, &res->low))
+ res->high += 1U;
+#else
+ if (res->low > UINTMAX_MAX - c2)
+ res->high += 1U;
+ res->low += c2;
+#endif
+
+ c = a2 * b1;
+ c1 = c >> n;
+ c2 = c ^ (c1 << n);
+ c2 <<= n;
+ res->high += c1;
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_add_overflow(res->low, c2, &res->low))
+ res->high += 1U;
+#else
+ if (res->low > UINTMAX_MAX - c2)
+ res->high += 1U;
+ res->low += c2;
+#endif
+}
+
+
+/**
+ * Calculate the product of an unsigned double-max
+ * precision integer (multiplier) and an unsigned
+ * max precision integer (multiplicand)
+ *
+ * `libj2_j2u_mul_ju_to_j2u(a, b)` implements `*a *= b`,
+ * where `b` are converted into an `struct libj2_j2u`
+ *
+ * @param a The multiplier, also used as the
+ * output parameter for the product
+ * @param b The multiplicand
+ */
+inline void
+libj2_j2u_mul_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ uintmax_t c = a->high * b;
+ libj2_ju_mul_ju_to_j2u(a->low, b, a);
+ a->high += c;
+}
+
+
+/**
+ * Calculate the product of an unsigned double-max
+ * precision integer (multiplier) and an unsigned
+ * max precision integer (multiplicand)
+ *
+ * `libj2_j2u_mul_ju_to_j2u(a, b, res)` implements
+ * `*res = *a * b`, where `b` are converted into
+ * an `struct libj2_j2u`
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ */
+inline void
+libj2_j2u_mul_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ *res = *a;
+ libj2_j2u_mul_ju(res, b);
+}
+
+
+/**
+ * Calculate the product of an unsigned max
+ * precision integer (multiplier) and an unsigned
+ * double-max precision integer (multiplicand)
+ *
+ * `libj2_ju_mul_j2u_to_j2u(a, b, res)` implements
+ * `*res = a * *b`, where `a` are converted into
+ * an `struct libj2_j2u`
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ */
+inline void
+libj2_ju_mul_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ *res = *b;
+ libj2_j2u_mul_ju(res, a);
+}
+
+
+/**
+ * Calculate the product of an unsigned double-max
+ * precision integer (multiplier) and an unsigned
+ * max precision integer (multiplicand)
+ *
+ * `libj2_j2u_mul_ju_to_overflow(a, b)` implements
+ * `*a *= b`, where `b` are converted into an
+ * `struct libj2_j2u`, with overflow-detection
+ *
+ * @param a The multiplier, also used as the
+ * output parameter for the product
+ * @param b The multiplicand
+ * @return 1 if the result overflowed, 0 otherwise
+ */
+inline int
+libj2_j2u_mul_ju_overflow(struct libj2_j2u *a, uintmax_t b)
+{
+ int overflow = 0;
+ uintmax_t c;
+
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ overflow |= __builtin_mul_overflow(a->high, b, &c);
+#else
+ if (b && a->high > UINTMAX_MAX / b)
+ overflow = 1;
+ c = a->high * b;
+#endif
+
+ libj2_ju_mul_ju_to_j2u(a->low, b, a);
+
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ overflow |= __builtin_add_overflow(a->high, c, &a->high);
+#else
+ if (a->high > UINTMAX_MAX - c)
+ overflow = 1;
+ a->high += c;
+#endif
+
+ return overflow;
+}
+
+
+/**
+ * Calculate the product of an unsigned double-max
+ * precision integer (multiplier) and an unsigned
+ * max precision integer (multiplicand)
+ *
+ * `libj2_j2u_mul_ju_to_j2u_overflow(a, b, res)`
+ * implements `*res = *a * b`, where `b` are
+ * converted into an `struct libj2_j2u`, with
+ * overflow-detection
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ * @return 1 if the result overflowed, 0 otherwise
+ */
+inline int
+libj2_j2u_mul_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ *res = *a;
+ return libj2_j2u_mul_ju_overflow(res, b);
+}
+
+
+/**
+ * Calculate the product of an unsigned max
+ * precision integer (multiplier) and an unsigned
+ * double-max precision integer (multiplicand)
+ *
+ * `libj2_ju_mul_j2u_to_j2u_overflow(a, b, res)`
+ * implements `*res = a * *b`, where `a` are
+ * converted into an `struct libj2_j2u`, with
+ * overflow-detection
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ * @return 1 if the result overflowed, 0 otherwise
+ */
+inline int
+libj2_ju_mul_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ *res = *b;
+ return libj2_j2u_mul_ju_overflow(res, a);
+}
+
+
+/**
+ * Calculate the product of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_mul_j2u_destructive(a, b)`
+ * implements `*a *= *b`, except that `*b`
+ * will be arbitrarily modified
+ *
+ * @param a The multiplier, also used as the
+ * output parameter for the product
+ * @param b The multiplicand; will be tainted
+ *
+ * `a` and `b` must not be the same pointers
+ */
+inline void
+libj2_j2u_mul_j2u_destructive(struct libj2_j2u *restrict a /* result */, struct libj2_j2u *restrict b /* destructed */)
+{
+ a->high *= b->low;
+ b->high *= a->low;
+ b->high += a->high;
+
+ libj2_ju_mul_ju_to_j2u(a->low, b->low, a);
+ a->high += b->high;
+}
+
+
+/**
+ * Calculate the product of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_mul_j2u(a, b)` implements `*a *= *b`
+ *
+ * @param a The multiplier, also used as the
+ * output parameter for the product
+ * @param b The multiplicand
+ */
+inline void
+libj2_j2u_mul_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ struct libj2_j2u c = *b;
+ libj2_j2u_mul_j2u_destructive(a, &c);
+}
+
+
+/**
+ * Calculate the product of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_mul_j2u_overflow_destructive(a, b)`
+ * implements `*a *= *b`, except that `*b`
+ * will be arbitrarily modified, with
+ * overflow-detection
+ *
+ * @param a The multiplier, also used as the
+ * output parameter for the product
+ * @param b The multiplicand; will be tainted
+ * @return 1 if the result overflowed, 0 otherwise
+ *
+ * `a` and `b` must not be the same pointers
+ */
+inline int
+libj2_j2u_mul_j2u_overflow_destructive(struct libj2_j2u *restrict a /* result */, struct libj2_j2u *restrict b /* destructed */)
+{
+ int overflow = a->high && b->high;
+
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ overflow |= __builtin_mul_overflow(a->high, b->low, &a->high);
+ overflow |= __builtin_mul_overflow(b->high, a->low, &b->high);
+ overflow |= __builtin_add_overflow(b->high, a->high, &b->high);
+#else
+ if (b->low && a->high > UINTMAX_MAX / b->low)
+ overflow = 1;
+ a->high *= b->low;
+ if (a->low && b->high > UINTMAX_MAX / a->low)
+ overflow = 1;
+ b->high *= a->low;
+ if (b->high > UINTMAX_MAX - a->high)
+ overflow = 1;
+ b->high += a->high;
+#endif
+
+ libj2_ju_mul_ju_to_j2u(a->low, b->low, a);
+
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ overflow |= __builtin_add_overflow(a->high, b->high, &a->high);
+#else
+ if (a->high > UINTMAX_MAX - b->high)
+ overflow = 1;
+ a->high += b->high;
+#endif
+
+ return overflow;
+}
+
+
+/**
+ * Calculate the product of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_mul_j2u_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 if the result overflowed, 0 otherwise
+ */
+inline int
+libj2_j2u_mul_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ struct libj2_j2u c = *b;
+ return libj2_j2u_mul_j2u_overflow_destructive(a, &c);
+}
+
+
+/**
+ * Calculate the product of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_mul_j2u_to_j2u(a, b, res)`
+ * implements `*res = *a * *b`
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ */
+inline void
+libj2_j2u_mul_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ struct libj2_j2u c = *b;
+ *res = *a;
+ libj2_j2u_mul_j2u_destructive(res, &c);
+}
+
+/**
+ * Calculate the product of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_mul_j2u_to_j2u_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 if the result overflowed, 0 otherwise
+ */
+inline int
+libj2_j2u_mul_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ struct libj2_j2u c = *b;
+ *res = *a;
+ return libj2_j2u_mul_j2u_overflow_destructive(res, &c);
+}
diff --git a/libj2/sign-shifting.h b/libj2/sign-shifting.h
new file mode 100644
index 0000000..034259e
--- /dev/null
+++ b/libj2/sign-shifting.h
@@ -0,0 +1,43 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBJ2_H
+# error Do not include this header directly, include <libj2.h> instead
+#endif
+
+
+/**
+ * Calculate the additive inverse of an unsigned
+ * double-max precision integer
+ *
+ * `libj2_minus_j2u(a)` implements `*a = -*a`
+ *
+ * @param a The integer to invert, also used as the
+ * output parameter for the inverse
+ */
+inline void
+libj2_minus_j2u(struct libj2_j2u *a)
+{
+ a->high = -a->high;
+ if (a->low) {
+ a->high -= 1U;
+ a->low = -a->low;
+ }
+}
+
+
+/**
+ * Calculate the additive inverse of an unsigned
+ * double-max precision integer
+ *
+ * `libj2_minus_j2u_j2u(a, res)` implements `*res = -*a`
+ *
+ * @param a The integer to invert
+ * @param res Output parameter for the inverse
+ */
+inline void
+libj2_minus_j2u_to_j2u(const struct libj2_j2u *a, struct libj2_j2u *res)
+{
+ res->high = -a->high;
+ if (a->low)
+ res->high -= 1U;
+ res->low = -a->low;
+}
diff --git a/libj2/signum.h b/libj2/signum.h
new file mode 100644
index 0000000..7ae1833
--- /dev/null
+++ b/libj2/signum.h
@@ -0,0 +1,45 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBJ2_H
+# error Do not include this header directly, include <libj2.h> instead
+#endif
+
+
+/**
+ * Check whether an unsigned double-max precision integer has a
+ * positive value (or equivalently, a non-zero value)
+ *
+ * `libj2_j2u_is_positive(a)` implements `*a > 0`
+ *
+ * @param a The integer to inspect
+ * @return 1 if `a` has a positive value, 0 otherwise
+ */
+inline int
+libj2_j2u_is_positive(const struct libj2_j2u *a)
+{
+ return a->high || a->low;
+}
+
+
+/**
+ * Get the sign (signum function) of an unsigned double-max
+ * precision integer
+ *
+ * `libj2_sgn_j2u(a)` implements `*a < 0 ? -1 : *a > 0 ? +1 : 0`,
+ * or equaivalently, since `a` is unsigned, `*a > 0 ? +1 : 0`
+ *
+ * Since the integer type is unsigned, this function
+ * does the same thing as `libj2_j2u_is_positive(res)`
+ *
+ * @param a The integer to inspect
+ * @return -1 if `a` is negative (impossible),
+ * +1 if `a` is positive, and
+ * 0 if `a` is 0
+ */
+inline int
+libj2_sgn_j2u(const struct libj2_j2u *a)
+{
+ return libj2_j2u_is_positive(a);
+}
+
+
+/* libj2_j2u_is_zero is located in constants.h */
diff --git a/libj2/subtraction.h b/libj2/subtraction.h
new file mode 100644
index 0000000..27ae9d6
--- /dev/null
+++ b/libj2/subtraction.h
@@ -0,0 +1,493 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBJ2_H
+# error Do not include this header directly, include <libj2.h> instead
+#endif
+
+
+/**
+ * Calculate the difference between an unsigned
+ * double-max precision integer (minuend) and an
+ * unsigned max precision integer (subtrahend)
+ *
+ * `libj2_j2u_sub_ju(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)
+ */
+inline void
+libj2_j2u_sub_ju(struct libj2_j2u *a, uintmax_t b)
+{
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_sub_overflow(a->low, b, &a->low))
+ a->high -= 1U;
+#else
+ if (a->low < b)
+ a->high -= 1U;
+ a->low -= b;
+#endif
+}
+
+
+/**
+ * Calculate the difference between an unsigned
+ * double-max precision integer (minuend) and an
+ * unsigned max precision integer (subtrahend)
+ *
+ * `libj2_j2u_sub_ju_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 if the result overflowed (`b` is greater than `*a`),
+ * so the result wrapped around (actual difference is
+ * negative), 0 otherwise
+ */
+inline int
+libj2_j2u_sub_ju_overflow(struct libj2_j2u *a, uintmax_t b)
+{
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_sub_overflow(a->low, b, &a->low))
+ return __builtin_sub_overflow(a->high, 1U, &a->high);
+ return 0;
+#else
+ int overflow = 0;
+ if (a->low < b) {
+ if (!a->high)
+ overflow = 1;
+ a->high -= 1U;
+ }
+ a->low -= b;
+ return overflow;
+#endif
+}
+
+
+/**
+ * Calculate the difference between an unsigned
+ * double-max precision integer (minuend) and an
+ * unsigned max precision integer (subtrahend)
+ *
+ * `libj2_j2u_sub_ju_to_j2u(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
+ */
+inline void
+libj2_j2u_sub_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ res->high = a->high;
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_sub_overflow(a->low, b, &res->low))
+ res->high -= 1U;
+#else
+ if (a->low < b)
+ res->high -= 1U;
+ res->low = a->low - b;
+#endif
+}
+
+
+/**
+ * Calculate the difference between an unsigned
+ * double-max precision integer (minuend) and an
+ * unsigned max precision integer (subtrahend)
+ *
+ * `libj2_j2u_sub_ju_to_j2u_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 if the result overflowed (`b` is greater than `*a`),
+ * so the result wrapped around (actual difference is
+ * negative), 0 otherwise
+ */
+inline int
+libj2_j2u_sub_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_sub_overflow(a->low, b, &res->low))
+ return __builtin_sub_overflow(a->high, 1U, &res->high);
+ res->high = a->high;
+ return 0;
+#else
+ int overflow = 0;
+ res->high = a->high;
+ if (a->low < b) {
+ if (!a->high)
+ overflow = 1;
+ res->high -= 1U;
+ }
+ res->low = a->low - b;
+ return overflow;
+#endif
+}
+
+
+/**
+ * Calculate the difference between two unsigned
+ * max precision integers, as an unsigned double-max
+ * precision integer
+ *
+ * `libj2_ju_sub_ju_to_j2u_overflow(a, b, res)`
+ * implements `*res = a - b`, where `a` and `b`
+ * are converted into `struct libj2_j2u`'s
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @param res Output parameter for the difference
+ */
+inline void
+libj2_ju_sub_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *res)
+{
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ res->high = -(uintmax_t)(__builtin_sub_overflow(a, b, &res->low) ? 1U : 0U);
+#else
+ res->high = -(uintmax_t)(a < b);
+ res->low = a - b;
+#endif
+}
+
+
+/**
+ * Calculate the difference between two unsigned
+ * max precision integers, as an unsigned double-max
+ * precision integer
+ *
+ * `libj2_ju_sub_ju_to_j2u_overflow(a, b, res)`
+ * implements `*res = a - b` with overflow-detection,
+ * and where `a` and `b` are converted into
+ * `struct libj2_j2u`'s
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @param res Output parameter for the difference
+ * @return 1 if the result overflowed (`b` is greater than `*a`),
+ * so the result wrapped around (actual difference is
+ * negative), 0 otherwise
+ */
+inline int
+libj2_ju_sub_ju_to_j2u_overflow(uintmax_t a, uintmax_t b, struct libj2_j2u *res)
+{
+ int overflow;
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ overflow = __builtin_sub_overflow(a, b, &res->low) ? 1 : 0;
+#else
+ overflow = a < b;
+ res->low = a - b;
+#endif
+ res->high = -(uintmax_t)overflow;
+ return overflow;
+}
+
+
+/**
+ * Calculate the difference between two unsigned
+ * double-max precision integers
+ *
+ * `libj2_j2u_sub_j2u(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)
+ */
+inline void
+libj2_j2u_sub_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ libj2_j2u_sub_ju(a, b->low);
+ a->high -= b->high;
+}
+
+
+/**
+ * Calculate the difference between two unsigned
+ * double-max precision integers
+ *
+ * `libj2_j2u_sub_j2u_to_j2u(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
+ */
+inline void
+libj2_j2u_sub_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ if (a == b) {
+ libj2_j2u_zero(res);
+ } else if (res == b) {
+ libj2_minus_j2u(res);
+ libj2_j2u_add_j2u(res, a);
+ } else {
+ libj2_j2u_sub_ju_to_j2u(a, b->low, res);
+ res->high -= b->high;
+ }
+}
+
+
+/**
+ * Calculate the difference between two unsigned
+ * double-max precision integers
+ *
+ * `libj2_j2u_sub_j2u_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 if the result overflowed (`b` is greater than `*a`),
+ * so the result wrapped around (actual difference is
+ * negative), 0 otherwise
+ */
+inline int
+libj2_j2u_sub_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ int overflow = libj2_j2u_sub_ju_overflow(a, b->low);
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ return __builtin_sub_overflow(a->high, b->high, &a->high) || overflow;
+#else
+ if (a->high < b->high)
+ overflow = 1;
+ a->high -= b->high;
+ return overflow;
+#endif
+}
+
+
+/**
+ * Calculate the difference between two unsigned
+ * double-max precision integers
+ *
+ * `libj2_j2u_sub_j2u_to_j2u_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 if the result overflowed (`b` is greater than `*a`),
+ * so the result wrapped around (actual difference is
+ * negative), 0 otherwise
+ */
+inline int
+libj2_j2u_sub_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ if (a == b) {
+ libj2_j2u_zero(res);
+ return 0;
+ } else if (res == b) {
+ int overflow = libj2_j2u_lt_j2u(a, res);
+ libj2_minus_j2u(res);
+ libj2_j2u_add_j2u(res, a);
+ return overflow;
+ } else {
+ int overflow = libj2_j2u_sub_ju_to_j2u_overflow(a, b->low, res);
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ return __builtin_sub_overflow(res->high, b->high, &res->high) || overflow;
+#else
+ if (res->high < b->high)
+ overflow = 1;
+ res->high -= b->high;
+ return overflow;
+#endif
+ }
+}
+
+
+/**
+ * Calculate the difference between an unsigned
+ * max precision integer (minuend) and an unsigned
+ * double-max precision integer (subtrahend)
+ *
+ * `libj2_ju_sub_j2u_to_j2u(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
+ */
+inline void
+libj2_ju_sub_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ if (res == b) {
+ libj2_minus_j2u(res);
+ libj2_j2u_add_ju(res, a);
+ } else {
+ res->high = 0;
+ res->low = a;
+ libj2_j2u_sub_j2u(res, b);
+ }
+}
+
+
+/**
+ * Calculate the difference between an unsigned
+ * max precision integer (minuend) and an unsigned
+ * double-max precision integer (subtrahend)
+ *
+ * `libj2_ju_sub_j2u_to_j2u_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 if the result overflowed (`*b` is greater than `a`),
+ * so the result wrapped around (actual difference is
+ * negative), 0 otherwise
+ */
+inline int
+libj2_ju_sub_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ if (res == b) {
+ int overflow = b->high || b->low > a;
+ libj2_minus_j2u(res);
+ libj2_j2u_add_ju(res, a);
+ return overflow;
+ } else {
+ res->high = 0;
+ res->low = a;
+ return libj2_j2u_sub_j2u_overflow(res, b);
+ }
+}
+
+
+/**
+ * Calculate the difference between two unsigned
+ * max precision integers; in this variant of
+ * `libj2_j2u_sub_j2u`, the minuend (left-hand)
+ * is the second parameter and the subtrahend
+ * (right-hand) is the first parameter
+ *
+ * `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)
+ */
+inline void
+libj2_j2u_rsub_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ a->high = b->high - a->high;
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_sub_overflow(b->low, a->low, &a->low))
+ a->high -= 1U;
+#else
+ if (a->low > b->low)
+ a->high -= 1U;
+ a->low = b->low - a->low;
+#endif
+}
+
+
+/**
+ * Calculate the difference between two unsigned
+ * max precision integers; in this variant of
+ * `libj2_j2u_sub_j2u`, the minuend (left-hand)
+ * is the second parameter and the subtrahend
+ * (right-hand) is the first parameter
+ *
+ * `libj2_j2u_rsub_j2u_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 if the result overflowed (`*a` is greater than `*b`),
+ * so the result wrapped around (actual difference is
+ * negative), 0 otherwise
+ */
+inline int
+libj2_j2u_rsub_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ int overflow;
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ overflow = __builtin_sub_overflow(b->high, a->high, &a->high);
+ if (__builtin_sub_overflow(b->low, a->low, &a->low))
+ overflow |= __builtin_sub_overflow(a->high, 1U, &a->high);
+#else
+ overflow = b->high < a->high;
+ a->high = b->high - a->high;
+ if (b->low < a->low) {
+ if (!a->high)
+ overflow = 1;
+ a->high -= 1U;
+ }
+ a->low = b->low - a->low;
+#endif
+ return overflow;
+}
+
+
+/**
+ * Calculate the difference between an unsigned
+ * max precision integer (minuend) and an unsigned
+ * double-max precision integer (subtrahend);
+ * in this variant of `libj2_j2u_sub_ju`, the
+ * minuend (left-hand) is the second parameter
+ * and the subtrahend (right-hand) is the first
+ * parameter
+ *
+ * `libj2_j2u_rsub_ju(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)
+ */
+inline void
+libj2_j2u_rsub_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ a->high = -a->high;
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_sub_overflow(b, a->low, &a->low))
+ a->high -= 1U;
+#else
+ if (a->low > b)
+ a->high -= 1U;
+ a->low = b - a->low;
+#endif
+}
+
+
+/**
+ * Calculate the difference between an unsigned
+ * max precision integer (minuend) and an unsigned
+ * double-max precision integer (subtrahend);
+ * in this variant of `libj2_j2u_sub_ju`, the
+ * minuend (left-hand) is the second parameter
+ * and the subtrahend (right-hand) is the first
+ * parameter
+ *
+ * `libj2_j2u_rsub_ju_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 if the result overflowed (`*a` is greater than `b`),
+ * so the result wrapped around (actual difference is
+ * negative), 0 otherwise
+ */
+inline int
+libj2_j2u_rsub_ju_overflow(struct libj2_j2u *a, uintmax_t b)
+{
+ int overflow = !!a->high;
+ a->high = -a->high;
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_sub_overflow(b, a->low, &a->low))
+ overflow |= __builtin_sub_overflow(a->high, 1U, &a->high);
+#else
+ if (a->low > b) {
+ if (!a->high)
+ overflow = 1;
+ a->high -= 1U;
+ }
+ if (b < a->low)
+ overflow = 1;
+ a->low = b - a->low;
+#endif
+ return overflow;
+}
diff --git a/libj2/unsigned-comparsion.h b/libj2/unsigned-comparsion.h
new file mode 100644
index 0000000..3362753
--- /dev/null
+++ b/libj2/unsigned-comparsion.h
@@ -0,0 +1,774 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBJ2_H
+# error Do not include this header directly, include <libj2.h> instead
+#endif
+
+
+
+/**
+ * Check whether an unsigned double-max precision integer is
+ * less than another unsigned double-max precision integer
+ *
+ * `libj2_j2u_lt_j2u(a, b)` implements `*a < *b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `*a` is less than `*b`, 0 otherwise
+ */
+inline int
+libj2_j2u_lt_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ return a->high < b->high || (a->high == b->high && a->low < b->low);
+}
+
+
+/**
+ * Check whether an unsigned double-max precision integer is less
+ * than or equal to another unsigned double-max precision integer
+ *
+ * `libj2_j2u_le_j2u(a, b)` implements `*a <= *b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `*a` is less than or equal to `*b`, 0 otherwise
+ */
+inline int
+libj2_j2u_le_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ return a->high < b->high || (a->high == b->high && a->low <= b->low);
+}
+
+
+/**
+ * Check whether an unsigned double-max precision integer is
+ * greater than another unsigned double-max precision integer
+ *
+ * `libj2_j2u_gt_j2u(a, b)` implements `*a > *b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `*a` is greater than `*b`, 0 otherwise
+ */
+inline int
+libj2_j2u_gt_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ return a->high > b->high || (a->high == b->high && a->low > b->low);
+}
+
+
+/**
+ * Check whether an unsigned double-max precision integer is greater
+ * than or equal to another unsigned double-max precision integer
+ *
+ * `libj2_j2u_ge_j2u(a, b)` implements `*a >= *b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `*a` is greater than or equal to `*b`, 0 otherwise
+ */
+inline int
+libj2_j2u_ge_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ return a->high > b->high || (a->high == b->high && a->low >= b->low);
+}
+
+
+/**
+ * Check whether an unsigned double-max precision integer is
+ * equal to another unsigned double-max precision integer
+ *
+ * `libj2_j2u_eq_j2u(a, b)` implements `*a == *b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `*a` is equal to `*b`, 0 otherwise
+ */
+inline int
+libj2_j2u_eq_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ return a->high == b->high && a->low == b->low;
+}
+
+
+/**
+ * Check whether an unsigned double-max precision integer is
+ * not equal to another unsigned double-max precision integer
+ *
+ * `libj2_j2u_eq_j2u(a, b)` implements `*a != *b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `*a` is not equal to `*b`, 0 otherwise
+ */
+inline int
+libj2_j2u_ne_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ return a->high != b->high || a->low != b->low;
+}
+
+
+/**
+ * Compare an unsigned double-max precision integer
+ * to another unsigned double-max precision integer
+ *
+ * `libj2_j2u_cmp_j2u(a, b)` implements `*a < *b ? -1 : *a > *b ? +1 : 0`,
+ * or equivalently, the signum of `*a - *b` where the signum is 0 for 0
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return -1 if `*a` is less than `*b`,
+ * +1 if `*a` is greater than `*b`,
+ * 0 if `*a` is equal to `*b`
+ */
+inline int
+libj2_j2u_cmp_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ return a->high < b->high ? -1 : a->high > b->high ? +1 : a->low < b->low ? -1 : a->low > b->low;
+}
+
+
+/**
+ * Check whether an unsigned double-max precision integer
+ * is less than an unsigned max precision integer
+ *
+ * `libj2_j2u_lt_ju(a, b)` implements `*a < b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `*a` is less than `b`, 0 otherwise
+ */
+inline int
+libj2_j2u_lt_ju(const struct libj2_j2u *a, uintmax_t b)
+{
+ return !a->high && a->low < b;
+}
+
+
+/**
+ * Check whether an unsigned double-max precision integer is
+ * less than or equal to an unsigned max precision integer
+ *
+ * `libj2_j2u_le_ju(a, b)` implements `*a <= b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `*a` is less than or equal to `b`, 0 otherwise
+ */
+inline int
+libj2_j2u_le_ju(const struct libj2_j2u *a, uintmax_t b)
+{
+ return !a->high && a->low <= b;
+}
+
+
+/**
+ * Check whether an unsigned double-max precision integer
+ * is greater than an unsigned max precision integer
+ *
+ * `libj2_j2u_gt_ju(a, b)` implements `*a > b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `*a` is less than `b`, 0 otherwise
+ */
+inline int
+libj2_j2u_gt_ju(const struct libj2_j2u *a, uintmax_t b)
+{
+ return a->high || a->low > b;
+}
+
+
+/**
+ * Check whether an unsigned double-max precision integer is
+ * greater than or equal to an unsigned max precision integer
+ *
+ * `libj2_j2u_ge_ju(a, b)` implements `*a >= b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `*a` is greater than or equal to `b`, 0 otherwise
+ */
+inline int
+libj2_j2u_ge_ju(const struct libj2_j2u *a, uintmax_t b)
+{
+ return a->high || a->low >= b;
+}
+
+
+/**
+ * Check whether an unsigned double-max precision integer
+ * is equal to an unsigned max precision integer
+ *
+ * `libj2_j2u_eq_ju(a, b)` implements `*a == b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `*a` is equal to `b`, 0 otherwise
+ */
+inline int
+libj2_j2u_eq_ju(const struct libj2_j2u *a, uintmax_t b)
+{
+ return !a->high && a->low == b;
+}
+
+
+/**
+ * Check whether an unsigned double-max precision integer
+ * is not equal to an unsigned max precision integer
+ *
+ * `libj2_j2u_ne_ju(a, b)` implements `*a != b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `*a` is not equal to `b`, 0 otherwise
+ */
+inline int
+libj2_j2u_ne_ju(const struct libj2_j2u *a, uintmax_t b)
+{
+ return a->high || a->low != b;
+}
+
+
+/**
+ * Compare an unsigned double-max precision integer
+ * to an unsigned max precision integer
+ *
+ * `libj2_j2u_cmp_ju(a, b)` implements `*a < b ? -1 : *a > b ? +1 : 0`,
+ * or equivalently, the signum of `*a - b` where the signum is 0 for 0
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return -1 if `*a` is less than `b`,
+ * +1 if `*a` is greater than `b`,
+ * 0 if `*a` is equal to `b`
+ */
+inline int
+libj2_j2u_cmp_ju(const struct libj2_j2u *a, uintmax_t b)
+{
+ return a->high ? +1 : a->low < b ? -1 : a->low > b;
+}
+
+
+/**
+ * Check whether an unsigned max precision integer is
+ * less than an unsigned double-max precision integer
+ *
+ * `libj2_ju_lt_j2u(a, b)` implements `a < *b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `a` is less than `*b`, 0 otherwise
+ */
+inline int
+libj2_ju_lt_j2u(uintmax_t a, const struct libj2_j2u *b)
+{
+ return libj2_j2u_gt_ju(b, a);
+}
+
+
+/**
+ * Check whether an unsigned max precision integer is less
+ * than or equal to an unsigned double-max precision integer
+ *
+ * `libj2_ju_le_j2u(a, b)` implements `a <= *b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `a` is less than or equal to `*b`, 0 otherwise
+ */
+inline int
+libj2_ju_le_j2u(uintmax_t a, const struct libj2_j2u *b)
+{
+ return libj2_j2u_ge_ju(b, a);
+}
+
+
+/**
+ * Check whether an unsigned max precision integer is
+ * greater than an unsigned double-max precision integer
+ *
+ * `libj2_ju_gt_j2u(a, b)` implements `a > *b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `a` is less than `*b`, 0 otherwise
+ */
+inline int
+libj2_ju_gt_j2u(uintmax_t a, const struct libj2_j2u *b)
+{
+ return libj2_j2u_lt_ju(b, a);
+}
+
+
+/**
+ * Check whether an unsigned max precision integer is greater
+ * than or equal to an unsigned double-max precision integer
+ *
+ * `libj2_ju_ge_j2u(a, b)` implements `a >= *b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `a` is greater than or equal to `*b`, 0 otherwise
+ */
+inline int
+libj2_ju_ge_j2u(uintmax_t a, const struct libj2_j2u *b)
+{
+ return libj2_j2u_le_ju(b, a);
+}
+
+
+/**
+ * Check whether an unsigned max precision integer is
+ * equal to an unsigned double-max precision integer
+ *
+ * `libj2_ju_eq_j2u(a, b)` implements `a == *b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `a` is equal to `*b`, 0 otherwise
+ */
+inline int
+libj2_ju_eq_j2u(uintmax_t a, const struct libj2_j2u *b)
+{
+ return libj2_j2u_eq_ju(b, a);
+}
+
+
+/**
+ * Check whether an unsigned max precision integer is
+ * not equal to an unsigned double-max precision integer
+ *
+ * `libj2_ju_ne_j2u(a, b)` implements `a != *b`
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return 1 if `a` is not equal to `*b`, 0 otherwise
+ */
+inline int
+libj2_ju_ne_j2u(uintmax_t a, const struct libj2_j2u *b)
+{
+ return libj2_j2u_ne_ju(b, a);
+}
+
+
+/**
+ * Compare an unsigned max precision integer
+ * to an unsigned double-max precision integer
+ *
+ * `libj2_ju_cmp_j2u(a, b)` implements `a < *b ? -1 : a > *b ? +1 : 0`,
+ * or equivalently, the signum of `a - *b` where the signum is 0 for 0
+ *
+ * @param a The left-hand value
+ * @param b The right-hand value
+ * @return -1 if `a` is less than `*b`,
+ * +1 if `a` is greater than `*b`,
+ * 0 if `a` is equal to `*b`
+ */
+inline int
+libj2_ju_cmp_j2u(uintmax_t a, const struct libj2_j2u *b)
+{
+ return b->high ? -1 : a < b->low ? -1 : a > b->low;
+}
+
+
+
+
+
+/**
+ * Get the maximum of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_max_j2u_to_ju2(a, b, res)` implements
+ * `*res = *a > *b ? *a : *b`
+ *
+ * @param a One of the values
+ * @param b The other value
+ * @param res Output parameter for the maximum of `*a` and `*b`
+ */
+inline void
+libj2_j2u_max_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ *res = libj2_j2u_gt_j2u(a, b) ? *a : *b;
+}
+
+
+/**
+ * Get the maximum of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_max_j2u(a, b)` implements
+ * `*a = *a > *b ? *a : *b`
+ *
+ * @param a One of the values, and output parameter
+ * for the maximum of `*a` and `*b`
+ * @param b The other value
+ */
+inline void
+libj2_j2u_max_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ if (libj2_j2u_gt_j2u(b, a))
+ *a = *b;
+}
+
+
+/**
+ * Get the maximum of an unsigned double-max
+ * precision integer and an unsigned precision
+ * integer
+ *
+ * `libj2_j2u_max_ju(a, b)` implements
+ * `*a = *a > b ? *a : b`
+ *
+ * @param a One of the values, and output parameter
+ * for the maximum of `*a` and `b`
+ * @param b The other value
+ */
+inline void
+libj2_j2u_max_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ if (!a->high && a->low < b)
+ a->low = b;
+}
+
+
+/**
+ * Get the maximum of an unsigned double-max
+ * precision integer and an unsigned precision
+ * integer
+ *
+ * `libj2_j2u_max_ju_to_j2u(a, b, res)` implements
+ * `*res = *a > b ? *a : b`
+ *
+ * @param a One of the values
+ * @param b The other value
+ * @param res Output parameter for the maximum of `*a` and `b`
+ */
+inline void
+libj2_j2u_max_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ if (!a->high && a->low < b) {
+ res->high = 0;
+ res->low = b;
+ } else {
+ *res = *a;
+ }
+}
+
+
+/**
+ * Get the minimum of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_min_j2u_to_ju2(a, b, res)` implements
+ * `*res = *a < *b ? *a : *b`
+ *
+ * @param a One of the values
+ * @param b The other value
+ * @param res Output parameter for the minimum of `*a` and `*b`
+ */
+inline void
+libj2_j2u_min_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ *res = libj2_j2u_lt_j2u(a, b) ? *a : *b;
+}
+
+
+/**
+ * Get the minimum of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_min_j2u(a, b)` implements
+ * `*a = *a < *b ? *a : *b`
+ *
+ * @param a One of the values, and output parameter
+ * for the minimum of `*a` and `*b`
+ * @param b The other value
+ */
+inline void
+libj2_j2u_min_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ if (libj2_j2u_lt_j2u(b, a))
+ *a = *b;
+}
+
+
+/**
+ * Get the minimum of an unsigned double-max
+ * precision integer and an unsigned precision
+ * integer
+ *
+ * `libj2_j2u_min_ju(a, b)` implements
+ * `*a = *a < b ? *a : b`
+ *
+ * @param a One of the values, and output parameter
+ * for the minimum of `*a` and `b`
+ * @param b The other value
+ */
+inline void
+libj2_j2u_min_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ if (a->high || a->low > b) {
+ a->high = 0;
+ a->low = b;
+ }
+}
+
+
+/**
+ * Get the minimum of an unsigned double-max
+ * precision integer and an unsigned precision
+ * integer
+ *
+ * `libj2_j2u_min_ju_to_j2u(a, b, res)` implements
+ * `*res = *a < b ? *a : b`
+ *
+ * @param a One of the values
+ * @param b The other value
+ * @param res Output parameter for the minimum of `*a` and `b`
+ */
+inline void
+libj2_j2u_min_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ if (a->high || a->low > b) {
+ res->high = 0;
+ res->low = b;
+ } else {
+ *res = *a;
+ }
+}
+
+
+/**
+ * Get the maximum of a set of unsigned double-max
+ * precision integers
+ *
+ * @param a One of the values, and output parameter for
+ * the maximum of the values
+ * @param args `NULL` terminated list of additional values; each
+ * argument shall have the type `const struct libj2_j2u *`
+ */
+inline void
+libj2_vmax_j2u(struct libj2_j2u *a, va_list args)
+{
+ const struct libj2_j2u *b;
+ while ((b = va_arg(args, const struct libj2_j2u *)))
+ libj2_j2u_max_j2u(a, b);
+}
+
+
+/**
+ * Get the maximum of a set of unsigned double-max
+ * precision integers
+ *
+ * @param a One of the values, and output parameter for
+ * the maximum of the values
+ * @param ... `NULL` terminated list of additional values; each
+ * argument shall have the type `const struct libj2_j2u *`
+ */
+inline void
+libj2_max_j2u(struct libj2_j2u *a, ... /*, NULL */)
+{
+ va_list args;
+ va_start(args, a);
+ libj2_vmax_j2u(a, args);
+ va_end(args);
+}
+
+
+/**
+ * Get the maximum of a set of unsigned double-max
+ * precision integers
+ *
+ * @param a One of the values
+ * @param args `NULL` terminated list of additional values; each
+ * argument shall have the type `const struct libj2_j2u *`
+ * @return One of the `const struct libj2_j2u *` that as the
+ * maximum of the values of each argument
+ */
+inline const struct libj2_j2u *
+libj2_vmax_j2u_return(const struct libj2_j2u *a, va_list args)
+{
+ const struct libj2_j2u *b;
+ while ((b = va_arg(args, const struct libj2_j2u *)))
+ if (libj2_j2u_gt_j2u(b, a))
+ a = b;
+ return a;
+}
+
+
+/**
+ * Get the maximum of a set of unsigned double-max
+ * precision integers
+ *
+ * @param a One of the values
+ * @param ... `NULL` terminated list of additional values; each
+ * argument shall have the type `const struct libj2_j2u *`
+ * @return One of the `const struct libj2_j2u *` that as the
+ * maximum of the values of each argument
+ */
+inline const struct libj2_j2u *
+libj2_max_j2u_return(const struct libj2_j2u *a, ... /*, NULL */)
+{
+ va_list args;
+ va_start(args, a);
+ return libj2_vmax_j2u_return(a, args);
+ va_end(args);
+}
+
+
+/**
+ * Get the maximum of a set of unsigned double-max
+ * precision integers
+ *
+ * @param a One of the values
+ * @param args `NULL` terminated list of additional values, each
+ * argument shall have the type `const struct libj2_j2u *`,
+ * followed by a `struct libj2_j2u *` is used as the
+ * output parameter for the maximum of the values
+ */
+inline void
+libj2_vmax_j2u_to_j2u(const struct libj2_j2u *a, va_list args)
+{
+ struct libj2_j2u *res;
+ a = libj2_vmax_j2u_return(a, args);
+ res = va_arg(args, struct libj2_j2u *);
+ *res = *a;
+}
+
+
+/**
+ * Get the maximum of a set of unsigned double-max
+ * precision integers
+ *
+ * @param a One of the values
+ * @param ... `NULL` terminated list of additional values, each
+ * argument shall have the type `const struct libj2_j2u *`,
+ * followed by a `struct libj2_j2u *` is used as the
+ * output parameter for the maximum of the values
+ */
+inline void
+libj2_max_j2u_to_j2u(const struct libj2_j2u *a, ... /*, NULL, struct libj2_j2u *res */)
+{
+ va_list args;
+ va_start(args, a);
+ libj2_vmax_j2u_to_j2u(a, args);
+ va_end(args);
+}
+
+
+/**
+ * Get the minimum of a set of unsigned double-max
+ * precision integers
+ *
+ * @param a One of the values, and output parameter for
+ * the minimum of the values
+ * @param args `NULL` terminated list of additional values; each
+ * argument shall have the type `const struct libj2_j2u *`
+ */
+inline void
+libj2_vmin_j2u(struct libj2_j2u *a, va_list args)
+{
+ const struct libj2_j2u *b;
+ while ((b = va_arg(args, const struct libj2_j2u *)))
+ libj2_j2u_min_j2u(a, b);
+}
+
+
+/**
+ * Get the minimum of a set of unsigned double-max
+ * precision integers
+ *
+ * @param a One of the values, and output parameter for
+ * the minimum of the values
+ * @param ... `NULL` terminated list of additional values; each
+ * argument shall have the type `const struct libj2_j2u *`
+ */
+inline void
+libj2_min_j2u(struct libj2_j2u *a, ... /*, NULL */)
+{
+ va_list args;
+ va_start(args, a);
+ libj2_vmin_j2u(a, args);
+ va_end(args);
+}
+
+
+/**
+ * Get the minimum of a set of unsigned double-max
+ * precision integers
+ *
+ * @param a One of the values
+ * @param args `NULL` terminated list of additional values; each
+ * argument shall have the type `const struct libj2_j2u *`
+ * @return One of the `const struct libj2_j2u *` that as the
+ * minimum of the values of each argument
+ */
+inline const struct libj2_j2u *
+libj2_vmin_j2u_return(const struct libj2_j2u *a, va_list args)
+{
+ const struct libj2_j2u *b;
+ while ((b = va_arg(args, const struct libj2_j2u *)))
+ if (libj2_j2u_lt_j2u(b, a))
+ a = b;
+ return a;
+}
+
+
+/**
+ * Get the minimum of a set of unsigned double-max
+ * precision integers
+ *
+ * @param a One of the values
+ * @param ... `NULL` terminated list of additional values; each
+ * argument shall have the type `const struct libj2_j2u *`
+ * @return One of the `const struct libj2_j2u *` that as the
+ * minimum of the values of each argument
+ */
+inline const struct libj2_j2u *
+libj2_min_j2u_return(const struct libj2_j2u *a, ... /*, NULL */)
+{
+ va_list args;
+ va_start(args, a);
+ return libj2_vmin_j2u_return(a, args);
+ va_end(args);
+}
+
+
+/**
+ * Get the minimum of a set of unsigned double-max
+ * precision integers
+ *
+ * @param a One of the values
+ * @param args `NULL` terminated list of additional values, each
+ * argument shall have the type `const struct libj2_j2u *`,
+ * followed by a `struct libj2_j2u *` is used as the
+ * output parameter for the minimum of the values
+ */
+inline void
+libj2_vmin_j2u_to_j2u(const struct libj2_j2u *a, va_list args)
+{
+ struct libj2_j2u *res;
+ a = libj2_vmin_j2u_return(a, args);
+ res = va_arg(args, struct libj2_j2u *);
+ *res = *a;
+}
+
+
+/**
+ * Get the minimum of a set of unsigned double-max
+ * precision integers
+ *
+ * @param a One of the values
+ * @param ... `NULL` terminated list of additional values, each
+ * argument shall have the type `const struct libj2_j2u *`,
+ * followed by a `struct libj2_j2u *` is used as the
+ * output parameter for the minimum of the values
+ */
+inline void
+libj2_min_j2u_to_j2u(const struct libj2_j2u *a, ... /*, NULL, struct libj2_j2u *res */)
+{
+ va_list args;
+ va_start(args, a);
+ libj2_vmin_j2u_to_j2u(a, args);
+ va_end(args);
+}
diff --git a/libj2_j2u_add_j2u.c b/libj2_j2u_add_j2u.c
new file mode 100644
index 0000000..bd783a0
--- /dev/null
+++ b/libj2_j2u_add_j2u.c
@@ -0,0 +1,201 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_add_j2u(struct libj2_j2u *a, const struct libj2_j2u *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_j2u a, b, r, a_saved, b_saved, expected;
+
+ a_saved = (struct libj2_j2u){.high = a_high, .low = a_low};
+ b_saved = (struct libj2_j2u){.high = b_high, .low = b_low};
+ expected = (struct libj2_j2u){.high = r_high, .low = r_low};
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2u_add_j2u(&a, &b);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ b = b_saved;
+ libj2_j2u_add_j2u_to_j2u(&a, &b, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2u_add_j2u_to_j2u(&a, &b, &a);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2u_add_j2u_to_j2u(&a, &b, &b);
+ EXPECT(libj2_j2u_eq_j2u(&b, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2u_add_j2u_overflow(&a, &b) == r_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, &r) == r_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, &a) == r_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, &b) == r_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&b, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+}
+
+
+static void
+check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low)
+{
+ uintmax_t r_high = 0, r_low = 0, carry = 0;
+ int r_overflow;
+ 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; i++) {
+ carry += (a_high >> i) & 1U;
+ carry += (b_high >> i) & 1U;
+ r_high |= (carry & 1U) << i;
+ carry >>= 1;
+ }
+
+ r_overflow = (int)carry;
+ 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_j2u 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 = !!(high >> (LIBJ2_JU_BIT - 1U));
+
+ a_saved = (struct libj2_j2u){.high = high, .low = low};
+ expected = (struct libj2_j2u){.high = expected_high, .low = expected_low};
+
+ a = a_saved;
+ b = a_saved;
+ libj2_j2u_add_j2u(&a, &b);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+
+ a = a_saved;
+ libj2_j2u_add_j2u(&a, &a);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ libj2_j2u_add_j2u_to_j2u(&a, &a, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ a = a_saved;
+ libj2_j2u_add_j2u_to_j2u(&a, &a, &a);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ EXPECT(libj2_j2u_add_j2u_overflow(&a, &a) == expected_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ EXPECT(libj2_j2u_add_j2u_to_j2u_overflow(&a, &a, &r) == expected_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ a = a_saved;
+ EXPECT(libj2_j2u_add_j2u_to_j2u_overflow(&a, &a, &a) == expected_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+}
+
+
+int
+main(void)
+{
+ unsigned i;
+
+ srand((unsigned)time(NULL));
+
+ 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, UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX - 1U, 1);
+
+ for (i = 0; i < 256; i++)
+ check(random_ju(), random_ju(), random_ju(), random_ju());
+
+ check_double(0, 0);
+ check_double(0, UINTMAX_MAX);
+ check_double(UINTMAX_MAX, 0);
+ check_double(UINTMAX_MAX, UINTMAX_MAX);
+ 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, random_ju());
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_add_j2u_overflow.c b/libj2_j2u_add_j2u_overflow.c
new file mode 100644
index 0000000..cab3cf6
--- /dev/null
+++ b/libj2_j2u_add_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_add_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_j2u.c */
+
+#endif
diff --git a/libj2_j2u_add_j2u_to_j2u.c b/libj2_j2u_add_j2u_to_j2u.c
new file mode 100644
index 0000000..ebd96da
--- /dev/null
+++ b/libj2_j2u_add_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_add_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_j2u.c */
+
+#endif
diff --git a/libj2_j2u_add_j2u_to_j2u_overflow.c b/libj2_j2u_add_j2u_to_j2u_overflow.c
new file mode 100644
index 0000000..8a152ff
--- /dev/null
+++ b/libj2_j2u_add_j2u_to_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_add_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_j2u.c */
+
+#endif
diff --git a/libj2_j2u_add_ju.c b/libj2_j2u_add_ju.c
new file mode 100644
index 0000000..8592662
--- /dev/null
+++ b/libj2_j2u_add_ju.c
@@ -0,0 +1,301 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_add_ju(struct libj2_j2u *a, uintmax_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
+check_zero_low(uintmax_t high, uintmax_t low)
+{
+ struct libj2_j2u a, r;
+
+ a = (struct libj2_j2u){.high = high, .low = 0};
+ libj2_j2u_add_ju(&a, low);
+ EXPECT(a.high == high);
+ EXPECT(a.low == low);
+
+ a = (struct libj2_j2u){.high = high, .low = 0};
+ EXPECT(libj2_j2u_add_ju_overflow(&a, low) == 0);
+ EXPECT(a.high == high);
+ EXPECT(a.low == low);
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = high, .low = 0};
+ libj2_j2u_add_ju_to_j2u(&a, low, &r);
+ EXPECT(a.high == high);
+ EXPECT(a.low == 0);
+ EXPECT(r.high == high);
+ EXPECT(r.low == low);
+
+ a = (struct libj2_j2u){.high = high, .low = 0};
+ libj2_j2u_add_ju_to_j2u(&a, low, &a);
+ EXPECT(a.high == high);
+ EXPECT(a.low == low);
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = high, .low = 0};
+ EXPECT(libj2_j2u_add_ju_to_j2u_overflow(&a, low, &r) == 0);
+ EXPECT(a.high == high);
+ EXPECT(a.low == 0);
+ EXPECT(r.high == high);
+ EXPECT(r.low == low);
+
+ a = (struct libj2_j2u){.high = high, .low = 0};
+ EXPECT(libj2_j2u_add_ju_to_j2u_overflow(&a, low, &a) == 0);
+ EXPECT(a.high == high);
+ EXPECT(a.low == low);
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = high, .low = 0};
+ libj2_ju_add_j2u_to_j2u(low, &a, &r);
+ EXPECT(a.high == high);
+ EXPECT(a.low == 0);
+ EXPECT(r.high == high);
+ EXPECT(r.low == low);
+
+ a = (struct libj2_j2u){.high = high, .low = 0};
+ libj2_ju_add_j2u_to_j2u(low, &a, &a);
+ EXPECT(a.high == high);
+ EXPECT(a.low == low);
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = high, .low = 0};
+ EXPECT(libj2_ju_add_j2u_to_j2u_overflow(low, &a, &r) == 0);
+ EXPECT(a.high == high);
+ EXPECT(a.low == 0);
+ EXPECT(r.high == high);
+ EXPECT(r.low == low);
+
+ a = (struct libj2_j2u){.high = high, .low = 0};
+ EXPECT(libj2_ju_add_j2u_to_j2u_overflow(low, &a, &a) == 0);
+ EXPECT(a.high == high);
+ EXPECT(a.low == low);
+}
+
+
+static void
+check_max_low(uintmax_t high, uintmax_t low)
+{
+ struct libj2_j2u a, r;
+ uintmax_t expected_high = high + (uintmax_t)!!low;
+ uintmax_t expected_low = low - 1U;
+ int expected_overflow = high == UINTMAX_MAX && low;
+
+ a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ libj2_j2u_add_ju(&a, low);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+ a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ EXPECT(libj2_j2u_add_ju_overflow(&a, low) == expected_overflow);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ libj2_j2u_add_ju_to_j2u(&a, low, &r);
+ EXPECT(a.high == high);
+ EXPECT(a.low == UINTMAX_MAX);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+
+ a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ libj2_j2u_add_ju_to_j2u(&a, low, &a);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ EXPECT(libj2_j2u_add_ju_to_j2u_overflow(&a, low, &r) == expected_overflow);
+ EXPECT(a.high == high);
+ EXPECT(a.low == UINTMAX_MAX);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+
+ a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ EXPECT(libj2_j2u_add_ju_to_j2u_overflow(&a, low, &a) == expected_overflow);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ libj2_ju_add_j2u_to_j2u(low, &a, &r);
+ EXPECT(a.high == high);
+ EXPECT(a.low == UINTMAX_MAX);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+
+ a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ libj2_ju_add_j2u_to_j2u(low, &a, &a);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ EXPECT(libj2_ju_add_j2u_to_j2u_overflow(low, &a, &r) == expected_overflow);
+ EXPECT(a.high == high);
+ EXPECT(a.low == UINTMAX_MAX);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+
+ a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ EXPECT(libj2_ju_add_j2u_to_j2u_overflow(low, &a, &a) == expected_overflow);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+}
+
+
+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 carry = 0;
+ unsigned i;
+
+ 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; i++) {
+ carry += (a_high >> i) & 1U;
+ carry += (b_high >> i) & 1U;
+ EXPECT((carry & 1U) == ((r_high >> i) & 1U));
+ carry >>= 1;
+ }
+
+ EXPECT((uintmax_t)r_overflow == carry);
+}
+
+
+static void
+check(uintmax_t a_high, uintmax_t a_low, uintmax_t b)
+{
+ struct libj2_j2u a, r;
+ uintmax_t expected_high = a_high + (uintmax_t)(a_low > UINTMAX_MAX - b);
+ uintmax_t expected_low = a_low + b;
+ int expected_overflow = a_high && !expected_high;
+
+ self_check(a_high, a_low, 0, b, expected_high, expected_low, expected_overflow);
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_add_ju(&a, b);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_j2u_add_ju_overflow(&a, b) == expected_overflow);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_add_ju_to_j2u(&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_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_add_ju_to_j2u(&a, b, &a);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_j2u_add_ju_to_j2u_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_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_j2u_add_ju_to_j2u_overflow(&a, b, &a) == expected_overflow);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_ju_add_j2u_to_j2u(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_j2u){.high = a_high, .low = a_low};
+ libj2_ju_add_j2u_to_j2u(b, &a, &a);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_ju_add_j2u_to_j2u_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_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_ju_add_j2u_to_j2u_overflow(b, &a, &a) == expected_overflow);
+ EXPECT(a.high == expected_high);
+ EXPECT(a.low == expected_low);
+}
+
+
+int
+main(void)
+{
+ unsigned i;
+
+ srand((unsigned)time(NULL));
+
+ check_zero_low(0, 0);
+ check_zero_low(0, UINTMAX_MAX);
+ check_zero_low(UINTMAX_MAX, 0);
+ check_zero_low(UINTMAX_MAX, UINTMAX_MAX);
+ for (i = 0; i < 256; i++) {
+ check_zero_low(0, random_ju());
+ check_zero_low(random_ju(), 0);
+ check_zero_low(random_ju(), random_ju());
+ check_zero_low(random_ju(), UINTMAX_MAX);
+ check_zero_low(UINTMAX_MAX, random_ju());
+ }
+
+ check_max_low(0, 0);
+ check_max_low(0, UINTMAX_MAX);
+ check_max_low(UINTMAX_MAX, 0);
+ check_max_low(UINTMAX_MAX, UINTMAX_MAX);
+ for (i = 0; i < 256; i++) {
+ check_max_low(0, random_ju());
+ check_max_low(random_ju(), 0);
+ check_max_low(random_ju(), 1);
+ check_max_low(random_ju(), random_ju());
+ check_max_low(random_ju(), UINTMAX_MAX);
+ check_max_low(UINTMAX_MAX, random_ju());
+ }
+
+ for (i = 0; i < 256; i++)
+ check(random_ju(), random_ju(), random_ju());
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_add_ju_overflow.c b/libj2_j2u_add_ju_overflow.c
new file mode 100644
index 0000000..9c01dd2
--- /dev/null
+++ b/libj2_j2u_add_ju_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_add_ju_overflow(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_ju.c */
+
+#endif
diff --git a/libj2_j2u_add_ju_to_j2u.c b/libj2_j2u_add_ju_to_j2u.c
new file mode 100644
index 0000000..348cc2c
--- /dev/null
+++ b/libj2_j2u_add_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_add_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_ju.c */
+
+#endif
diff --git a/libj2_j2u_add_ju_to_j2u_overflow.c b/libj2_j2u_add_ju_to_j2u_overflow.c
new file mode 100644
index 0000000..d93e76d
--- /dev/null
+++ b/libj2_j2u_add_ju_to_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_add_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_ju.c */
+
+#endif
diff --git a/libj2_j2u_and_j2u.c b/libj2_j2u_and_j2u.c
new file mode 100644
index 0000000..4ae1347
--- /dev/null
+++ b/libj2_j2u_and_j2u.c
@@ -0,0 +1,140 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_and_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+static void
+check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected)
+{
+ struct libj2_j2u a_saved = *a, b_saved = *b, r;
+
+ r = *a;
+ libj2_j2u_and_j2u(&r, b);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_and_j2u(&r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &a_saved));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_and_j2u_to_j2u(a, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_and_j2u_to_j2u(&r, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_j2u_and_j2u_to_j2u(a, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_and_j2u_to_j2u(a, a, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, &a_saved));
+
+ r = *a;
+ libj2_j2u_and_j2u_to_j2u(a, a, a);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+
+ if (a->high == 0U) {
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_and_j2u_to_j2u(a->low, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_ju_and_j2u_to_j2u(a->low, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+
+ if (b->high == 0U) {
+ r = *a;
+ libj2_j2u_and_ju(&r, b->low);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_and_ju_to_j2u(a, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_and_ju_to_j2u(&r, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+}
+
+int
+main(void)
+{
+ unsigned truthtable[] = {0, 0, 0, 1};
+ unsigned i, j;
+ uintmax_t a_bit, b_bit, r_bit;
+ struct libj2_j2u a, b, r, a_saved;
+
+ srand((unsigned)time(NULL));
+
+ for (j = 0; j < 128; j++) {
+ a.high = a.low = 0;
+ b.high = b.low = 0;
+ r.high = r.low = 0;
+ for (i = 0; i < LIBJ2_J2U_BIT; i++) {
+ a_bit = (uintmax_t)(rand() < rand());
+ b_bit = (uintmax_t)(rand() < rand());
+ r_bit = truthtable[a_bit * 2U + b_bit];
+ if (i < LIBJ2_JU_BIT) {
+ a.low |= a_bit << i;
+ b.low |= b_bit << i;
+ r.low |= r_bit << i;
+ } else {
+ a.high |= a_bit << (i - LIBJ2_JU_BIT);
+ b.high |= b_bit << (i - LIBJ2_JU_BIT);
+ r.high |= r_bit << (i - LIBJ2_JU_BIT);
+ }
+ }
+
+ check(&a, &b, &r);
+
+ a_saved = a;
+ a.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[(b.high >> i) & 1U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+ a = a_saved;
+
+ b.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 2U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+
+ r.high = 0U;
+ r.low = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 3U];
+ r.high |= r_bit << i;
+ r_bit = truthtable[((a.low >> i) & 1U) * 3U];
+ r.low |= r_bit << i;
+ }
+ check(&a, &a, &r);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_and_j2u_to_j2u.c b/libj2_j2u_and_j2u_to_j2u.c
new file mode 100644
index 0000000..80b33c5
--- /dev/null
+++ b/libj2_j2u_and_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_and_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_and_j2u.c */
+
+#endif
diff --git a/libj2_j2u_and_ju.c b/libj2_j2u_and_ju.c
new file mode 100644
index 0000000..9d947f5
--- /dev/null
+++ b/libj2_j2u_and_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_and_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_and_j2u.c */
+
+#endif
diff --git a/libj2_j2u_and_ju_to_j2u.c b/libj2_j2u_and_ju_to_j2u.c
new file mode 100644
index 0000000..862fbaa
--- /dev/null
+++ b/libj2_j2u_and_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_and_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_and_j2u.c */
+
+#endif
diff --git a/libj2_j2u_cmp_j2u.c b/libj2_j2u_cmp_j2u.c
new file mode 100644
index 0000000..a5072d8
--- /dev/null
+++ b/libj2_j2u_cmp_j2u.c
@@ -0,0 +1,200 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_cmp_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+static int
+cmp(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low)
+{
+ struct libj2_j2u a, b, c;
+ int ret;
+
+ a.high = a_high;
+ a.low = a_low;
+ b.high = b_high;
+ b.low = b_low;
+
+ ret = libj2_j2u_cmp_j2u(&a, &b);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(b.high == b_high);
+ EXPECT(b.low == b_low);
+
+ EXPECT(libj2_j2u_cmp_j2u(&b, &a) == (ret ? -ret : 0));
+
+ EXPECT(libj2_j2u_lt_j2u(&a, &b) == (ret < 0));
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(b.high == b_high);
+ EXPECT(b.low == b_low);
+
+ EXPECT(libj2_j2u_le_j2u(&a, &b) == (ret <= 0));
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(b.high == b_high);
+ EXPECT(b.low == b_low);
+
+ EXPECT(libj2_j2u_gt_j2u(&a, &b) == (ret > 0));
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(b.high == b_high);
+ EXPECT(b.low == b_low);
+
+ EXPECT(libj2_j2u_ge_j2u(&a, &b) == (ret >= 0));
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(b.high == b_high);
+ EXPECT(b.low == b_low);
+
+ EXPECT(libj2_j2u_eq_j2u(&a, &b) == (ret == 0));
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(b.high == b_high);
+ EXPECT(b.low == b_low);
+
+ EXPECT(libj2_j2u_ne_j2u(&a, &b) == (ret != 0));
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(b.high == b_high);
+ EXPECT(b.low == b_low);
+
+ EXPECT(libj2_j2u_lt_j2u(&b, &a) == (ret > 0));
+ EXPECT(libj2_j2u_le_j2u(&b, &a) == (ret >= 0));
+ EXPECT(libj2_j2u_gt_j2u(&b, &a) == (ret < 0));
+ EXPECT(libj2_j2u_ge_j2u(&b, &a) == (ret <= 0));
+ EXPECT(libj2_j2u_eq_j2u(&b, &a) == (ret == 0));
+ EXPECT(libj2_j2u_ne_j2u(&b, &a) == (ret != 0));
+
+ c = (struct libj2_j2u){111, 222};
+ libj2_j2u_max_j2u_to_j2u(&a, &b, &c);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(b.high == b_high);
+ EXPECT(b.low == b_low);
+ if (ret >= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1);
+ if (ret <= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1);
+
+ c = (struct libj2_j2u){111, 222};
+ libj2_j2u_max_j2u_to_j2u(&b, &a, &c);
+ if (ret >= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1);
+ if (ret <= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1);
+
+ c = a;
+ libj2_j2u_max_j2u(&c, &b);
+ EXPECT(b.high == b_high);
+ EXPECT(b.low == b_low);
+ if (ret >= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1);
+ if (ret <= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1);
+
+ c = b;
+ libj2_j2u_max_j2u(&c, &a);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ if (ret >= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1);
+ if (ret <= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1);
+
+ c = (struct libj2_j2u){111, 222};
+ libj2_j2u_min_j2u_to_j2u(&a, &b, &c);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(b.high == b_high);
+ EXPECT(b.low == b_low);
+ if (ret <= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1);
+ if (ret >= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1);
+
+ c = (struct libj2_j2u){111, 222};
+ libj2_j2u_min_j2u_to_j2u(&b, &a, &c);
+ if (ret <= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1);
+ if (ret >= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1);
+
+ c = a;
+ libj2_j2u_min_j2u(&c, &b);
+ EXPECT(b.high == b_high);
+ EXPECT(b.low == b_low);
+ if (ret <= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1);
+ if (ret >= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1);
+
+ c = b;
+ libj2_j2u_min_j2u(&c, &a);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ if (ret <= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1);
+ if (ret >= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1);
+
+ return ret;
+}
+
+int
+main(void)
+{
+ const uintmax_t max = UINTMAX_MAX;
+
+ EXPECT(cmp(0, 0, 0, 0) == 0);
+ EXPECT(cmp(0, 0, 0, 1) == -1);
+ EXPECT(cmp(0, 0, 1, 0) == -1);
+ EXPECT(cmp(0, 0, 1, 1) == -1);
+ EXPECT(cmp(0, 0, 0, max) == -1);
+ EXPECT(cmp(0, 0, max, 0) == -1);
+ EXPECT(cmp(0, 0, max, max) == -1);
+ EXPECT(cmp(0, 0, max, max - 1) == -1);
+
+ EXPECT(cmp(0, 1, 0, 1) == 0);
+ EXPECT(cmp(0, 1, 1, 0) == -1);
+ EXPECT(cmp(0, 1, 1, 1) == -1);
+ EXPECT(cmp(0, 1, 0, max) == -1);
+ EXPECT(cmp(0, 1, max, 0) == -1);
+ EXPECT(cmp(0, 1, max, max) == -1);
+ EXPECT(cmp(0, 1, max, max - 1) == -1);
+
+ EXPECT(cmp(1, 0, 1, 0) == 0);
+ EXPECT(cmp(1, 0, 1, 1) == -1);
+ EXPECT(cmp(1, 0, 0, max) == +1);
+ EXPECT(cmp(1, 0, max, 0) == -1);
+ EXPECT(cmp(1, 0, max, max) == -1);
+ EXPECT(cmp(1, 0, max, max - 1) == -1);
+
+ EXPECT(cmp(1, 1, 1, 1) == 0);
+ EXPECT(cmp(1, 1, 0, max) == +1);
+ EXPECT(cmp(1, 1, max, 0) == -1);
+ EXPECT(cmp(1, 1, max, max) == -1);
+ EXPECT(cmp(1, 1, max, max - 1) == -1);
+
+ EXPECT(cmp(0, max, 0, max) == 0);
+ EXPECT(cmp(0, max, max, 0) == -1);
+ EXPECT(cmp(0, max, max, max) == -1);
+ EXPECT(cmp(0, max, max, max - 1) == -1);
+
+ EXPECT(cmp(max, 0, max, 0) == 0);
+ EXPECT(cmp(max, 0, max, max) == -1);
+ EXPECT(cmp(max, 0, max, max - 1) == -1);
+
+ EXPECT(cmp(max, max, max, max) == 0);
+ EXPECT(cmp(max, max, max, max - 1) == +1);
+
+ EXPECT(cmp(max, max - 1, max, max - 1) == 0);
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_cmp_ju.c b/libj2_j2u_cmp_ju.c
new file mode 100644
index 0000000..ba45409
--- /dev/null
+++ b/libj2_j2u_cmp_ju.c
@@ -0,0 +1,145 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_cmp_ju(const struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+static int
+cmp(uintmax_t a_high, uintmax_t a_low, uintmax_t b)
+{
+ struct libj2_j2u a, c;
+ int ret;
+
+ a.high = a_high;
+ a.low = a_low;
+
+ ret = libj2_j2u_cmp_ju(&a, b);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+
+ EXPECT(libj2_ju_cmp_j2u(b, &a) == (ret ? -ret : 0));
+
+ EXPECT(libj2_j2u_lt_ju(&a, b) == (ret < 0));
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+
+ EXPECT(libj2_j2u_le_ju(&a, b) == (ret <= 0));
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+
+ EXPECT(libj2_j2u_gt_ju(&a, b) == (ret > 0));
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+
+ EXPECT(libj2_j2u_ge_ju(&a, b) == (ret >= 0));
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+
+ EXPECT(libj2_j2u_eq_ju(&a, b) == (ret == 0));
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+
+ EXPECT(libj2_j2u_ne_ju(&a, b) == (ret != 0));
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+
+ EXPECT(libj2_ju_lt_j2u(b, &a) == (ret > 0));
+ EXPECT(libj2_ju_le_j2u(b, &a) == (ret >= 0));
+ EXPECT(libj2_ju_gt_j2u(b, &a) == (ret < 0));
+ EXPECT(libj2_ju_ge_j2u(b, &a) == (ret <= 0));
+ EXPECT(libj2_ju_eq_j2u(b, &a) == (ret == 0));
+ EXPECT(libj2_ju_ne_j2u(b, &a) == (ret != 0));
+
+ c = (struct libj2_j2u){111, 222};
+ libj2_j2u_max_ju_to_j2u(&a, b, &c);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ if (ret >= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1);
+ if (ret <= 0)
+ EXPECT(libj2_j2u_eq_ju(&c, b) == 1);
+
+ c = a;
+ libj2_j2u_max_ju(&c, b);
+ if (ret >= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1);
+ if (ret <= 0)
+ EXPECT(libj2_j2u_eq_ju(&c, b) == 1);
+
+ c = (struct libj2_j2u){111, 222};
+ libj2_j2u_min_ju_to_j2u(&a, b, &c);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ if (ret <= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1);
+ if (ret >= 0)
+ EXPECT(libj2_j2u_eq_ju(&c, b) == 1);
+
+ c = a;
+ libj2_j2u_min_ju(&c, b);
+ if (ret <= 0)
+ EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1);
+ if (ret >= 0)
+ EXPECT(libj2_j2u_eq_ju(&c, b) == 1);
+
+ return ret;
+}
+
+int
+main(void)
+{
+ const uintmax_t max = UINTMAX_MAX;
+
+ EXPECT(cmp(0, 0, 0) == 0);
+ EXPECT(cmp(0, 1, 0) == +1);
+ EXPECT(cmp(1, 0, 0) == +1);
+ EXPECT(cmp(1, 1, 0) == +1);
+ EXPECT(cmp(0, max, 0) == +1);
+ EXPECT(cmp(max, 0, 0) == +1);
+ EXPECT(cmp(max, max, 0) == +1);
+ EXPECT(cmp(max, max - 1, 0) == +1);
+
+ EXPECT(cmp(0, 0, 1) == -1);
+ EXPECT(cmp(0, 1, 1) == 0);
+ EXPECT(cmp(1, 0, 1) == +1);
+ EXPECT(cmp(1, 1, 1) == +1);
+ EXPECT(cmp(0, max, 1) == +1);
+ EXPECT(cmp(max, 0, 1) == +1);
+ EXPECT(cmp(max, max, 1) == +1);
+ EXPECT(cmp(max, max - 1, 1) == +1);
+
+ EXPECT(cmp(0, 0, 2) == -1);
+ EXPECT(cmp(0, 1, 2) == -1);
+ EXPECT(cmp(1, 0, 2) == +1);
+ EXPECT(cmp(1, 1, 2) == +1);
+ EXPECT(cmp(0, max, 2) == +1);
+ EXPECT(cmp(max, 0, 2) == +1);
+ EXPECT(cmp(max, max, 2) == +1);
+ EXPECT(cmp(max, max - 1, 2) == +1);
+
+ EXPECT(cmp(0, 0, max) == -1);
+ EXPECT(cmp(0, 1, max) == -1);
+ EXPECT(cmp(1, 0, max) == +1);
+ EXPECT(cmp(1, 1, max) == +1);
+ EXPECT(cmp(0, max, max) == 0);
+ EXPECT(cmp(max, 0, max) == +1);
+ EXPECT(cmp(max, max, max) == +1);
+ EXPECT(cmp(max, max - 1, max) == +1);
+
+ EXPECT(cmp(0, 0, max - 1) == -1);
+ EXPECT(cmp(0, 1, max - 1) == -1);
+ EXPECT(cmp(1, 0, max - 1) == +1);
+ EXPECT(cmp(1, 1, max - 1) == +1);
+ EXPECT(cmp(0, max, max - 1) == +1);
+ EXPECT(cmp(max, 0, max - 1) == +1);
+ EXPECT(cmp(max, max, max - 1) == +1);
+ EXPECT(cmp(max, max - 1, max - 1) == +1);
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_div_j2u.c b/libj2_j2u_div_j2u.c
new file mode 100644
index 0000000..fdd84bd
--- /dev/null
+++ b/libj2_j2u_div_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_div_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_div_j2u_return.c b/libj2_j2u_div_j2u_return.c
new file mode 100644
index 0000000..9519796
--- /dev/null
+++ b/libj2_j2u_div_j2u_return.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline uintmax_t libj2_j2u_div_j2u_return(const struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_div_j2u_to_j2u.c b/libj2_j2u_div_j2u_to_j2u.c
new file mode 100644
index 0000000..dee0640
--- /dev/null
+++ b/libj2_j2u_div_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_div_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_div_ju.c b/libj2_j2u_div_ju.c
new file mode 100644
index 0000000..732efad
--- /dev/null
+++ b/libj2_j2u_div_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_div_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_div_ju_return.c b/libj2_j2u_div_ju_return.c
new file mode 100644
index 0000000..bcaac5c
--- /dev/null
+++ b/libj2_j2u_div_ju_return.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline uintmax_t libj2_j2u_div_ju_return(const struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_div_ju_to_j2u.c b/libj2_j2u_div_ju_to_j2u.c
new file mode 100644
index 0000000..65dabfb
--- /dev/null
+++ b/libj2_j2u_div_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_div_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_divmod_j2u.c b/libj2_j2u_divmod_j2u.c
new file mode 100644
index 0000000..70dbb2a
--- /dev/null
+++ b/libj2_j2u_divmod_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline uintmax_t libj2_j2u_divmod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_divmod_j2u_to_j2u.c b/libj2_j2u_divmod_j2u_to_j2u.c
new file mode 100644
index 0000000..3c5e756
--- /dev/null
+++ b/libj2_j2u_divmod_j2u_to_j2u.c
@@ -0,0 +1,389 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_divmod_j2u_to_j2u(struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *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_j2u *a, const struct libj2_j2u *b,
+ const struct libj2_j2u *q, const struct libj2_j2u *r)
+{
+ struct libj2_j2u v;
+ libj2_j2u_mul_j2u_to_j2u(q, b, &v);
+ libj2_j2u_add_j2u(&v, r);
+ EXPECT(libj2_j2u_eq_j2u(&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_j2u *a, const struct libj2_j2u *b,
+ const struct libj2_j2u *expected_q, const struct libj2_j2u *expected_r)
+{
+ struct libj2_j2u a_saved = *a, b_saved = *b, q, r, eq, er;
+
+ EXPECT(!libj2_j2u_is_zero(b));
+
+ r = (struct libj2_j2u){111, 222};
+ q = (struct libj2_j2u){333, 444};
+ libj2_j2u_divmod_j2u_to_j2u_j2u(a, b, &q, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ if (expected_q) {
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ } else {
+ eq = q;
+ expected_q = &eq;
+ }
+ if (expected_r) {
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+ } else {
+ er = r;
+ expected_r = &er;
+ }
+
+ validate_result(a, b, expected_q, expected_r);
+
+ r = (struct libj2_j2u){111, 222};
+ q = *a;
+ libj2_j2u_divmod_j2u_to_j2u_j2u(&q, b, &q, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2u){333, 444};
+ libj2_j2u_divmod_j2u_to_j2u_j2u(&r, b, &q, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = (struct libj2_j2u){111, 222};
+ q = *b;
+ libj2_j2u_divmod_j2u_to_j2u_j2u(a, &q, &q, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *b;
+ q = (struct libj2_j2u){333, 444};
+ libj2_j2u_divmod_j2u_to_j2u_j2u(a, &r, &q, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *b;
+ q = *a;
+ libj2_j2u_divmod_j2u_to_j2u_j2u(&q, &r, &q, &r);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ q = *b;
+ libj2_j2u_divmod_j2u_to_j2u_j2u(&r, &q, &q, &r);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ q = (struct libj2_j2u){333, 444};
+ libj2_j2u_div_j2u_to_j2u(a, b, &q);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+
+ q = *a;
+ libj2_j2u_div_j2u_to_j2u(&q, b, &q);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+
+ q = *b;
+ libj2_j2u_div_j2u_to_j2u(a, &q, &q);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_mod_j2u_to_j2u(a, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ libj2_j2u_mod_j2u_to_j2u(&r, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *b;
+ libj2_j2u_mod_j2u_to_j2u(a, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2u){333, 444};
+ libj2_j2u_divmod_j2u_to_j2u(&r, b, &q);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ q = *b;
+ libj2_j2u_divmod_j2u_to_j2u(&r, &q, &q);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ q = *a;
+ libj2_j2u_div_j2u(&q, b);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+
+ r = *a;
+ libj2_j2u_mod_j2u(&r, b);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *b;
+ q = (struct libj2_j2u){333, 444};
+ libj2_j2u_rdivmod_j2u_to_j2u(&r, a, &q);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *b;
+ q = *a;
+ libj2_j2u_rdivmod_j2u_to_j2u(&r, &q, &q);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ q = *b;
+ libj2_j2u_rdiv_j2u(&q, a);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+
+ r = *b;
+ libj2_j2u_rmod_j2u(&r, a);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ EXPECT(libj2_j2u_divmod_j2u(&r, b) == expected_q->low);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ EXPECT(libj2_j2u_div_j2u_return(a, b) == expected_q->low);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+
+ if (!b->high) {
+ r = (struct libj2_j2u){111, 222};
+ q = (struct libj2_j2u){333, 444};
+ libj2_j2u_divmod_ju_to_j2u_j2u(a, b->low, &q, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = (struct libj2_j2u){111, 222};
+ q = *a;
+ libj2_j2u_divmod_ju_to_j2u_j2u(&q, b->low, &q, &r);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2u){333, 444};
+ libj2_j2u_divmod_ju_to_j2u_j2u(&r, b->low, &q, &r);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ q = (struct libj2_j2u){333, 444};
+ libj2_j2u_div_ju_to_j2u(a, b->low, &q);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+
+ q = *a;
+ libj2_j2u_div_ju_to_j2u(&q, b->low, &q);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_mod_ju_to_j2u(a, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ libj2_j2u_mod_ju_to_j2u(&r, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2u){333, 444};
+ libj2_j2u_divmod_ju_to_j2u(&r, b->low, &q);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ q = *a;
+ libj2_j2u_div_ju(&q, b->low);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+
+ r = *a;
+ libj2_j2u_mod_ju(&r, b->low);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *b;
+ EXPECT(libj2_j2u_rdivmod_j2u(&r, a) == expected_q->low);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ EXPECT(libj2_j2u_divmod_ju(&r, b->low) == expected_q->low);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ EXPECT(libj2_j2u_div_ju_return(a, b->low) == expected_q->low);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ }
+
+ if (a == b) {
+ r = (struct libj2_j2u){111, 222};
+ q = *a;
+ libj2_j2u_divmod_j2u_to_j2u_j2u(&q, &q, &q, &r);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2u){333, 444};
+ libj2_j2u_divmod_j2u_to_j2u_j2u(&r, &r, &q, &r);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ q = *a;
+ libj2_j2u_div_j2u_to_j2u(&q, &q, &q);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+
+ r = *a;
+ libj2_j2u_mod_j2u_to_j2u(&r, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2u){333, 444};
+ libj2_j2u_divmod_j2u_to_j2u(&r, &r, &q);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ q = *a;
+ libj2_j2u_div_j2u(&q, &q);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+
+ r = *a;
+ libj2_j2u_mod_j2u(&r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ q = (struct libj2_j2u){333, 444};
+ libj2_j2u_rdivmod_j2u_to_j2u(&r, &r, &q);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ q = *a;
+ libj2_j2u_rdiv_j2u(&q, &q);
+ EXPECT(libj2_j2u_eq_j2u(&q, expected_q));
+
+ r = *a;
+ libj2_j2u_rmod_j2u(&r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+
+ r = *a;
+ EXPECT(libj2_j2u_divmod_j2u(&r, &r) == expected_q->low);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected_r));
+ }
+}
+
+
+static void
+check(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ struct libj2_j2u 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_j2u a = {0, 0}, b = {0, 0}, q = {0, 0}, r = {0, 0};
+ struct libj2_j2u zero = {0, 0}, one = {0, 0}, two = {0, 0};
+ unsigned i;
+
+ srand((unsigned)time(NULL));
+
+ one.low = 1;
+ two.low = 2;
+
+ 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(0x94385c048097d350);
+ b.low = UINTMAX_C(0x9212734e33d9df1e);
+ 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_j2u_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);
+ check_manual(&a, &two, &b, (a.low & 1U) ? &one : &zero);
+ }
+
+ return 0;
+}
+
+
+#endif
diff --git a/libj2_j2u_divmod_j2u_to_j2u_j2u.c b/libj2_j2u_divmod_j2u_to_j2u_j2u.c
new file mode 100644
index 0000000..3e9d0b0
--- /dev/null
+++ b/libj2_j2u_divmod_j2u_to_j2u_j2u.c
@@ -0,0 +1,14 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_divmod_j2u_to_j2u_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b,
+ struct libj2_j2u *res_q, struct libj2_j2u *res_r);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_divmod_ju.c b/libj2_j2u_divmod_ju.c
new file mode 100644
index 0000000..70a5d64
--- /dev/null
+++ b/libj2_j2u_divmod_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline uintmax_t libj2_j2u_divmod_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_divmod_ju_to_j2u.c b/libj2_j2u_divmod_ju_to_j2u.c
new file mode 100644
index 0000000..bfe0146
--- /dev/null
+++ b/libj2_j2u_divmod_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_divmod_ju_to_j2u(struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res_q);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_divmod_ju_to_j2u_j2u.c b/libj2_j2u_divmod_ju_to_j2u_j2u.c
new file mode 100644
index 0000000..9828d30
--- /dev/null
+++ b/libj2_j2u_divmod_ju_to_j2u_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_divmod_ju_to_j2u_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res_q, struct libj2_j2u *res_r);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_eq_j2u.c b/libj2_j2u_eq_j2u.c
new file mode 100644
index 0000000..847f942
--- /dev/null
+++ b/libj2_j2u_eq_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_eq_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */
+
+#endif
diff --git a/libj2_j2u_eq_ju.c b/libj2_j2u_eq_ju.c
new file mode 100644
index 0000000..9012baa
--- /dev/null
+++ b/libj2_j2u_eq_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_eq_ju(const struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_j2u_ge_j2u.c b/libj2_j2u_ge_j2u.c
new file mode 100644
index 0000000..031b7dd
--- /dev/null
+++ b/libj2_j2u_ge_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_ge_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */
+
+#endif
diff --git a/libj2_j2u_ge_ju.c b/libj2_j2u_ge_ju.c
new file mode 100644
index 0000000..a348fa6
--- /dev/null
+++ b/libj2_j2u_ge_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_ge_ju(const struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_j2u_gt_j2u.c b/libj2_j2u_gt_j2u.c
new file mode 100644
index 0000000..bd4da14
--- /dev/null
+++ b/libj2_j2u_gt_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_gt_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */
+
+#endif
diff --git a/libj2_j2u_gt_ju.c b/libj2_j2u_gt_ju.c
new file mode 100644
index 0000000..e7947d0
--- /dev/null
+++ b/libj2_j2u_gt_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_gt_ju(const struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_j2u_if_j2u.c b/libj2_j2u_if_j2u.c
new file mode 100644
index 0000000..c035683
--- /dev/null
+++ b/libj2_j2u_if_j2u.c
@@ -0,0 +1,140 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_if_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+static void
+check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected)
+{
+ struct libj2_j2u a_saved = *a, b_saved = *b, r;
+
+ r = *a;
+ libj2_j2u_if_j2u(&r, b);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_if_j2u(&r, &r);
+ EXPECT(libj2_j2u_is_max(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_if_j2u_to_j2u(a, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_if_j2u_to_j2u(&r, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_j2u_if_j2u_to_j2u(a, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_if_j2u_to_j2u(a, a, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_is_max(&r));
+
+ r = *a;
+ libj2_j2u_if_j2u_to_j2u(&r, &r, &r);
+ EXPECT(libj2_j2u_is_max(&r));
+
+ if (a->high == 0U) {
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_if_j2u_to_j2u(a->low, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_ju_if_j2u_to_j2u(a->low, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+
+ if (b->high == 0U) {
+ r = *a;
+ libj2_j2u_if_ju(&r, b->low);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_if_ju_to_j2u(a, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_if_ju_to_j2u(&r, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+}
+
+int
+main(void)
+{
+ unsigned truthtable[] = {1, 0, 1, 1};
+ unsigned i, j;
+ uintmax_t a_bit, b_bit, r_bit;
+ struct libj2_j2u a, b, r, a_saved;
+
+ srand((unsigned)time(NULL));
+
+ for (j = 0; j < 128; j++) {
+ a.high = a.low = 0;
+ b.high = b.low = 0;
+ r.high = r.low = 0;
+ for (i = 0; i < LIBJ2_J2U_BIT; i++) {
+ a_bit = (uintmax_t)(rand() < rand());
+ b_bit = (uintmax_t)(rand() < rand());
+ r_bit = truthtable[a_bit * 2U + b_bit];
+ if (i < LIBJ2_JU_BIT) {
+ a.low |= a_bit << i;
+ b.low |= b_bit << i;
+ r.low |= r_bit << i;
+ } else {
+ a.high |= a_bit << (i - LIBJ2_JU_BIT);
+ b.high |= b_bit << (i - LIBJ2_JU_BIT);
+ r.high |= r_bit << (i - LIBJ2_JU_BIT);
+ }
+ }
+
+ check(&a, &b, &r);
+
+ a_saved = a;
+ a.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[(b.high >> i) & 1U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+ a = a_saved;
+
+ b.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 2U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+
+ r.high = 0U;
+ r.low = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 3U];
+ r.high |= r_bit << i;
+ r_bit = truthtable[((a.low >> i) & 1U) * 3U];
+ r.low |= r_bit << i;
+ }
+ check(&a, &a, &r);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_if_j2u_to_j2u.c b/libj2_j2u_if_j2u_to_j2u.c
new file mode 100644
index 0000000..d9cbe47
--- /dev/null
+++ b/libj2_j2u_if_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_if_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_if_j2u.c */
+
+#endif
diff --git a/libj2_j2u_if_ju.c b/libj2_j2u_if_ju.c
new file mode 100644
index 0000000..088c176
--- /dev/null
+++ b/libj2_j2u_if_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_if_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_if_j2u.c */
+
+#endif
diff --git a/libj2_j2u_if_ju_to_j2u.c b/libj2_j2u_if_ju_to_j2u.c
new file mode 100644
index 0000000..a74c441
--- /dev/null
+++ b/libj2_j2u_if_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_if_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_if_j2u.c */
+
+#endif
diff --git a/libj2_j2u_imply_j2u.c b/libj2_j2u_imply_j2u.c
new file mode 100644
index 0000000..83accf9
--- /dev/null
+++ b/libj2_j2u_imply_j2u.c
@@ -0,0 +1,140 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_imply_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+static void
+check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected)
+{
+ struct libj2_j2u a_saved = *a, b_saved = *b, r;
+
+ r = *a;
+ libj2_j2u_imply_j2u(&r, b);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_imply_j2u(&r, &r);
+ EXPECT(libj2_j2u_is_max(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_imply_j2u_to_j2u(a, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_imply_j2u_to_j2u(&r, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_j2u_imply_j2u_to_j2u(a, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_imply_j2u_to_j2u(a, a, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_is_max(&r));
+
+ r = *a;
+ libj2_j2u_imply_j2u_to_j2u(&r, &r, &r);
+ EXPECT(libj2_j2u_is_max(&r));
+
+ if (a->high == 0U) {
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_imply_j2u_to_j2u(a->low, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_ju_imply_j2u_to_j2u(a->low, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+
+ if (b->high == 0U) {
+ r = *a;
+ libj2_j2u_imply_ju(&r, b->low);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_imply_ju_to_j2u(a, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_imply_ju_to_j2u(&r, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+}
+
+int
+main(void)
+{
+ unsigned truthtable[] = {1, 1, 0, 1};
+ unsigned i, j;
+ uintmax_t a_bit, b_bit, r_bit;
+ struct libj2_j2u a, b, r, a_saved;
+
+ srand((unsigned)time(NULL));
+
+ for (j = 0; j < 128; j++) {
+ a.high = a.low = 0;
+ b.high = b.low = 0;
+ r.high = r.low = 0;
+ for (i = 0; i < LIBJ2_J2U_BIT; i++) {
+ a_bit = (uintmax_t)(rand() < rand());
+ b_bit = (uintmax_t)(rand() < rand());
+ r_bit = truthtable[a_bit * 2U + b_bit];
+ if (i < LIBJ2_JU_BIT) {
+ a.low |= a_bit << i;
+ b.low |= b_bit << i;
+ r.low |= r_bit << i;
+ } else {
+ a.high |= a_bit << (i - LIBJ2_JU_BIT);
+ b.high |= b_bit << (i - LIBJ2_JU_BIT);
+ r.high |= r_bit << (i - LIBJ2_JU_BIT);
+ }
+ }
+
+ check(&a, &b, &r);
+
+ a_saved = a;
+ a.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[(b.high >> i) & 1U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+ a = a_saved;
+
+ b.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 2U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+
+ r.high = 0U;
+ r.low = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 3U];
+ r.high |= r_bit << i;
+ r_bit = truthtable[((a.low >> i) & 1U) * 3U];
+ r.low |= r_bit << i;
+ }
+ check(&a, &a, &r);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_imply_j2u_to_j2u.c b/libj2_j2u_imply_j2u_to_j2u.c
new file mode 100644
index 0000000..4ff3041
--- /dev/null
+++ b/libj2_j2u_imply_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_imply_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_imply_j2u.c */
+
+#endif
diff --git a/libj2_j2u_imply_ju.c b/libj2_j2u_imply_ju.c
new file mode 100644
index 0000000..735c31a
--- /dev/null
+++ b/libj2_j2u_imply_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_imply_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_imply_j2u.c */
+
+#endif
diff --git a/libj2_j2u_imply_ju_to_j2u.c b/libj2_j2u_imply_ju_to_j2u.c
new file mode 100644
index 0000000..cbb6309
--- /dev/null
+++ b/libj2_j2u_imply_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_imply_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_imply_j2u.c */
+
+#endif
diff --git a/libj2_j2u_is_max.c b/libj2_j2u_is_max.c
new file mode 100644
index 0000000..45df414
--- /dev/null
+++ b/libj2_j2u_is_max.c
@@ -0,0 +1,197 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_is_max(const struct libj2_j2u *a);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u value;
+ uintmax_t a, b;
+ int i, j;
+
+ for (i = 0; i < CHAR_BIT * (int)sizeof(uintmax_t); i++) {
+ for (j = 0; j < CHAR_BIT * (int)sizeof(uintmax_t); j++) {
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b = (uintmax_t)(j + 1);
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b = (uintmax_t)(j + 1);
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b = (uintmax_t)1 << j;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b = (uintmax_t)1 << j;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b = ~((uintmax_t)(j + 1));
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b = ~((uintmax_t)(j + 1));
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b = ~((uintmax_t)1 << j);
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b = ~((uintmax_t)1 << j);
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+ }
+
+ value.high = 0;
+ value.low = a = (uintmax_t)(i + 1);
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = (uintmax_t)1 << i;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = ~((uintmax_t)(i + 1));
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = ~((uintmax_t)1 << i);
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ b = ~(uintmax_t)0;
+
+ value.high = b;
+ value.low = a = (uintmax_t)(i + 1);
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = (uintmax_t)1 << i;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = ~((uintmax_t)(i + 1));
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = ~((uintmax_t)1 << i);
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+ }
+
+ value.high = 0;
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == 0);
+
+ a = ~(uintmax_t)0;
+
+ value.high = 0;
+ value.low = a;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a;
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_max(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = a;
+ value.low = a;
+ EXPECT(libj2_j2u_is_max(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == a);
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_is_min.c b/libj2_j2u_is_min.c
new file mode 100644
index 0000000..a2a7565
--- /dev/null
+++ b/libj2_j2u_is_min.c
@@ -0,0 +1,197 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_is_min(const struct libj2_j2u *a);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u value;
+ uintmax_t a, b;
+ int i, j;
+
+ for (i = 0; i < CHAR_BIT * (int)sizeof(uintmax_t); i++) {
+ for (j = 0; j < CHAR_BIT * (int)sizeof(uintmax_t); j++) {
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b = (uintmax_t)(j + 1);
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b = (uintmax_t)(j + 1);
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b = (uintmax_t)1 << j;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b = (uintmax_t)1 << j;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b = ~((uintmax_t)(j + 1));
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b = ~((uintmax_t)(j + 1));
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b = ~((uintmax_t)1 << j);
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b = ~((uintmax_t)1 << j);
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+ }
+
+ value.high = 0;
+ value.low = a = (uintmax_t)(i + 1);
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = (uintmax_t)1 << i;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = ~((uintmax_t)(i + 1));
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = ~((uintmax_t)1 << i);
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ b = ~(uintmax_t)0;
+
+ value.high = b;
+ value.low = a = (uintmax_t)(i + 1);
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = (uintmax_t)1 << i;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = ~((uintmax_t)(i + 1));
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = ~((uintmax_t)1 << i);
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+ }
+
+ value.high = 0;
+ value.low = 0;
+ EXPECT(libj2_j2u_is_min(&value) == 1);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == 0);
+
+ a = ~(uintmax_t)0;
+
+ value.high = 0;
+ value.low = a;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a;
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = a;
+ value.low = a;
+ EXPECT(!libj2_j2u_is_min(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == a);
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_is_positive.c b/libj2_j2u_is_positive.c
new file mode 100644
index 0000000..21a9dd7
--- /dev/null
+++ b/libj2_j2u_is_positive.c
@@ -0,0 +1,197 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_is_positive(const struct libj2_j2u *a);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u value;
+ uintmax_t a, b;
+ int i, j;
+
+ for (i = 0; i < CHAR_BIT * (int)sizeof(uintmax_t); i++) {
+ for (j = 0; j < CHAR_BIT * (int)sizeof(uintmax_t); j++) {
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b = (uintmax_t)(j + 1);
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b = (uintmax_t)(j + 1);
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b = (uintmax_t)1 << j;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b = (uintmax_t)1 << j;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b = ~((uintmax_t)(j + 1));
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b = ~((uintmax_t)(j + 1));
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b = ~((uintmax_t)1 << j);
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b = ~((uintmax_t)1 << j);
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+ }
+
+ value.high = 0;
+ value.low = a = (uintmax_t)(i + 1);
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = 0;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = (uintmax_t)1 << i;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = 0;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = ~((uintmax_t)(i + 1));
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = 0;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = ~((uintmax_t)1 << i);
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = 0;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ b = ~(uintmax_t)0;
+
+ value.high = b;
+ value.low = a = (uintmax_t)(i + 1);
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = (uintmax_t)1 << i;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = ~((uintmax_t)(i + 1));
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = ~((uintmax_t)1 << i);
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+ }
+
+ value.high = 0;
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_positive(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == 0);
+
+ a = ~(uintmax_t)0;
+
+ value.high = 0;
+ value.low = a;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a;
+ value.low = 0;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = a;
+ value.low = a;
+ EXPECT(libj2_j2u_is_positive(&value) == 1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == a);
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_is_zero.c b/libj2_j2u_is_zero.c
new file mode 100644
index 0000000..7058bbe
--- /dev/null
+++ b/libj2_j2u_is_zero.c
@@ -0,0 +1,197 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_is_zero(const struct libj2_j2u *a);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u value;
+ uintmax_t a, b;
+ int i, j;
+
+ for (i = 0; i < CHAR_BIT * (int)sizeof(uintmax_t); i++) {
+ for (j = 0; j < CHAR_BIT * (int)sizeof(uintmax_t); j++) {
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b = (uintmax_t)(j + 1);
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b = (uintmax_t)(j + 1);
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b = (uintmax_t)1 << j;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b = (uintmax_t)1 << j;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b = ~((uintmax_t)(j + 1));
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b = ~((uintmax_t)(j + 1));
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b = ~((uintmax_t)1 << j);
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b = ~((uintmax_t)1 << j);
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+ }
+
+ value.high = 0;
+ value.low = a = (uintmax_t)(i + 1);
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = (uintmax_t)1 << i;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = ~((uintmax_t)(i + 1));
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = ~((uintmax_t)1 << i);
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ b = ~(uintmax_t)0;
+
+ value.high = b;
+ value.low = a = (uintmax_t)(i + 1);
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = (uintmax_t)1 << i;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = ~((uintmax_t)(i + 1));
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = ~((uintmax_t)1 << i);
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+ }
+
+ value.high = 0;
+ value.low = 0;
+ EXPECT(libj2_j2u_is_zero(&value) == 1);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == 0);
+
+ a = ~(uintmax_t)0;
+
+ value.high = 0;
+ value.low = a;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a;
+ value.low = 0;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = a;
+ value.low = a;
+ EXPECT(!libj2_j2u_is_zero(&value));
+ EXPECT(value.high == a);
+ EXPECT(value.low == a);
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_le_j2u.c b/libj2_j2u_le_j2u.c
new file mode 100644
index 0000000..9403271
--- /dev/null
+++ b/libj2_j2u_le_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_le_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */
+
+#endif
diff --git a/libj2_j2u_le_ju.c b/libj2_j2u_le_ju.c
new file mode 100644
index 0000000..a55bfff
--- /dev/null
+++ b/libj2_j2u_le_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_le_ju(const struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_j2u_lrot.c b/libj2_j2u_lrot.c
new file mode 100644
index 0000000..0ad033b
--- /dev/null
+++ b/libj2_j2u_lrot.c
@@ -0,0 +1,81 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_lrot(struct libj2_j2u *a, unsigned b);
+/* TODO Add man page */
+
+
+#else
+
+static void
+set(struct libj2_j2u *a, const char *pattern, unsigned shift)
+{
+ unsigned i, j = (LIBJ2_J2U_BIT - (shift % LIBJ2_J2U_BIT)) % LIBJ2_J2U_BIT;
+
+ a->high = 0;
+ a->low = 0;
+
+ for (i = 0; i < LIBJ2_JU_BIT; i++, j++)
+ if (pattern[j % LIBJ2_J2U_BIT] == '1')
+ a->low |= (uintmax_t)1 << i;
+
+ for (i = 0; i < LIBJ2_JU_BIT; i++, j++)
+ if (pattern[j % LIBJ2_J2U_BIT] == '1')
+ a->high |= (uintmax_t)1 << i;
+
+}
+
+
+int
+main(void)
+{
+ struct libj2_j2u a, r, a_saved, expected;
+ char pattern[LIBJ2_J2U_BIT + 1U];
+ unsigned i, j, k;
+
+ srand((unsigned)time(NULL));
+
+ for (i = 0; i < 128U; i++) {
+ for (j = 0; j < LIBJ2_J2U_BIT; j++)
+ pattern[j] = '0' + (rand() < rand());
+ pattern[LIBJ2_J2U_BIT] = '\0';
+ set(&a, pattern, 0);
+ a_saved = a;
+ for (j = 0; j <= 2U * LIBJ2_J2U_BIT; j++) {
+ set(&expected, pattern, j);
+
+ r = a;
+ libj2_j2u_lrot(&r, j);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_lrot_to_j2u(&a, j, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ r = a;
+ libj2_j2u_lrot_to_j2u(&r, j, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ k = 2U * LIBJ2_J2U_BIT - j;
+
+ r = a;
+ libj2_j2u_rrot(&r, k);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_rrot_to_j2u(&a, k, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ r = a;
+ libj2_j2u_rrot_to_j2u(&r, k, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_lrot_to_j2u.c b/libj2_j2u_lrot_to_j2u.c
new file mode 100644
index 0000000..66f7a1d
--- /dev/null
+++ b/libj2_j2u_lrot_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_lrot_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_lrot.c */
+
+#endif
diff --git a/libj2_j2u_lsh.c b/libj2_j2u_lsh.c
new file mode 100644
index 0000000..85ca72b
--- /dev/null
+++ b/libj2_j2u_lsh.c
@@ -0,0 +1,172 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_lsh(struct libj2_j2u *a, unsigned b);
+/* TODO Add man page */
+
+
+#else
+
+static const char *patterns[] = {
+ "0",
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1010101010101001010100100010101010101011000101101011101001000110",
+ "1110100100100010000010111111011101101001000010001000011110101010",
+ "11111111111100001001011",
+ "0010011011001",
+ "110010001011110100101001010011010111101",
+ NULL
+};
+
+
+PURE static size_t
+count_ones(const char *bits)
+{
+ size_t n = strlen(bits);
+ if (n > LIBJ2_J2U_BIT)
+ bits = &bits[n - LIBJ2_J2U_BIT];
+ n = 0;
+ while (*bits)
+ if (*bits++ == '1')
+ n += 1U;
+ return n;
+}
+
+
+static int
+set(struct libj2_j2u *a, const char *bits, size_t trailing_zeroes)
+{
+ size_t i, n;
+ char *all_bits, *p;
+
+ n = LIBJ2_J2U_BIT + strlen(bits) + trailing_zeroes;
+ EXPECT((all_bits = malloc(n + 1U)));
+ memset(all_bits, '0', LIBJ2_J2U_BIT);
+ p = stpcpy(&all_bits[LIBJ2_J2U_BIT], bits);
+ memset(p, '0', trailing_zeroes);
+ p = &p[trailing_zeroes];
+
+ n = 0;
+
+ a->low = 0;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ if (*--p == '1') {
+ a->low |= (uintmax_t)1 << i;
+ n += 1U;
+ }
+ }
+
+ a->high = 0;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ if (*--p == '1') {
+ a->high |= (uintmax_t)1 << i;
+ n += 1U;
+ }
+ }
+
+ free(all_bits);
+ return n < count_ones(bits);
+}
+
+
+static void
+self_check(void)
+{
+ struct libj2_j2u a = {111, 222};
+ EXPECT(set(&a, "11", 8) == 0);
+ EXPECT(a.high == 0);
+ EXPECT(a.low == (3U << 8));
+ EXPECT(set(&a, "1101", LIBJ2_JU_BIT) == 0);
+ EXPECT(a.high == 13U);
+ EXPECT(a.low == 0);
+ EXPECT(set(&a, "1", LIBJ2_JU_BIT - 1) == 0);
+ EXPECT(a.high == 0);
+ EXPECT(a.low == (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)));
+ EXPECT(set(&a, "111", LIBJ2_JU_BIT - 2) == 0);
+ EXPECT(a.high == 1);
+ EXPECT(a.low == (UINTMAX_MAX ^ (UINTMAX_MAX >> 2)));
+ EXPECT(set(&a, "1", LIBJ2_J2U_BIT) == 1);
+ EXPECT(a.high == 0);
+ EXPECT(a.low == 0);
+}
+
+
+static void
+check(const char *pattern)
+{
+ struct libj2_j2u a, a_saved, r, expected;
+ unsigned i;
+ int overflows;
+
+ set(&a, pattern, 0);
+ a_saved = a;
+ for (i = 0; i < LIBJ2_J2U_BIT + 8U; i++) {
+ overflows = set(&expected, pattern, i);
+
+ r = a;
+ libj2_j2u_lsh(&r, i);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = a;
+ EXPECT(libj2_j2u_lsh_overflow(&r, i) == overflows);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_lsh_to_j2u(&a, i, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ r = (struct libj2_j2u){111, 222};
+ EXPECT(libj2_j2u_lsh_to_j2u_overflow(&a, i, &r) == overflows);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ r = a;
+ libj2_j2u_lsh_to_j2u(&r, i, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = a;
+ EXPECT(libj2_j2u_lsh_to_j2u_overflow(&r, i, &r) == overflows);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ }
+}
+
+
+int
+main(void)
+{
+ size_t i, j;
+ char pattern[LIBJ2_J2U_BIT + 1U];
+
+ self_check();
+ srand((unsigned)time(NULL));
+
+ for (i = 0; patterns[i]; i++)
+ check(patterns[i]);
+
+ for (i = 0; i < 64; i++) {
+ for (j = 0; j < LIBJ2_J2U_BIT; j++)
+ pattern[j] = '0' + (rand() < rand());
+ pattern[LIBJ2_J2U_BIT] = '\0';
+ check(pattern);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_lsh_overflow.c b/libj2_j2u_lsh_overflow.c
new file mode 100644
index 0000000..aee6155
--- /dev/null
+++ b/libj2_j2u_lsh_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_lsh_overflow(struct libj2_j2u *a, unsigned b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_lsh.c */
+
+#endif
diff --git a/libj2_j2u_lsh_to_j2u.c b/libj2_j2u_lsh_to_j2u.c
new file mode 100644
index 0000000..31b32c7
--- /dev/null
+++ b/libj2_j2u_lsh_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_lsh_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_lsh.c */
+
+#endif
diff --git a/libj2_j2u_lsh_to_j2u_overflow.c b/libj2_j2u_lsh_to_j2u_overflow.c
new file mode 100644
index 0000000..63aaa3f
--- /dev/null
+++ b/libj2_j2u_lsh_to_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_lsh_to_j2u_overflow(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_lsh.c */
+
+#endif
diff --git a/libj2_j2u_lt_j2u.c b/libj2_j2u_lt_j2u.c
new file mode 100644
index 0000000..3dddb5e
--- /dev/null
+++ b/libj2_j2u_lt_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_lt_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */
+
+#endif
diff --git a/libj2_j2u_lt_ju.c b/libj2_j2u_lt_ju.c
new file mode 100644
index 0000000..e467f58
--- /dev/null
+++ b/libj2_j2u_lt_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_lt_ju(const struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_j2u_max.c b/libj2_j2u_max.c
new file mode 100644
index 0000000..a6b7317
--- /dev/null
+++ b/libj2_j2u_max.c
@@ -0,0 +1,27 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_max(struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u value = {1, 2};
+
+ libj2_j2u_max(&value);
+ EXPECT(~value.high == 0);
+ EXPECT(~value.low == 0);
+
+ libj2_j2u_max(&value);
+ EXPECT(~value.high == 0);
+ EXPECT(~value.low == 0);
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_max_j2u.c b/libj2_j2u_max_j2u.c
new file mode 100644
index 0000000..3120428
--- /dev/null
+++ b/libj2_j2u_max_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_max_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */
+
+#endif
diff --git a/libj2_j2u_max_j2u_to_j2u.c b/libj2_j2u_max_j2u_to_j2u.c
new file mode 100644
index 0000000..ab780fa
--- /dev/null
+++ b/libj2_j2u_max_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_max_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */
+
+#endif
diff --git a/libj2_j2u_max_ju.c b/libj2_j2u_max_ju.c
new file mode 100644
index 0000000..dfb10b8
--- /dev/null
+++ b/libj2_j2u_max_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_max_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_j2u_max_ju_to_j2u.c b/libj2_j2u_max_ju_to_j2u.c
new file mode 100644
index 0000000..4739cf3
--- /dev/null
+++ b/libj2_j2u_max_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_max_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_j2u_min.c b/libj2_j2u_min.c
new file mode 100644
index 0000000..4ede699
--- /dev/null
+++ b/libj2_j2u_min.c
@@ -0,0 +1,27 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_min(struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u value = {1, 2};
+
+ libj2_j2u_min(&value);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == 0);
+
+ libj2_j2u_min(&value);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == 0);
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_min_j2u.c b/libj2_j2u_min_j2u.c
new file mode 100644
index 0000000..1aa9f98
--- /dev/null
+++ b/libj2_j2u_min_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_min_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */
+
+#endif
diff --git a/libj2_j2u_min_j2u_to_j2u.c b/libj2_j2u_min_j2u_to_j2u.c
new file mode 100644
index 0000000..a47b80f
--- /dev/null
+++ b/libj2_j2u_min_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_min_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */
+
+#endif
diff --git a/libj2_j2u_min_ju.c b/libj2_j2u_min_ju.c
new file mode 100644
index 0000000..a3dfcdf
--- /dev/null
+++ b/libj2_j2u_min_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_min_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_j2u_min_ju_to_j2u.c b/libj2_j2u_min_ju_to_j2u.c
new file mode 100644
index 0000000..8fe83c5
--- /dev/null
+++ b/libj2_j2u_min_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_min_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_j2u_mod_j2u.c b/libj2_j2u_mod_j2u.c
new file mode 100644
index 0000000..511b026
--- /dev/null
+++ b/libj2_j2u_mod_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_mod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_mod_j2u_to_j2u.c b/libj2_j2u_mod_j2u_to_j2u.c
new file mode 100644
index 0000000..cf28e65
--- /dev/null
+++ b/libj2_j2u_mod_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_mod_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_mod_ju.c b/libj2_j2u_mod_ju.c
new file mode 100644
index 0000000..ec8016b
--- /dev/null
+++ b/libj2_j2u_mod_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_mod_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_mod_ju_to_j2u.c b/libj2_j2u_mod_ju_to_j2u.c
new file mode 100644
index 0000000..284ef6a
--- /dev/null
+++ b/libj2_j2u_mod_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_mod_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_mul_j2u.c b/libj2_j2u_mul_j2u.c
new file mode 100644
index 0000000..aa1f178
--- /dev/null
+++ b/libj2_j2u_mul_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_mul_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_j2u_destructive.c */
+
+#endif
diff --git a/libj2_j2u_mul_j2u_destructive.c b/libj2_j2u_mul_j2u_destructive.c
new file mode 100644
index 0000000..cfa36a2
--- /dev/null
+++ b/libj2_j2u_mul_j2u_destructive.c
@@ -0,0 +1,267 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_mul_j2u_destructive(struct libj2_j2u *restrict a /*result */, struct libj2_j2u *restrict b /*destructed */);
+/* 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 void
+random_j2u(struct libj2_j2u *a)
+{
+ a->high = random_ju();
+ a->low = random_ju();
+}
+
+
+static int
+refmul(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *expected)
+{
+ struct libj2_j2u c;
+ unsigned i;
+ int overflow = 0;
+
+ libj2_j2u_zero(expected);
+ for (i = 0; i < LIBJ2_J2U_BIT; i++) {
+ if (libj2_j2u_test_bit(b, i)) {
+ overflow |= libj2_j2u_lsh_to_j2u_overflow(a, i, &c);
+ libj2_j2u_add_j2u(expected, &c);
+ }
+ }
+
+ return overflow;
+}
+
+
+static void
+mul_(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *expected, int expect_overflow)
+{
+ struct libj2_j2u t, x, a_saved = *a, b_saved = *b;
+
+ *expected = *a;
+ libj2_j2u_mul_j2u(expected, b);
+
+ t = (struct libj2_j2u){111, 222};
+ libj2_j2u_mul_j2u_to_j2u(a, b, &t);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+
+ t = *a;
+ EXPECT(libj2_j2u_mul_j2u_overflow(&t, b) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+
+ t = (struct libj2_j2u){111, 222};
+ EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow(a, b, &t) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+
+ t = *a;
+ x = *b;
+ libj2_j2u_mul_j2u_destructive(&t, &x);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+
+ t = *a;
+ x = *b;
+ EXPECT(libj2_j2u_mul_j2u_overflow_destructive(&t, &x) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+
+ if (a == b) {
+ t = *a;
+ libj2_j2u_mul_j2u(&t, &t);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+
+ t = *a;
+ libj2_j2u_mul_j2u_to_j2u(&t, &t, &t);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+
+ t = *a;
+ EXPECT(libj2_j2u_mul_j2u_overflow(&t, &t) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+
+ t = *a;
+ EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow(&t, &t, &t) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ }}
+
+
+static void
+mul(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *expected, int expect_overflow)
+{
+ struct libj2_j2u t;
+
+ if (a == b) {
+ t = *a;
+ mul_(a, &t, expected, expect_overflow);
+ mul_(a, a, expected, expect_overflow);
+ } else {
+ mul_(a, b, expected, expect_overflow);
+ mul_(b, a, expected, expect_overflow);
+ }
+}
+
+
+int
+main(void)
+{
+ const struct libj2_j2u zero = {0, 0};
+ const struct libj2_j2u one = {.high = 0, .low = 1};
+ const struct libj2_j2u four = {.high = 0, .low = 4};
+ const struct libj2_j2u ju_max = {.high = 0, .low = UINTMAX_MAX};
+ const struct libj2_j2u j2u_max = {.high = UINTMAX_MAX, .low = UINTMAX_MAX};
+ struct libj2_j2u a, b, r, expected;
+ uintmax_t u, v;
+ unsigned i;
+ int expect_overflow;
+
+ srand((unsigned)time(NULL));
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&zero, &zero, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&zero, &one, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&zero, &ju_max, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&one, &zero, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&ju_max, &zero, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ for (i = 0; i < 32; i++) {
+ r = (struct libj2_j2u){111, 222};
+ v = random_ju();
+ libj2_ju_to_j2u(v, &a);
+ mul(&zero, &a, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ v = random_ju();
+ libj2_ju_to_j2u(v, &a);
+ mul(&a, &zero, &r, 0);
+
+ EXPECT(libj2_j2u_is_zero(&r));
+ r = (struct libj2_j2u){111, 222};
+ random_j2u(&a);
+ mul(&zero, &a, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ random_j2u(&a);
+ mul(&a, &zero, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+ }
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&one, &one, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == 1);
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&four, &four, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == 16);
+
+ for (i = 0; i < 32; i++) {
+ r = (struct libj2_j2u){111, 222};
+ v = random_ju();
+ libj2_ju_to_j2u(v, &a);
+ mul(&one, &a, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == v);
+
+ r = (struct libj2_j2u){111, 222};
+ v = random_ju();
+ libj2_ju_to_j2u(v, &a);
+ mul(&a, &one, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == v);
+ }
+
+ for (i = 0; i < 32; i++) {
+ u = random_hju();
+ v = random_hju();
+
+ libj2_ju_to_j2u(u, &a);
+ libj2_ju_to_j2u(v, &b);
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&a, &b, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == u * v);
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&b, &a, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == u * v);
+ }
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&ju_max, &ju_max, &r, 0);
+ EXPECT(r.high == UINTMAX_MAX - 1U);
+ EXPECT(r.low == 1);
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&j2u_max, &ju_max, &r, 1);
+ EXPECT(r.high == UINTMAX_MAX);
+ EXPECT(r.low == 1);
+
+ /* self-check */
+ r = (struct libj2_j2u){111, 222};
+ EXPECT(refmul(&j2u_max, &ju_max, &r) == 1);
+ EXPECT(r.high == UINTMAX_MAX);
+ EXPECT(r.low == 1);
+ r = (struct libj2_j2u){111, 222};
+ EXPECT(refmul(&j2u_max, &j2u_max, &r) == 1);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == 1);
+
+ for (i = 0; i < 256; i++) {
+ random_j2u(&a);
+ random_j2u(&b);
+
+ expect_overflow = refmul(&a, &b, &expected);
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&a, &b, &r, expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_mul_j2u_overflow.c b/libj2_j2u_mul_j2u_overflow.c
new file mode 100644
index 0000000..30c665d
--- /dev/null
+++ b/libj2_j2u_mul_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_mul_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_j2u_destructive.c */
+
+#endif
diff --git a/libj2_j2u_mul_j2u_overflow_destructive.c b/libj2_j2u_mul_j2u_overflow_destructive.c
new file mode 100644
index 0000000..4f346c5
--- /dev/null
+++ b/libj2_j2u_mul_j2u_overflow_destructive.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_mul_j2u_overflow_destructive(struct libj2_j2u *restrict a /*result */, struct libj2_j2u *restrict b /*destructed */);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_j2u_destructive.c */
+
+#endif
diff --git a/libj2_j2u_mul_j2u_to_j2u.c b/libj2_j2u_mul_j2u_to_j2u.c
new file mode 100644
index 0000000..b2fb25a
--- /dev/null
+++ b/libj2_j2u_mul_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_mul_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_j2u_destructive.c */
+
+#endif
diff --git a/libj2_j2u_mul_j2u_to_j2u_overflow.c b/libj2_j2u_mul_j2u_to_j2u_overflow.c
new file mode 100644
index 0000000..5867c4f
--- /dev/null
+++ b/libj2_j2u_mul_j2u_to_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_mul_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_j2u_destructive.c */
+
+#endif
diff --git a/libj2_j2u_mul_ju.c b/libj2_j2u_mul_ju.c
new file mode 100644
index 0000000..17fc453
--- /dev/null
+++ b/libj2_j2u_mul_ju.c
@@ -0,0 +1,197 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_mul_ju(struct libj2_j2u *a, uintmax_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_j2u *a, uintmax_t b, struct libj2_j2u *expected)
+{
+ struct libj2_j2u c;
+ unsigned i;
+ int overflow = 0;
+
+ libj2_j2u_zero(expected);
+ for (i = 0; i < LIBJ2_J2U_BIT; i++, b >>= 1) {
+ if (b & 1U) {
+ overflow |= libj2_j2u_lsh_to_j2u_overflow(a, i, &c);
+ libj2_j2u_add_j2u(expected, &c);
+ }
+ }
+
+ return overflow;
+}
+
+
+static void
+mul(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *expected, int expect_overflow)
+{
+ struct libj2_j2u t, a_saved = *a;
+
+ *expected = *a;
+ libj2_j2u_mul_ju(expected, b);
+
+ t = (struct libj2_j2u){111, 222};
+ libj2_j2u_mul_ju_to_j2u(a, b, &t);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+
+ t = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_j2u_to_j2u(b, a, &t);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+
+ t = *a;
+ EXPECT(libj2_j2u_mul_ju_overflow(&t, b) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+
+ t = (struct libj2_j2u){111, 222};
+ EXPECT(libj2_j2u_mul_ju_to_j2u_overflow(a, b, &t) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+
+ t = (struct libj2_j2u){111, 222};
+ EXPECT(libj2_ju_mul_j2u_to_j2u_overflow(b, a, &t) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+}
+
+
+int
+main(void)
+{
+ struct libj2_j2u r, expected;
+ uintmax_t u, v, w;
+ unsigned i;
+ int expect_overflow;
+
+ srand((unsigned)time(NULL));
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){.high = 0, .low = 0}, 0, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){.high = 0, .low = 0}, 1, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){.high = 0, .low = 0}, UINTMAX_MAX, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){.high = 0, .low = 1}, 0, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){.high = 0, .low = UINTMAX_MAX}, 0, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ for (i = 0; i < 32; i++) {
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){.high = 0, .low = 0}, random_ju(), &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){.high = 0, .low = random_ju()}, 0, &r, 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+ }
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){.high = 0, .low = 1}, 1, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == 1);
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){.high = 0, .low = 4}, 4, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == 16);
+
+ for (i = 0; i < 32; i++) {
+ r = (struct libj2_j2u){111, 222};
+ v = random_ju();
+ mul(&(struct libj2_j2u){.high = 0, .low = 1}, v, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == v);
+
+ r = (struct libj2_j2u){111, 222};
+ v = random_ju();
+ mul(&(struct libj2_j2u){.high = 0, .low = v}, 1, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == v);
+ }
+
+ for (i = 0; i < 32; i++) {
+ u = random_hju();
+ v = random_hju();
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){.high = 0, .low = u}, v, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == u * v);
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){.high = 0, .low = v}, u, &r, 0);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == u * v);
+ }
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){.high = 0, .low = UINTMAX_MAX}, UINTMAX_MAX, &r, 0);
+ EXPECT(r.high == UINTMAX_MAX - 1U);
+ EXPECT(r.low == 1);
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){.high = UINTMAX_MAX, .low = UINTMAX_MAX}, UINTMAX_MAX, &r, 1);
+ EXPECT(r.high == UINTMAX_MAX);
+ EXPECT(r.low == 1);
+
+ /* self-check */
+ r = (struct libj2_j2u){111, 222};
+ EXPECT(refmul(&(struct libj2_j2u){.high = UINTMAX_MAX, .low = UINTMAX_MAX}, UINTMAX_MAX, &r) == 1);
+ EXPECT(r.high == UINTMAX_MAX);
+ EXPECT(r.low == 1);
+
+ for (i = 0; i < 256; i++) {
+ u = random_ju();
+ v = random_ju();
+ w = random_ju();
+
+ expect_overflow = refmul(&(struct libj2_j2u){u, v}, w, &expected);
+
+ r = (struct libj2_j2u){111, 222};
+ mul(&(struct libj2_j2u){u, v}, w, &r, expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_mul_ju_overflow.c b/libj2_j2u_mul_ju_overflow.c
new file mode 100644
index 0000000..bd7900f
--- /dev/null
+++ b/libj2_j2u_mul_ju_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_mul_ju_overflow(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */
+
+#endif
diff --git a/libj2_j2u_mul_ju_to_j2u.c b/libj2_j2u_mul_ju_to_j2u.c
new file mode 100644
index 0000000..7a79b79
--- /dev/null
+++ b/libj2_j2u_mul_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_mul_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */
+
+#endif
diff --git a/libj2_j2u_mul_ju_to_j2u_overflow.c b/libj2_j2u_mul_ju_to_j2u_overflow.c
new file mode 100644
index 0000000..c88450b
--- /dev/null
+++ b/libj2_j2u_mul_ju_to_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_mul_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */
+
+#endif
diff --git a/libj2_j2u_nand_j2u.c b/libj2_j2u_nand_j2u.c
new file mode 100644
index 0000000..6c575fe
--- /dev/null
+++ b/libj2_j2u_nand_j2u.c
@@ -0,0 +1,143 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nand_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+static void
+check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected)
+{
+ struct libj2_j2u a_saved = *a, b_saved = *b, r;
+
+ r = *a;
+ libj2_j2u_nand_j2u(&r, b);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_nand_j2u(&r, &r);
+ libj2_not_j2u(&r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &a_saved));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_nand_j2u_to_j2u(a, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_nand_j2u_to_j2u(&r, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_j2u_nand_j2u_to_j2u(a, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_nand_j2u_to_j2u(a, a, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ libj2_not_j2u(&r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &a_saved));
+
+ r = *a;
+ libj2_j2u_nand_j2u_to_j2u(&r, &r, &r);
+ libj2_not_j2u(&r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &a_saved));
+
+ if (a->high == 0U) {
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_nand_j2u_to_j2u(a->low, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_ju_nand_j2u_to_j2u(a->low, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+
+ if (b->high == 0U) {
+ r = *a;
+ libj2_j2u_nand_ju(&r, b->low);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_nand_ju_to_j2u(a, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_nand_ju_to_j2u(&r, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+}
+
+int
+main(void)
+{
+ unsigned truthtable[] = {1, 1, 1, 0};
+ unsigned i, j;
+ uintmax_t a_bit, b_bit, r_bit;
+ struct libj2_j2u a, b, r, a_saved;
+
+ srand((unsigned)time(NULL));
+
+ for (j = 0; j < 128; j++) {
+ a.high = a.low = 0;
+ b.high = b.low = 0;
+ r.high = r.low = 0;
+ for (i = 0; i < LIBJ2_J2U_BIT; i++) {
+ a_bit = (uintmax_t)(rand() < rand());
+ b_bit = (uintmax_t)(rand() < rand());
+ r_bit = truthtable[a_bit * 2U + b_bit];
+ if (i < LIBJ2_JU_BIT) {
+ a.low |= a_bit << i;
+ b.low |= b_bit << i;
+ r.low |= r_bit << i;
+ } else {
+ a.high |= a_bit << (i - LIBJ2_JU_BIT);
+ b.high |= b_bit << (i - LIBJ2_JU_BIT);
+ r.high |= r_bit << (i - LIBJ2_JU_BIT);
+ }
+ }
+
+ check(&a, &b, &r);
+
+ a_saved = a;
+ a.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[(b.high >> i) & 1U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+ a = a_saved;
+
+ b.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 2U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+
+ r.high = 0U;
+ r.low = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 3U];
+ r.high |= r_bit << i;
+ r_bit = truthtable[((a.low >> i) & 1U) * 3U];
+ r.low |= r_bit << i;
+ }
+ check(&a, &a, &r);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_nand_j2u_to_j2u.c b/libj2_j2u_nand_j2u_to_j2u.c
new file mode 100644
index 0000000..8cad27e
--- /dev/null
+++ b/libj2_j2u_nand_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nand_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nand_j2u.c */
+
+#endif
diff --git a/libj2_j2u_nand_ju.c b/libj2_j2u_nand_ju.c
new file mode 100644
index 0000000..0237342
--- /dev/null
+++ b/libj2_j2u_nand_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nand_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nand_j2u.c */
+
+#endif
diff --git a/libj2_j2u_nand_ju_to_j2u.c b/libj2_j2u_nand_ju_to_j2u.c
new file mode 100644
index 0000000..b3d458a
--- /dev/null
+++ b/libj2_j2u_nand_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nand_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nand_j2u.c */
+
+#endif
diff --git a/libj2_j2u_ne_j2u.c b/libj2_j2u_ne_j2u.c
new file mode 100644
index 0000000..539d481
--- /dev/null
+++ b/libj2_j2u_ne_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_ne_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */
+
+#endif
diff --git a/libj2_j2u_ne_ju.c b/libj2_j2u_ne_ju.c
new file mode 100644
index 0000000..128f3f6
--- /dev/null
+++ b/libj2_j2u_ne_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_ne_ju(const struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_j2u_nif_j2u.c b/libj2_j2u_nif_j2u.c
new file mode 100644
index 0000000..fbb45d4
--- /dev/null
+++ b/libj2_j2u_nif_j2u.c
@@ -0,0 +1,140 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nif_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+static void
+check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected)
+{
+ struct libj2_j2u a_saved = *a, b_saved = *b, r;
+
+ r = *a;
+ libj2_j2u_nif_j2u(&r, b);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_nif_j2u(&r, &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_nif_j2u_to_j2u(a, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_nif_j2u_to_j2u(&r, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_j2u_nif_j2u_to_j2u(a, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_nif_j2u_to_j2u(a, a, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = *a;
+ libj2_j2u_nif_j2u_to_j2u(&r, &r, &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ if (a->high == 0U) {
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_nif_j2u_to_j2u(a->low, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_ju_nif_j2u_to_j2u(a->low, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+
+ if (b->high == 0U) {
+ r = *a;
+ libj2_j2u_nif_ju(&r, b->low);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_nif_ju_to_j2u(a, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_nif_ju_to_j2u(&r, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+}
+
+int
+main(void)
+{
+ unsigned truthtable[] = {0, 1, 0, 0};
+ unsigned i, j;
+ uintmax_t a_bit, b_bit, r_bit;
+ struct libj2_j2u a, b, r, a_saved;
+
+ srand((unsigned)time(NULL));
+
+ for (j = 0; j < 128; j++) {
+ a.high = a.low = 0;
+ b.high = b.low = 0;
+ r.high = r.low = 0;
+ for (i = 0; i < LIBJ2_J2U_BIT; i++) {
+ a_bit = (uintmax_t)(rand() < rand());
+ b_bit = (uintmax_t)(rand() < rand());
+ r_bit = truthtable[a_bit * 2U + b_bit];
+ if (i < LIBJ2_JU_BIT) {
+ a.low |= a_bit << i;
+ b.low |= b_bit << i;
+ r.low |= r_bit << i;
+ } else {
+ a.high |= a_bit << (i - LIBJ2_JU_BIT);
+ b.high |= b_bit << (i - LIBJ2_JU_BIT);
+ r.high |= r_bit << (i - LIBJ2_JU_BIT);
+ }
+ }
+
+ check(&a, &b, &r);
+
+ a_saved = a;
+ a.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[(b.high >> i) & 1U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+ a = a_saved;
+
+ b.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 2U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+
+ r.high = 0U;
+ r.low = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 3U];
+ r.high |= r_bit << i;
+ r_bit = truthtable[((a.low >> i) & 1U) * 3U];
+ r.low |= r_bit << i;
+ }
+ check(&a, &a, &r);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_nif_j2u_to_j2u.c b/libj2_j2u_nif_j2u_to_j2u.c
new file mode 100644
index 0000000..e1cd670
--- /dev/null
+++ b/libj2_j2u_nif_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nif_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nif_j2u.c */
+
+#endif
diff --git a/libj2_j2u_nif_ju.c b/libj2_j2u_nif_ju.c
new file mode 100644
index 0000000..caa6222
--- /dev/null
+++ b/libj2_j2u_nif_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nif_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nif_j2u.c */
+
+#endif
diff --git a/libj2_j2u_nif_ju_to_j2u.c b/libj2_j2u_nif_ju_to_j2u.c
new file mode 100644
index 0000000..f95f4a0
--- /dev/null
+++ b/libj2_j2u_nif_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nif_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nif_j2u.c */
+
+#endif
diff --git a/libj2_j2u_nimply_j2u.c b/libj2_j2u_nimply_j2u.c
new file mode 100644
index 0000000..c81a049
--- /dev/null
+++ b/libj2_j2u_nimply_j2u.c
@@ -0,0 +1,140 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nimply_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+static void
+check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected)
+{
+ struct libj2_j2u a_saved = *a, b_saved = *b, r;
+
+ r = *a;
+ libj2_j2u_nimply_j2u(&r, b);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_nimply_j2u(&r, &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_nimply_j2u_to_j2u(a, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_nimply_j2u_to_j2u(&r, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_j2u_nimply_j2u_to_j2u(a, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_nimply_j2u_to_j2u(a, a, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = *a;
+ libj2_j2u_nimply_j2u_to_j2u(&r, &r, &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ if (a->high == 0U) {
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_nimply_j2u_to_j2u(a->low, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_ju_nimply_j2u_to_j2u(a->low, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+
+ if (b->high == 0U) {
+ r = *a;
+ libj2_j2u_nimply_ju(&r, b->low);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_nimply_ju_to_j2u(a, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_nimply_ju_to_j2u(&r, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+}
+
+int
+main(void)
+{
+ unsigned truthtable[] = {0, 0, 1, 0};
+ unsigned i, j;
+ uintmax_t a_bit, b_bit, r_bit;
+ struct libj2_j2u a, b, r, a_saved;
+
+ srand((unsigned)time(NULL));
+
+ for (j = 0; j < 128; j++) {
+ a.high = a.low = 0;
+ b.high = b.low = 0;
+ r.high = r.low = 0;
+ for (i = 0; i < LIBJ2_J2U_BIT; i++) {
+ a_bit = (uintmax_t)(rand() < rand());
+ b_bit = (uintmax_t)(rand() < rand());
+ r_bit = truthtable[a_bit * 2U + b_bit];
+ if (i < LIBJ2_JU_BIT) {
+ a.low |= a_bit << i;
+ b.low |= b_bit << i;
+ r.low |= r_bit << i;
+ } else {
+ a.high |= a_bit << (i - LIBJ2_JU_BIT);
+ b.high |= b_bit << (i - LIBJ2_JU_BIT);
+ r.high |= r_bit << (i - LIBJ2_JU_BIT);
+ }
+ }
+
+ check(&a, &b, &r);
+
+ a_saved = a;
+ a.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[(b.high >> i) & 1U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+ a = a_saved;
+
+ b.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 2U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+
+ r.high = 0U;
+ r.low = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 3U];
+ r.high |= r_bit << i;
+ r_bit = truthtable[((a.low >> i) & 1U) * 3U];
+ r.low |= r_bit << i;
+ }
+ check(&a, &a, &r);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_nimply_j2u_to_j2u.c b/libj2_j2u_nimply_j2u_to_j2u.c
new file mode 100644
index 0000000..654be2e
--- /dev/null
+++ b/libj2_j2u_nimply_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nimply_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nimply_j2u.c */
+
+#endif
diff --git a/libj2_j2u_nimply_ju.c b/libj2_j2u_nimply_ju.c
new file mode 100644
index 0000000..8d87725
--- /dev/null
+++ b/libj2_j2u_nimply_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nimply_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nimply_j2u.c */
+
+#endif
diff --git a/libj2_j2u_nimply_ju_to_j2u.c b/libj2_j2u_nimply_ju_to_j2u.c
new file mode 100644
index 0000000..e46d803
--- /dev/null
+++ b/libj2_j2u_nimply_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nimply_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nimply_j2u.c */
+
+#endif
diff --git a/libj2_j2u_nor_j2u.c b/libj2_j2u_nor_j2u.c
new file mode 100644
index 0000000..902997f
--- /dev/null
+++ b/libj2_j2u_nor_j2u.c
@@ -0,0 +1,143 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nor_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+static void
+check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected)
+{
+ struct libj2_j2u a_saved = *a, b_saved = *b, r;
+
+ r = *a;
+ libj2_j2u_nor_j2u(&r, b);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_nor_j2u(&r, &r);
+ libj2_not_j2u(&r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &a_saved));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_nor_j2u_to_j2u(a, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_nor_j2u_to_j2u(&r, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_j2u_nor_j2u_to_j2u(a, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_nor_j2u_to_j2u(a, a, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ libj2_not_j2u(&r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &a_saved));
+
+ r = *a;
+ libj2_j2u_nor_j2u_to_j2u(&r, &r, &r);
+ libj2_not_j2u(&r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &a_saved));
+
+ if (a->high == 0U) {
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_nor_j2u_to_j2u(a->low, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_ju_nor_j2u_to_j2u(a->low, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+
+ if (b->high == 0U) {
+ r = *a;
+ libj2_j2u_nor_ju(&r, b->low);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_nor_ju_to_j2u(a, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_nor_ju_to_j2u(&r, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+}
+
+int
+main(void)
+{
+ unsigned truthtable[] = {1, 0, 0, 0};
+ unsigned i, j;
+ uintmax_t a_bit, b_bit, r_bit;
+ struct libj2_j2u a, b, r, a_saved;
+
+ srand((unsigned)time(NULL));
+
+ for (j = 0; j < 128; j++) {
+ a.high = a.low = 0;
+ b.high = b.low = 0;
+ r.high = r.low = 0;
+ for (i = 0; i < LIBJ2_J2U_BIT; i++) {
+ a_bit = (uintmax_t)(rand() < rand());
+ b_bit = (uintmax_t)(rand() < rand());
+ r_bit = truthtable[a_bit * 2U + b_bit];
+ if (i < LIBJ2_JU_BIT) {
+ a.low |= a_bit << i;
+ b.low |= b_bit << i;
+ r.low |= r_bit << i;
+ } else {
+ a.high |= a_bit << (i - LIBJ2_JU_BIT);
+ b.high |= b_bit << (i - LIBJ2_JU_BIT);
+ r.high |= r_bit << (i - LIBJ2_JU_BIT);
+ }
+ }
+
+ check(&a, &b, &r);
+
+ a_saved = a;
+ a.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[(b.high >> i) & 1U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+ a = a_saved;
+
+ b.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 2U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+
+ r.high = 0U;
+ r.low = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 3U];
+ r.high |= r_bit << i;
+ r_bit = truthtable[((a.low >> i) & 1U) * 3U];
+ r.low |= r_bit << i;
+ }
+ check(&a, &a, &r);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_nor_j2u_to_j2u.c b/libj2_j2u_nor_j2u_to_j2u.c
new file mode 100644
index 0000000..38c30c7
--- /dev/null
+++ b/libj2_j2u_nor_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nor_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nor_j2u.c */
+
+#endif
diff --git a/libj2_j2u_nor_ju.c b/libj2_j2u_nor_ju.c
new file mode 100644
index 0000000..145ec9e
--- /dev/null
+++ b/libj2_j2u_nor_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nor_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nor_j2u.c */
+
+#endif
diff --git a/libj2_j2u_nor_ju_to_j2u.c b/libj2_j2u_nor_ju_to_j2u.c
new file mode 100644
index 0000000..89f797d
--- /dev/null
+++ b/libj2_j2u_nor_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_nor_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nor_j2u.c */
+
+#endif
diff --git a/libj2_j2u_or_j2u.c b/libj2_j2u_or_j2u.c
new file mode 100644
index 0000000..9593807
--- /dev/null
+++ b/libj2_j2u_or_j2u.c
@@ -0,0 +1,140 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_or_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+static void
+check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected)
+{
+ struct libj2_j2u a_saved = *a, b_saved = *b, r;
+
+ r = *a;
+ libj2_j2u_or_j2u(&r, b);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_or_j2u(&r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &a_saved));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_or_j2u_to_j2u(a, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_or_j2u_to_j2u(&r, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_j2u_or_j2u_to_j2u(a, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_or_j2u_to_j2u(a, a, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, a));
+
+ r = *a;
+ libj2_j2u_or_j2u_to_j2u(a, a, a);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+
+ if (a->high == 0U) {
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_or_j2u_to_j2u(a->low, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_ju_or_j2u_to_j2u(a->low, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+
+ if (b->high == 0U) {
+ r = *a;
+ libj2_j2u_or_ju(&r, b->low);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_or_ju_to_j2u(a, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_or_ju_to_j2u(&r, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+}
+
+int
+main(void)
+{
+ unsigned truthtable[] = {0, 1, 1, 1};
+ unsigned i, j;
+ uintmax_t a_bit, b_bit, r_bit;
+ struct libj2_j2u a, b, r, a_saved;
+
+ srand((unsigned)time(NULL));
+
+ for (j = 0; j < 128; j++) {
+ a.high = a.low = 0;
+ b.high = b.low = 0;
+ r.high = r.low = 0;
+ for (i = 0; i < LIBJ2_J2U_BIT; i++) {
+ a_bit = (uintmax_t)(rand() < rand());
+ b_bit = (uintmax_t)(rand() < rand());
+ r_bit = truthtable[a_bit * 2U + b_bit];
+ if (i < LIBJ2_JU_BIT) {
+ a.low |= a_bit << i;
+ b.low |= b_bit << i;
+ r.low |= r_bit << i;
+ } else {
+ a.high |= a_bit << (i - LIBJ2_JU_BIT);
+ b.high |= b_bit << (i - LIBJ2_JU_BIT);
+ r.high |= r_bit << (i - LIBJ2_JU_BIT);
+ }
+ }
+
+ check(&a, &b, &r);
+
+ a_saved = a;
+ a.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[(b.high >> i) & 1U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+ a = a_saved;
+
+ b.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 2U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+
+ r.high = 0U;
+ r.low = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 3U];
+ r.high |= r_bit << i;
+ r_bit = truthtable[((a.low >> i) & 1U) * 3U];
+ r.low |= r_bit << i;
+ }
+ check(&a, &a, &r);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_or_j2u_to_j2u.c b/libj2_j2u_or_j2u_to_j2u.c
new file mode 100644
index 0000000..ab4b29b
--- /dev/null
+++ b/libj2_j2u_or_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_or_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_or_j2u.c */
+
+#endif
diff --git a/libj2_j2u_or_ju.c b/libj2_j2u_or_ju.c
new file mode 100644
index 0000000..81ad912
--- /dev/null
+++ b/libj2_j2u_or_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_or_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_or_j2u.c */
+
+#endif
diff --git a/libj2_j2u_or_ju_to_j2u.c b/libj2_j2u_or_ju_to_j2u.c
new file mode 100644
index 0000000..2707726
--- /dev/null
+++ b/libj2_j2u_or_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_or_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_or_j2u.c */
+
+#endif
diff --git a/libj2_j2u_rdiv_j2u.c b/libj2_j2u_rdiv_j2u.c
new file mode 100644
index 0000000..fd4a4fb
--- /dev/null
+++ b/libj2_j2u_rdiv_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_rdiv_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_rdivmod_j2u.c b/libj2_j2u_rdivmod_j2u.c
new file mode 100644
index 0000000..c856570
--- /dev/null
+++ b/libj2_j2u_rdivmod_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline uintmax_t libj2_j2u_rdivmod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_rdivmod_j2u_to_j2u.c b/libj2_j2u_rdivmod_j2u_to_j2u.c
new file mode 100644
index 0000000..fc04b1a
--- /dev/null
+++ b/libj2_j2u_rdivmod_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_rdivmod_j2u_to_j2u(struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res_q);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_rmod_j2u.c b/libj2_j2u_rmod_j2u.c
new file mode 100644
index 0000000..013e2af
--- /dev/null
+++ b/libj2_j2u_rmod_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_rmod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */
+
+#endif
diff --git a/libj2_j2u_rrot.c b/libj2_j2u_rrot.c
new file mode 100644
index 0000000..4fb3a70
--- /dev/null
+++ b/libj2_j2u_rrot.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_rrot(struct libj2_j2u *a, unsigned b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_lrot.c */
+
+#endif
diff --git a/libj2_j2u_rrot_to_j2u.c b/libj2_j2u_rrot_to_j2u.c
new file mode 100644
index 0000000..a73d220
--- /dev/null
+++ b/libj2_j2u_rrot_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_rrot_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_lrot.c */
+
+#endif
diff --git a/libj2_j2u_rsh.c b/libj2_j2u_rsh.c
new file mode 100644
index 0000000..2a5ed50
--- /dev/null
+++ b/libj2_j2u_rsh.c
@@ -0,0 +1,129 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_rsh(struct libj2_j2u *a, unsigned b);
+/* TODO Add man page */
+
+
+#else
+
+static const char *patterns[] = {
+ "0",
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1010101010101001010100100010101010101011000101101011101001000110",
+ "1110100100100010000010111111011101101001000010001000011110101010",
+ "11111111111100001001011",
+ "0010011011001",
+ "110010001011110100101001010011010111101",
+ NULL
+};
+
+
+static int
+set(struct libj2_j2u *a, const char *bits, size_t leading_zeroes)
+{
+ size_t i, n;
+ int underflow = 0;
+
+ a->high = 0;
+ a->low = 0;
+
+ n = strlen(bits);
+ if (n > LIBJ2_J2U_BIT) {
+ bits = &bits[n - LIBJ2_J2U_BIT];
+ n = LIBJ2_J2U_BIT;
+ }
+
+ while (n && leading_zeroes--)
+ underflow |= bits[--n] == '1';
+
+ for (i = 0; n && i < LIBJ2_JU_BIT; i++)
+ if (bits[--n] == '1')
+ a->low |= (uintmax_t)1 << i;
+
+ for (i = 0; n && i < LIBJ2_JU_BIT; i++)
+ if (bits[--n] == '1')
+ a->high |= (uintmax_t)1 << i;
+
+ return underflow;
+}
+
+
+static void
+check(const char *pattern)
+{
+ struct libj2_j2u a, a_saved, r, expected;
+ unsigned i;
+ int underflows;
+
+ set(&a, pattern, 0);
+ a_saved = a;
+ for (i = 0; i < LIBJ2_J2U_BIT + 8U; i++) {
+ underflows = set(&expected, pattern, i);
+
+ r = a;
+ libj2_j2u_rsh(&r, i);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = a;
+ EXPECT(libj2_j2u_rsh_underflow(&r, i) == underflows);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_rsh_to_j2u(&a, i, &r);
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ EXPECT(libj2_j2u_rsh_to_j2u_underflow(&a, i, &r) == underflows);
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = a;
+ libj2_j2u_rsh_to_j2u(&r, i, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = a;
+ EXPECT(libj2_j2u_rsh_to_j2u_underflow(&r, i, &r) == underflows);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ }
+}
+
+
+int
+main(void)
+{
+ size_t i, j;
+ char pattern[LIBJ2_J2U_BIT + 1U];
+
+ srand((unsigned)time(NULL));
+
+ for (i = 0; patterns[i]; i++)
+ check(patterns[i]);
+
+ for (i = 0; i < 64; i++) {
+ for (j = 0; j < LIBJ2_J2U_BIT; j++)
+ pattern[j] = '0' + (rand() < rand());
+ pattern[LIBJ2_J2U_BIT] = '\0';
+ check(pattern);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_rsh_to_j2u.c b/libj2_j2u_rsh_to_j2u.c
new file mode 100644
index 0000000..f5b63bd
--- /dev/null
+++ b/libj2_j2u_rsh_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_rsh_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_rsh.c */
+
+#endif
diff --git a/libj2_j2u_rsh_to_j2u_underflow.c b/libj2_j2u_rsh_to_j2u_underflow.c
new file mode 100644
index 0000000..c38a006
--- /dev/null
+++ b/libj2_j2u_rsh_to_j2u_underflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_rsh_to_j2u_underflow(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_rsh.c */
+
+#endif
diff --git a/libj2_j2u_rsh_underflow.c b/libj2_j2u_rsh_underflow.c
new file mode 100644
index 0000000..6cc9615
--- /dev/null
+++ b/libj2_j2u_rsh_underflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_rsh_underflow(struct libj2_j2u *a, unsigned b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_rsh.c */
+
+#endif
diff --git a/libj2_j2u_rsub_j2u.c b/libj2_j2u_rsub_j2u.c
new file mode 100644
index 0000000..edae0e7
--- /dev/null
+++ b/libj2_j2u_rsub_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_rsub_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */
+
+#endif
diff --git a/libj2_j2u_rsub_j2u_overflow.c b/libj2_j2u_rsub_j2u_overflow.c
new file mode 100644
index 0000000..e730930
--- /dev/null
+++ b/libj2_j2u_rsub_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_rsub_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */
+
+#endif
diff --git a/libj2_j2u_rsub_ju.c b/libj2_j2u_rsub_ju.c
new file mode 100644
index 0000000..cd3a80f
--- /dev/null
+++ b/libj2_j2u_rsub_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_rsub_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */
+
+#endif
diff --git a/libj2_j2u_rsub_ju_overflow.c b/libj2_j2u_rsub_ju_overflow.c
new file mode 100644
index 0000000..398479f
--- /dev/null
+++ b/libj2_j2u_rsub_ju_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_rsub_ju_overflow(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */
+
+#endif
diff --git a/libj2_j2u_sub_j2u.c b/libj2_j2u_sub_j2u.c
new file mode 100644
index 0000000..6727c71
--- /dev/null
+++ b/libj2_j2u_sub_j2u.c
@@ -0,0 +1,213 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_sub_j2u(struct libj2_j2u *a, const struct libj2_j2u *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_j2u a, b, r, a_saved, b_saved, expected;
+
+ a_saved = (struct libj2_j2u){.high = a_high, .low = a_low};
+ b_saved = (struct libj2_j2u){.high = b_high, .low = b_low};
+ expected = (struct libj2_j2u){.high = r_high, .low = r_low};
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2u_sub_j2u(&a, &b);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ b = b_saved;
+ libj2_j2u_sub_j2u_to_j2u(&a, &b, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2u_sub_j2u_to_j2u(&a, &b, &a);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2u_sub_j2u_to_j2u(&a, &b, &b);
+ EXPECT(libj2_j2u_eq_j2u(&b, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2u_sub_j2u_overflow(&a, &b) == r_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2u_sub_j2u_to_j2u_overflow(&a, &b, &r) == r_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2u_sub_j2u_to_j2u_overflow(&a, &b, &a) == r_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2u_sub_j2u_to_j2u_overflow(&a, &b, &b) == r_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&b, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2u_rsub_j2u(&b, &a);
+ EXPECT(libj2_j2u_eq_j2u(&b, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2u_rsub_j2u_overflow(&b, &a) == r_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&b, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+}
+
+
+static void
+check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low)
+{
+ struct libj2_j2u a, b, r;
+ int overflow;
+
+ a.high = a_high;
+ a.low = a_low;
+ b.high = b_high;
+ b.low = b_low;
+
+ overflow = libj2_j2u_lt_j2u(&a, &b);
+ libj2_minus_j2u(&b);
+ libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, &r);
+ check_(a_high, a_low, b_high, b_low, r.high, r.low, 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_j2u a, a_saved, r;
+
+ a_saved = (struct libj2_j2u){.high = high, .low = low};
+
+ a = a_saved;
+ libj2_j2u_sub_j2u(&a, &a);
+ EXPECT(libj2_j2u_is_zero(&a));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ libj2_j2u_sub_j2u_to_j2u(&a, &a, &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ a = a_saved;
+ libj2_j2u_sub_j2u_to_j2u(&a, &a, &a);
+ EXPECT(libj2_j2u_is_zero(&a));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ EXPECT(libj2_j2u_sub_j2u_overflow(&a, &a) == 0);
+ EXPECT(libj2_j2u_is_zero(&a));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ EXPECT(libj2_j2u_sub_j2u_to_j2u_overflow(&a, &a, &r) == 0);
+ EXPECT(libj2_j2u_is_zero(&r));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ a = a_saved;
+ EXPECT(libj2_j2u_sub_j2u_to_j2u_overflow(&a, &a, &a) == 0);
+ EXPECT(libj2_j2u_is_zero(&a));
+
+ a = a_saved;
+ libj2_j2u_rsub_j2u(&a, &a);
+ EXPECT(libj2_j2u_is_zero(&a));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ EXPECT(libj2_j2u_rsub_j2u_overflow(&a, &a) == 0);
+ EXPECT(libj2_j2u_is_zero(&a));
+}
+
+
+int
+main(void)
+{
+ unsigned i;
+
+ srand((unsigned)time(NULL));
+
+ check_manual(0, 0, 0, 0, 0, 0, 0);
+ check_manual(0, 1, 0, 1, 0, 0, 0);
+ check_manual(0, 1, 0, 0, 0, 1, 0);
+ check_manual(1, 0, 0, 1, 0, UINTMAX_MAX, 0);
+ check_manual(1, 1, 0, 2, 0, UINTMAX_MAX, 0);
+ check_manual(1, 1, 0, 1, 1, 0, 0);
+ check_manual(2, 0, 0, 1, 1, UINTMAX_MAX, 0);
+ check_manual(2, 0, 1, 1, 0, UINTMAX_MAX, 0);
+ check_manual(0, 0, 0, 1, UINTMAX_MAX, UINTMAX_MAX, 1);
+ check_manual(0, UINTMAX_MAX, 0, 1, 0, UINTMAX_MAX - 1U, 0);
+ check_manual(0, UINTMAX_MAX, 0, UINTMAX_MAX, 0, 0, 0);
+ check_manual(UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX, 0, 0, 0);
+
+ for (i = 0; i < 256; i++)
+ check(random_ju(), random_ju(), random_ju(), random_ju());
+
+ check_double(0, 0);
+ check_double(0, UINTMAX_MAX);
+ check_double(UINTMAX_MAX, 0);
+ check_double(UINTMAX_MAX, UINTMAX_MAX);
+ 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, random_ju());
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_sub_j2u_overflow.c b/libj2_j2u_sub_j2u_overflow.c
new file mode 100644
index 0000000..c4e3052
--- /dev/null
+++ b/libj2_j2u_sub_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_sub_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */
+
+#endif
diff --git a/libj2_j2u_sub_j2u_to_j2u.c b/libj2_j2u_sub_j2u_to_j2u.c
new file mode 100644
index 0000000..4f3e0c3
--- /dev/null
+++ b/libj2_j2u_sub_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_sub_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */
+
+#endif
diff --git a/libj2_j2u_sub_j2u_to_j2u_overflow.c b/libj2_j2u_sub_j2u_to_j2u_overflow.c
new file mode 100644
index 0000000..ca518a9
--- /dev/null
+++ b/libj2_j2u_sub_j2u_to_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_sub_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */
+
+#endif
diff --git a/libj2_j2u_sub_ju.c b/libj2_j2u_sub_ju.c
new file mode 100644
index 0000000..b2a3f47
--- /dev/null
+++ b/libj2_j2u_sub_ju.c
@@ -0,0 +1,142 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_sub_ju(struct libj2_j2u *a, uintmax_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
+check(uintmax_t a_high, uintmax_t a_low, uintmax_t b)
+{
+ struct libj2_j2u a, r, expected;
+ int expected_overflow, expected_roverflow;
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ expected_overflow = libj2_j2u_lt_ju(&a, b);
+ expected_roverflow = libj2_ju_lt_j2u(b, &a);
+ libj2_ju_to_j2u(b, &expected);
+ libj2_minus_j2u(&expected);
+ libj2_j2u_add_j2u_overflow(&expected, &a);
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_sub_ju(&a, b);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_j2u_sub_ju_overflow(&a, b) == expected_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_sub_ju_to_j2u(&a, b, &r);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_sub_ju_to_j2u(&a, b, &a);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_j2u_sub_ju_to_j2u_overflow(&a, b, &r) == expected_overflow);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_j2u_sub_ju_to_j2u_overflow(&a, b, &a) == expected_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_ju_sub_j2u_to_j2u(b, &a, &r);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ libj2_minus_j2u(&r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_ju_sub_j2u_to_j2u(b, &a, &a);
+ libj2_minus_j2u(&a);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_rsub_ju(&a, b);
+ libj2_minus_j2u(&a);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_j2u_rsub_ju_overflow(&a, b) == expected_roverflow);
+ libj2_minus_j2u(&a);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_ju_sub_j2u_to_j2u_overflow(b, &a, &r) == expected_roverflow);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ libj2_minus_j2u(&r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_ju_sub_j2u_to_j2u_overflow(b, &a, &a) == expected_roverflow);
+ libj2_minus_j2u(&a);
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+}
+
+
+int
+main(void)
+{
+ unsigned i;
+
+ srand((unsigned)time(NULL));
+
+ check(0, 0, 0);
+ check(0, 0, UINTMAX_MAX);
+ check(UINTMAX_MAX, 0, 0);
+ check(UINTMAX_MAX, 0, UINTMAX_MAX);
+ for (i = 0; i < 256; i++) {
+ check(0, 0, random_ju());
+ check(random_ju(), 0, 0);
+ check(random_ju(), 0, random_ju());
+ check(random_ju(), 0, UINTMAX_MAX);
+ check(UINTMAX_MAX, 0, random_ju());
+ }
+
+ check(0, UINTMAX_MAX, 0);
+ check(0, UINTMAX_MAX, UINTMAX_MAX);
+ check(UINTMAX_MAX, UINTMAX_MAX, 0);
+ check(UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX);
+ for (i = 0; i < 256; i++) {
+ check(0, UINTMAX_MAX, random_ju());
+ check(random_ju(), UINTMAX_MAX, 0);
+ check(random_ju(), UINTMAX_MAX, 1);
+ check(random_ju(), UINTMAX_MAX, random_ju());
+ check(random_ju(), UINTMAX_MAX, UINTMAX_MAX);
+ check(UINTMAX_MAX, UINTMAX_MAX, random_ju());
+ }
+
+ for (i = 0; i < 256; i++)
+ check(random_ju(), random_ju(), random_ju());
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_sub_ju_overflow.c b/libj2_j2u_sub_ju_overflow.c
new file mode 100644
index 0000000..4b675be
--- /dev/null
+++ b/libj2_j2u_sub_ju_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_sub_ju_overflow(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */
+
+#endif
diff --git a/libj2_j2u_sub_ju_to_j2u.c b/libj2_j2u_sub_ju_to_j2u.c
new file mode 100644
index 0000000..78ddc3a
--- /dev/null
+++ b/libj2_j2u_sub_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_sub_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */
+
+#endif
diff --git a/libj2_j2u_sub_ju_to_j2u_overflow.c b/libj2_j2u_sub_ju_to_j2u_overflow.c
new file mode 100644
index 0000000..4f983ab
--- /dev/null
+++ b/libj2_j2u_sub_ju_to_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_sub_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */
+
+#endif
diff --git a/libj2_j2u_test_bit.c b/libj2_j2u_test_bit.c
new file mode 100644
index 0000000..2d4661b
--- /dev/null
+++ b/libj2_j2u_test_bit.c
@@ -0,0 +1,39 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_test_bit(const struct libj2_j2u *a, unsigned b);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u a;
+ unsigned i, j, k;
+
+ for (k = 1; k <= 10; k++) {
+ for (j = 0; j < k; j++) {
+ a.high = 0;
+ a.low = 0;
+ for (i = 0; i < LIBJ2_J2U_BIT; i++) {
+ if (i % k != j)
+ continue;
+ if (i < LIBJ2_JU_BIT)
+ a.low |= (uintmax_t)1 << i;
+ else
+ a.high |= (uintmax_t)1 << (i - LIBJ2_JU_BIT);
+ }
+ for (i = 0; i < LIBJ2_J2U_BIT; i++)
+ EXPECT(libj2_j2u_test_bit(&a, i) == (i % k == j));
+ for (i = LIBJ2_J2U_BIT; i < 2U * LIBJ2_J2U_BIT; i++)
+ EXPECT(libj2_j2u_test_bit(&a, i) == 0);
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_test_high_ju.c b/libj2_j2u_test_high_ju.c
new file mode 100644
index 0000000..0d03b40
--- /dev/null
+++ b/libj2_j2u_test_high_ju.c
@@ -0,0 +1,35 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_test_high_ju(const struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u a;
+ uintmax_t h, i, j;
+
+ for (h = 0; h < 10; h++) {
+ a.low = h;
+ for (i = 0; i < 128; i++) {
+ for (j = 0; j < 128; j++) {
+ a.high = i;
+ if (i & j)
+ EXPECT(libj2_j2u_test_high_ju(&a, j) == 1);
+ else
+ EXPECT(libj2_j2u_test_high_ju(&a, j) == 0);
+ EXPECT(a.low == h);
+ EXPECT(a.high == i);
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_test_j2u.c b/libj2_j2u_test_j2u.c
new file mode 100644
index 0000000..682da56
--- /dev/null
+++ b/libj2_j2u_test_j2u.c
@@ -0,0 +1,90 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_test_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+static void
+set_pattern(struct libj2_j2u *a, unsigned off, unsigned mod)
+{
+ unsigned i;
+ a->high = 0;
+ a->low = 0;
+ for (i = 0; i < LIBJ2_J2U_BIT; i++) {
+ if (i % mod != off)
+ continue;
+ if (i < LIBJ2_JU_BIT)
+ a->low |= (uintmax_t)1 << i;
+ else
+ a->high |= (uintmax_t)1 << (i - LIBJ2_JU_BIT);
+ }
+}
+
+CONST static int
+expected(unsigned a_off, unsigned a_mod, unsigned b_off, unsigned b_mod)
+{
+ unsigned a, b;
+ if (a_off >= a_mod || b_off >= b_mod)
+ return 0;
+ if (a_mod == b_mod)
+ return a_off == b_off;
+ a = a_off;
+ b = b_off;
+ while (a < LIBJ2_J2U_BIT && b < LIBJ2_J2U_BIT) {
+ if (a == b)
+ return 1;
+ if (a < b)
+ a += a_mod;
+ else
+ b += b_mod;
+ }
+ return 0;
+}
+
+int
+main(void)
+{
+ struct libj2_j2u a, b, a_saved, b_saved;
+ unsigned i, j, u, v, ii, jj;
+ unsigned mods[] = {1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 33, 64, 12, LIBJ2_J2U_BIT,
+ LIBJ2_J2U_BIT - 1U, LIBJ2_J2U_BIT - 2U, LIBJ2_J2U_BIT - 3U};
+
+ EXPECT(expected(0, 4, 0, 5) == 1);
+ EXPECT(expected(0, 4, 1, 4) == 0);
+ EXPECT(expected(0, 4, 0, 4) == 1);
+ EXPECT(expected(0, 2, 0, 3) == 1);
+
+ for (ii = 0; ii < sizeof(mods) / sizeof(*mods); ii++) {
+ i = mods[ii];
+ for (u = 0; u <= i; u++) {
+ set_pattern(&a, u, i);
+ a_saved = a;
+ EXPECT(libj2_j2u_test_j2u(&a, &a) == (u < i));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+ b.high = ~a.high;
+ b.low = ~a.low;
+ b_saved = b;
+ EXPECT(libj2_j2u_test_j2u(&a, &b) == 0);
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+ for (jj = 0; jj < sizeof(mods) / sizeof(*mods); jj++) {
+ j = mods[jj];
+ for (v = 0; v <= j; v++) {
+ set_pattern(&b, v, j);
+ b_saved = b;
+ EXPECT(libj2_j2u_test_j2u(&a, &b) == expected(u, i, v, j));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_test_ju.c b/libj2_j2u_test_ju.c
new file mode 100644
index 0000000..5752bf2
--- /dev/null
+++ b/libj2_j2u_test_ju.c
@@ -0,0 +1,35 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_test_ju(const struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u a;
+ uintmax_t h, i, j;
+
+ for (h = 0; h < 10; h++) {
+ a.high = h;
+ for (i = 0; i < 128; i++) {
+ for (j = 0; j < 128; j++) {
+ a.low = i;
+ if (i & j)
+ EXPECT(libj2_j2u_test_ju(&a, j) == 1);
+ else
+ EXPECT(libj2_j2u_test_ju(&a, j) == 0);
+ EXPECT(a.high == h);
+ EXPECT(a.low == i);
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_xnor_j2u.c b/libj2_j2u_xnor_j2u.c
new file mode 100644
index 0000000..98f5298
--- /dev/null
+++ b/libj2_j2u_xnor_j2u.c
@@ -0,0 +1,140 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_xnor_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+static void
+check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected)
+{
+ struct libj2_j2u a_saved = *a, b_saved = *b, r;
+
+ r = *a;
+ libj2_j2u_xnor_j2u(&r, b);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_xnor_j2u(&r, &r);
+ EXPECT(libj2_j2u_is_max(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_xnor_j2u_to_j2u(a, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_xnor_j2u_to_j2u(&r, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_j2u_xnor_j2u_to_j2u(a, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_xnor_j2u_to_j2u(a, a, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_is_max(&r));
+
+ r = *a;
+ libj2_j2u_xnor_j2u_to_j2u(&r, &r, &r);
+ EXPECT(libj2_j2u_is_max(&r));
+
+ if (a->high == 0U) {
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_xnor_j2u_to_j2u(a->low, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_ju_xnor_j2u_to_j2u(a->low, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+
+ if (b->high == 0U) {
+ r = *a;
+ libj2_j2u_xnor_ju(&r, b->low);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_xnor_ju_to_j2u(a, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_xnor_ju_to_j2u(&r, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+}
+
+int
+main(void)
+{
+ unsigned truthtable[] = {1, 0, 0, 1};
+ unsigned i, j;
+ uintmax_t a_bit, b_bit, r_bit;
+ struct libj2_j2u a, b, r, a_saved;
+
+ srand((unsigned)time(NULL));
+
+ for (j = 0; j < 128; j++) {
+ a.high = a.low = 0;
+ b.high = b.low = 0;
+ r.high = r.low = 0;
+ for (i = 0; i < LIBJ2_J2U_BIT; i++) {
+ a_bit = (uintmax_t)(rand() < rand());
+ b_bit = (uintmax_t)(rand() < rand());
+ r_bit = truthtable[a_bit * 2U + b_bit];
+ if (i < LIBJ2_JU_BIT) {
+ a.low |= a_bit << i;
+ b.low |= b_bit << i;
+ r.low |= r_bit << i;
+ } else {
+ a.high |= a_bit << (i - LIBJ2_JU_BIT);
+ b.high |= b_bit << (i - LIBJ2_JU_BIT);
+ r.high |= r_bit << (i - LIBJ2_JU_BIT);
+ }
+ }
+
+ check(&a, &b, &r);
+
+ a_saved = a;
+ a.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[(b.high >> i) & 1U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+ a = a_saved;
+
+ b.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 2U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+
+ r.high = 0U;
+ r.low = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 3U];
+ r.high |= r_bit << i;
+ r_bit = truthtable[((a.low >> i) & 1U) * 3U];
+ r.low |= r_bit << i;
+ }
+ check(&a, &a, &r);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_xnor_j2u_to_j2u.c b/libj2_j2u_xnor_j2u_to_j2u.c
new file mode 100644
index 0000000..111532f
--- /dev/null
+++ b/libj2_j2u_xnor_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_xnor_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_xnor_j2u.c */
+
+#endif
diff --git a/libj2_j2u_xnor_ju.c b/libj2_j2u_xnor_ju.c
new file mode 100644
index 0000000..0d3f871
--- /dev/null
+++ b/libj2_j2u_xnor_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_xnor_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_xnor_j2u.c */
+
+#endif
diff --git a/libj2_j2u_xnor_ju_to_j2u.c b/libj2_j2u_xnor_ju_to_j2u.c
new file mode 100644
index 0000000..ca1bfe6
--- /dev/null
+++ b/libj2_j2u_xnor_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_xnor_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_xnor_j2u.c */
+
+#endif
diff --git a/libj2_j2u_xor_j2u.c b/libj2_j2u_xor_j2u.c
new file mode 100644
index 0000000..c6ee6d1
--- /dev/null
+++ b/libj2_j2u_xor_j2u.c
@@ -0,0 +1,140 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_xor_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+static void
+check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected)
+{
+ struct libj2_j2u a_saved = *a, b_saved = *b, r;
+
+ r = *a;
+ libj2_j2u_xor_j2u(&r, b);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_xor_j2u(&r, &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_xor_j2u_to_j2u(a, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_xor_j2u_to_j2u(&r, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_j2u_xor_j2u_to_j2u(a, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_xor_j2u_to_j2u(a, a, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = *a;
+ libj2_j2u_xor_j2u_to_j2u(&r, &r, &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ if (a->high == 0U) {
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_xor_j2u_to_j2u(a->low, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *b;
+ libj2_ju_xor_j2u_to_j2u(a->low, &r, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+
+ if (b->high == 0U) {
+ r = *a;
+ libj2_j2u_xor_ju(&r, b->low);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_xor_ju_to_j2u(a, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+
+ r = *a;
+ libj2_j2u_xor_ju_to_j2u(&r, b->low, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, expected));
+ }
+}
+
+int
+main(void)
+{
+ unsigned truthtable[] = {0, 1, 1, 0};
+ unsigned i, j;
+ uintmax_t a_bit, b_bit, r_bit;
+ struct libj2_j2u a, b, r, a_saved;
+
+ srand((unsigned)time(NULL));
+
+ for (j = 0; j < 128; j++) {
+ a.high = a.low = 0;
+ b.high = b.low = 0;
+ r.high = r.low = 0;
+ for (i = 0; i < LIBJ2_J2U_BIT; i++) {
+ a_bit = (uintmax_t)(rand() < rand());
+ b_bit = (uintmax_t)(rand() < rand());
+ r_bit = truthtable[a_bit * 2U + b_bit];
+ if (i < LIBJ2_JU_BIT) {
+ a.low |= a_bit << i;
+ b.low |= b_bit << i;
+ r.low |= r_bit << i;
+ } else {
+ a.high |= a_bit << (i - LIBJ2_JU_BIT);
+ b.high |= b_bit << (i - LIBJ2_JU_BIT);
+ r.high |= r_bit << (i - LIBJ2_JU_BIT);
+ }
+ }
+
+ check(&a, &b, &r);
+
+ a_saved = a;
+ a.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[(b.high >> i) & 1U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+ a = a_saved;
+
+ b.high = 0U;
+ r.high = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 2U];
+ r.high |= r_bit << i;
+ }
+ check(&a, &b, &r);
+
+ r.high = 0U;
+ r.low = 0U;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ r_bit = truthtable[((a.high >> i) & 1U) * 3U];
+ r.high |= r_bit << i;
+ r_bit = truthtable[((a.low >> i) & 1U) * 3U];
+ r.low |= r_bit << i;
+ }
+ check(&a, &a, &r);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_j2u_xor_j2u_to_j2u.c b/libj2_j2u_xor_j2u_to_j2u.c
new file mode 100644
index 0000000..bfd0d8c
--- /dev/null
+++ b/libj2_j2u_xor_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_xor_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_xor_j2u.c */
+
+#endif
diff --git a/libj2_j2u_xor_ju.c b/libj2_j2u_xor_ju.c
new file mode 100644
index 0000000..a4db682
--- /dev/null
+++ b/libj2_j2u_xor_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_xor_ju(struct libj2_j2u *a, uintmax_t b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_xor_j2u.c */
+
+#endif
diff --git a/libj2_j2u_xor_ju_to_j2u.c b/libj2_j2u_xor_ju_to_j2u.c
new file mode 100644
index 0000000..6503634
--- /dev/null
+++ b/libj2_j2u_xor_ju_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_xor_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_xor_j2u.c */
+
+#endif
diff --git a/libj2_j2u_zero.c b/libj2_j2u_zero.c
new file mode 100644
index 0000000..ae8f904
--- /dev/null
+++ b/libj2_j2u_zero.c
@@ -0,0 +1,27 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_zero(struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u value = {1, 2};
+
+ libj2_j2u_zero(&value);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == 0);
+
+ libj2_j2u_zero(&value);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == 0);
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_ju_add_j2u_to_j2u.c b/libj2_ju_add_j2u_to_j2u.c
new file mode 100644
index 0000000..60fff73
--- /dev/null
+++ b/libj2_ju_add_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_add_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_ju.c */
+
+#endif
diff --git a/libj2_ju_add_j2u_to_j2u_overflow.c b/libj2_ju_add_j2u_to_j2u_overflow.c
new file mode 100644
index 0000000..d02dfee
--- /dev/null
+++ b/libj2_ju_add_j2u_to_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_add_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_ju.c */
+
+#endif
diff --git a/libj2_ju_add_ju_to_j2u.c b/libj2_ju_add_ju_to_j2u.c
new file mode 100644
index 0000000..7622b84
--- /dev/null
+++ b/libj2_ju_add_ju_to_j2u.c
@@ -0,0 +1,95 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_add_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *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
+self_check(uintmax_t a, uintmax_t b, uintmax_t r_high, uintmax_t r_low)
+{
+ uintmax_t carry = 0;
+ unsigned i;
+
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ carry += (a >> i) & 1U;
+ carry += (b >> i) & 1U;
+ EXPECT((carry & 1U) == ((r_low >> i) & 1U));
+ carry >>= 1;
+ }
+
+ EXPECT(r_high == carry);
+}
+
+
+static void
+check(uintmax_t a, uintmax_t b)
+{
+ struct libj2_j2u r;
+ uintmax_t expected_high = (uintmax_t)(a > UINTMAX_MAX - b);
+ uintmax_t expected_low = a + b;
+
+ self_check(a, b, expected_high, expected_low);
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_add_ju_to_j2u(a, b, &r);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+}
+
+
+static void
+check_manual(uintmax_t a, uintmax_t b, uintmax_t expected_high, uintmax_t expected_low)
+{
+ struct libj2_j2u r;
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_add_ju_to_j2u(a, b, &r);
+ EXPECT(r.high == expected_high);
+ EXPECT(r.low == expected_low);
+ check(a, b);
+}
+
+
+int
+main(void)
+{
+ unsigned i;
+
+ srand((unsigned)time(NULL));
+
+ check_manual(0, 0, 0, 0);
+ check_manual(0, UINTMAX_MAX, 0, UINTMAX_MAX);
+ check_manual(UINTMAX_MAX, 0, 0, UINTMAX_MAX);
+ check_manual(UINTMAX_MAX, 1, 1, 0);
+ check_manual(1, UINTMAX_MAX, 1, 0);
+ check_manual(UINTMAX_MAX, UINTMAX_MAX, 1, UINTMAX_MAX - 1U);
+
+ for (i = 0; i < 256; i++) {
+ check(0, random_ju());
+ check(random_ju(), 0);
+ check(random_ju(), 1);
+ check(random_ju(), random_ju());
+ check(random_ju(), UINTMAX_MAX);
+ check(UINTMAX_MAX, random_ju());
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_ju_and_j2u_to_j2u.c b/libj2_ju_and_j2u_to_j2u.c
new file mode 100644
index 0000000..623d558
--- /dev/null
+++ b/libj2_ju_and_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_and_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_and_j2u.c */
+
+#endif
diff --git a/libj2_ju_cmp_j2u.c b/libj2_ju_cmp_j2u.c
new file mode 100644
index 0000000..e97d9be
--- /dev/null
+++ b/libj2_ju_cmp_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_cmp_j2u(uintmax_t a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_ju_eq_j2u.c b/libj2_ju_eq_j2u.c
new file mode 100644
index 0000000..c13e1b0
--- /dev/null
+++ b/libj2_ju_eq_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_eq_j2u(uintmax_t a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_ju_ge_j2u.c b/libj2_ju_ge_j2u.c
new file mode 100644
index 0000000..0787166
--- /dev/null
+++ b/libj2_ju_ge_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_ge_j2u(uintmax_t a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_ju_gt_j2u.c b/libj2_ju_gt_j2u.c
new file mode 100644
index 0000000..a7a4a2d
--- /dev/null
+++ b/libj2_ju_gt_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_gt_j2u(uintmax_t a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_ju_if_j2u_to_j2u.c b/libj2_ju_if_j2u_to_j2u.c
new file mode 100644
index 0000000..1f035bf
--- /dev/null
+++ b/libj2_ju_if_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_if_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_if_j2u.c */
+
+#endif
diff --git a/libj2_ju_imply_j2u_to_j2u.c b/libj2_ju_imply_j2u_to_j2u.c
new file mode 100644
index 0000000..f710250
--- /dev/null
+++ b/libj2_ju_imply_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_imply_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_imply_j2u.c */
+
+#endif
diff --git a/libj2_ju_le_j2u.c b/libj2_ju_le_j2u.c
new file mode 100644
index 0000000..0e428c2
--- /dev/null
+++ b/libj2_ju_le_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_le_j2u(uintmax_t a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_ju_lrot_to_j2u.c b/libj2_ju_lrot_to_j2u.c
new file mode 100644
index 0000000..25df836
--- /dev/null
+++ b/libj2_ju_lrot_to_j2u.c
@@ -0,0 +1,64 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_lrot_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+static void
+set(struct libj2_j2u *a, const char *pattern, unsigned shift)
+{
+ unsigned i, j = (LIBJ2_J2U_BIT - (shift % LIBJ2_J2U_BIT)) % LIBJ2_J2U_BIT;
+
+ a->high = 0;
+ a->low = 0;
+
+ for (i = 0; i < LIBJ2_JU_BIT; i++, j++)
+ if (pattern[j % LIBJ2_J2U_BIT] == '1')
+ a->low |= (uintmax_t)1 << i;
+
+ for (i = 0; i < LIBJ2_JU_BIT; i++, j++)
+ if (pattern[j % LIBJ2_J2U_BIT] == '1')
+ a->high |= (uintmax_t)1 << i;
+
+}
+
+
+int
+main(void)
+{
+ struct libj2_j2u a, r, expected;
+ char pattern[LIBJ2_J2U_BIT + 1U];
+ unsigned i, j, k;
+
+ srand((unsigned)time(NULL));
+
+ for (i = 0; i < 128U; i++) {
+ for (j = 0; j < LIBJ2_JU_BIT; j++)
+ pattern[j] = '0' + (rand() < rand());
+ memset(&pattern[LIBJ2_JU_BIT], '0', LIBJ2_JU_BIT);
+ pattern[LIBJ2_J2U_BIT] = '\0';
+ set(&a, pattern, 0);
+ EXPECT(a.high == 0);
+ for (j = 0; j <= 2U * LIBJ2_J2U_BIT; j++) {
+ set(&expected, pattern, j);
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_lrot_to_j2u(a.low, j, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ k = 2U * LIBJ2_J2U_BIT - j;
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_rrot_to_j2u(a.low, k, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_ju_lsh_to_j2u.c b/libj2_ju_lsh_to_j2u.c
new file mode 100644
index 0000000..82aa61f
--- /dev/null
+++ b/libj2_ju_lsh_to_j2u.c
@@ -0,0 +1,171 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_lsh_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+static const char *patterns[] = {
+ "0",
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1010101010101001010100100010101010101011000101101011101001000110",
+ "1110100100100010000010111111011101101001000010001000011110101010",
+ "11111111111100001001011",
+ "0010011011001",
+ "110010001011110100101001010011010111101",
+ NULL
+};
+
+
+PURE static size_t
+count_ones(const char *bits)
+{
+ size_t n = strlen(bits);
+ if (n > LIBJ2_J2U_BIT)
+ bits = &bits[n - LIBJ2_J2U_BIT];
+ n = 0;
+ while (*bits)
+ if (*bits++ == '1')
+ n += 1U;
+ return n;
+}
+
+
+static int
+set_j2u(struct libj2_j2u *a, const char *bits, size_t trailing_zeroes)
+{
+ size_t i, n;
+ char *all_bits, *p;
+
+ n = LIBJ2_J2U_BIT + strlen(bits) + trailing_zeroes;
+ EXPECT((all_bits = malloc(n + 1U)));
+ memset(all_bits, '0', LIBJ2_J2U_BIT);
+ p = stpcpy(&all_bits[LIBJ2_J2U_BIT], bits);
+ memset(p, '0', trailing_zeroes);
+ p = &p[trailing_zeroes];
+
+ n = 0;
+
+ a->low = 0;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ if (*--p == '1') {
+ a->low |= (uintmax_t)1 << i;
+ n += 1U;
+ }
+ }
+
+ a->high = 0;
+ for (i = 0; i < LIBJ2_JU_BIT; i++) {
+ if (*--p == '1') {
+ a->high |= (uintmax_t)1 << i;
+ n += 1U;
+ }
+ }
+
+ free(all_bits);
+ return n < count_ones(bits);
+}
+
+
+static int
+set(struct libj2_j2u *a, const char *bits, size_t trailing_zeroes)
+{
+ size_t n = strlen(bits);
+ if (n > LIBJ2_JU_BIT)
+ bits = &bits[n - LIBJ2_JU_BIT];
+ return set_j2u(a, bits, trailing_zeroes);
+}
+
+
+static void
+self_check(void)
+{
+ struct libj2_j2u a = {111, 222};
+ char pattern[LIBJ2_J2U_BIT + 1U];
+ EXPECT(set(&a, "11", 8) == 0);
+ EXPECT(a.high == 0);
+ EXPECT(a.low == (3U << 8));
+ EXPECT(set(&a, "1101", LIBJ2_JU_BIT) == 0);
+ EXPECT(a.high == 13U);
+ EXPECT(a.low == 0);
+ EXPECT(set(&a, "1", LIBJ2_JU_BIT - 1) == 0);
+ EXPECT(a.high == 0);
+ EXPECT(a.low == (UINTMAX_MAX ^ (UINTMAX_MAX >> 1)));
+ EXPECT(set(&a, "111", LIBJ2_JU_BIT - 2) == 0);
+ EXPECT(a.high == 1);
+ EXPECT(a.low == (UINTMAX_MAX ^ (UINTMAX_MAX >> 2)));
+ EXPECT(set(&a, "1", LIBJ2_J2U_BIT) == 1);
+ EXPECT(a.high == 0);
+ EXPECT(a.low == 0);
+ memset(pattern, '1', LIBJ2_J2U_BIT);
+ pattern[LIBJ2_J2U_BIT] = '\0';
+ a = (struct libj2_j2u){111, 222};
+ EXPECT(set(&a, pattern, 0) == 0);
+ EXPECT(a.high == 0);
+ EXPECT(a.low == UINTMAX_MAX);
+}
+
+
+static void
+check(const char *pattern)
+{
+ struct libj2_j2u a, r, expected;
+ unsigned i;
+ int overflows;
+
+ set(&a, pattern, 0);
+ EXPECT(a.high == 0);
+ for (i = 0; i < LIBJ2_J2U_BIT + 8U; i++) {
+ overflows = set(&expected, pattern, i);
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_lsh_to_j2u(a.low, i, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ EXPECT(libj2_ju_lsh_to_j2u_overflow(a.low, i, &r) == overflows);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ }
+}
+
+
+int
+main(void)
+{
+ size_t i, j;
+ char pattern[LIBJ2_JU_BIT + 1U];
+
+ self_check();
+ srand((unsigned)time(NULL));
+
+ for (i = 0; patterns[i]; i++)
+ check(patterns[i]);
+
+ for (i = 0; i < 64; i++) {
+ for (j = 0; j < LIBJ2_JU_BIT; j++)
+ pattern[j] = '0' + (rand() < rand());
+ pattern[LIBJ2_JU_BIT] = '\0';
+ check(pattern);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_ju_lsh_to_j2u_overflow.c b/libj2_ju_lsh_to_j2u_overflow.c
new file mode 100644
index 0000000..c67f0cf
--- /dev/null
+++ b/libj2_ju_lsh_to_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_lsh_to_j2u_overflow(uintmax_t a, unsigned b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_ju_lsh_to_j2u.c */
+
+#endif
diff --git a/libj2_ju_lt_j2u.c b/libj2_ju_lt_j2u.c
new file mode 100644
index 0000000..b9d88e2
--- /dev/null
+++ b/libj2_ju_lt_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_lt_j2u(uintmax_t a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_ju_mul_j2u_to_j2u.c b/libj2_ju_mul_j2u_to_j2u.c
new file mode 100644
index 0000000..03c8a74
--- /dev/null
+++ b/libj2_ju_mul_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_mul_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */
+
+#endif
diff --git a/libj2_ju_mul_j2u_to_j2u_overflow.c b/libj2_ju_mul_j2u_to_j2u_overflow.c
new file mode 100644
index 0000000..876ec5b
--- /dev/null
+++ b/libj2_ju_mul_j2u_to_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_mul_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */
+
+#endif
diff --git a/libj2_ju_mul_ju_to_j2u.c b/libj2_ju_mul_ju_to_j2u.c
new file mode 100644
index 0000000..11daad4
--- /dev/null
+++ b/libj2_ju_mul_ju_to_j2u.c
@@ -0,0 +1,149 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_mul_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *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 void
+mul(uintmax_t a, uintmax_t b, struct libj2_j2u *expected)
+{
+ struct libj2_j2u c;
+ unsigned i;
+
+ libj2_j2u_zero(expected);
+ for (i = 0; i < LIBJ2_JU_BIT; i++, b >>= 1) {
+ if (b & 1U) {
+ libj2_ju_lsh_to_j2u(a, i, &c);
+ libj2_j2u_add_j2u(expected, &c);
+ }
+ }
+}
+
+
+int
+main(void)
+{
+ struct libj2_j2u r, expected;
+ uintmax_t u, v;
+ unsigned i;
+
+ srand((unsigned)time(NULL));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_ju_to_j2u(0, 0, &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_ju_to_j2u(0, 1, &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_ju_to_j2u(0, UINTMAX_MAX, &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_ju_to_j2u(1, 0, &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_ju_to_j2u(UINTMAX_MAX, 0, &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ for (i = 0; i < 32; i++) {
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_ju_to_j2u(0, random_ju(), &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_ju_to_j2u(random_ju(), 0, &r);
+ EXPECT(libj2_j2u_is_zero(&r));
+ }
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_ju_to_j2u(1, 1, &r);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == 1);
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_ju_to_j2u(4, 4, &r);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == 16);
+
+ for (i = 0; i < 32; i++) {
+ r = (struct libj2_j2u){111, 222};
+ v = random_ju();
+ libj2_ju_mul_ju_to_j2u(1, v, &r);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == v);
+
+ r = (struct libj2_j2u){111, 222};
+ v = random_ju();
+ libj2_ju_mul_ju_to_j2u(v, 1, &r);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == v);
+ }
+
+ for (i = 0; i < 32; i++) {
+ u = random_hju();
+ v = random_hju();
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_ju_to_j2u(u, v, &r);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == u * v);
+
+ libj2_ju_mul_ju_to_j2u(v, u, &r);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == u * v);
+ }
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_ju_to_j2u(UINTMAX_MAX, UINTMAX_MAX, &r);
+ EXPECT(r.high == UINTMAX_MAX - 1U);
+ EXPECT(r.low == 1);
+
+ for (i = 0; i < 256; i++) {
+ u = random_ju();
+ v = random_ju();
+
+ mul(u, v, &expected);
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_mul_ju_to_j2u(u, v, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ libj2_ju_mul_ju_to_j2u(v, u, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_ju_nand_j2u_to_j2u.c b/libj2_ju_nand_j2u_to_j2u.c
new file mode 100644
index 0000000..d26055a
--- /dev/null
+++ b/libj2_ju_nand_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_nand_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nand_j2u.c */
+
+#endif
diff --git a/libj2_ju_ne_j2u.c b/libj2_ju_ne_j2u.c
new file mode 100644
index 0000000..556d553
--- /dev/null
+++ b/libj2_ju_ne_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_ne_j2u(uintmax_t a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */
+
+#endif
diff --git a/libj2_ju_nif_j2u_to_j2u.c b/libj2_ju_nif_j2u_to_j2u.c
new file mode 100644
index 0000000..eb9a17d
--- /dev/null
+++ b/libj2_ju_nif_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_nif_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nif_j2u.c */
+
+#endif
diff --git a/libj2_ju_nimply_j2u_to_j2u.c b/libj2_ju_nimply_j2u_to_j2u.c
new file mode 100644
index 0000000..42bc22f
--- /dev/null
+++ b/libj2_ju_nimply_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_nimply_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nimply_j2u.c */
+
+#endif
diff --git a/libj2_ju_nor_j2u_to_j2u.c b/libj2_ju_nor_j2u_to_j2u.c
new file mode 100644
index 0000000..01aec4c
--- /dev/null
+++ b/libj2_ju_nor_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_nor_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_nor_j2u.c */
+
+#endif
diff --git a/libj2_ju_or_j2u_to_j2u.c b/libj2_ju_or_j2u_to_j2u.c
new file mode 100644
index 0000000..85e9c70
--- /dev/null
+++ b/libj2_ju_or_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_or_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_or_j2u.c */
+
+#endif
diff --git a/libj2_ju_rrot_to_j2u.c b/libj2_ju_rrot_to_j2u.c
new file mode 100644
index 0000000..a1051ab
--- /dev/null
+++ b/libj2_ju_rrot_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_rrot_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_ju_lrot_to_j2u.c */
+
+#endif
diff --git a/libj2_ju_rsh_to_j2u.c b/libj2_ju_rsh_to_j2u.c
new file mode 100644
index 0000000..7c5913f
--- /dev/null
+++ b/libj2_ju_rsh_to_j2u.c
@@ -0,0 +1,121 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_rsh_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+static const char *patterns[] = {
+ "0",
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111"
+ "1111111111111111111111111111111111111111111111111111111111111111",
+ "1010101010101001010100100010101010101011000101101011101001000110",
+ "1110100100100010000010111111011101101001000010001000011110101010",
+ "11111111111100001001011",
+ "0010011011001",
+ "110010001011110100101001010011010111101",
+ NULL
+};
+
+
+static int
+set_j2u(struct libj2_j2u *a, const char *bits, size_t leading_zeroes)
+{
+ size_t i, n;
+ int underflow = 0;
+
+ a->high = 0;
+ a->low = 0;
+
+ n = strlen(bits);
+ if (n > LIBJ2_J2U_BIT) {
+ bits = &bits[n - LIBJ2_J2U_BIT];
+ n = LIBJ2_J2U_BIT;
+ }
+
+ while (n && leading_zeroes--)
+ underflow |= bits[--n] == '1';
+
+ for (i = 0; n && i < LIBJ2_JU_BIT; i++)
+ if (bits[--n] == '1')
+ a->low |= (uintmax_t)1 << i;
+
+ for (i = 0; n && i < LIBJ2_JU_BIT; i++)
+ if (bits[--n] == '1')
+ a->high |= (uintmax_t)1 << i;
+
+ return underflow;
+}
+
+
+static int
+set(struct libj2_j2u *a, const char *bits, size_t leading_zeroes)
+{
+ size_t n = strlen(bits);
+ if (n > LIBJ2_JU_BIT)
+ bits = &bits[n - LIBJ2_JU_BIT];
+ return set_j2u(a, bits, leading_zeroes);
+}
+
+
+static void
+check(const char *pattern)
+{
+ struct libj2_j2u a, r, expected;
+ unsigned i;
+ int underflows;
+
+ set(&a, pattern, 0);
+ EXPECT(a.high == 0);
+ for (i = 0; i < LIBJ2_J2U_BIT + 8U; i++) {
+ underflows = set(&expected, pattern, i);
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_rsh_to_j2u(a.low, i, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ EXPECT(libj2_ju_rsh_to_j2u_underflow(a.low, i, &r) == underflows);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ }
+}
+
+
+int
+main(void)
+{
+ size_t i, j;
+ char pattern[LIBJ2_J2U_BIT + 1U];
+
+ srand((unsigned)time(NULL));
+
+ for (i = 0; patterns[i]; i++)
+ check(patterns[i]);
+
+ for (i = 0; i < 64; i++) {
+ for (j = 0; j < LIBJ2_J2U_BIT; j++)
+ pattern[j] = '0' + (rand() < rand());
+ pattern[LIBJ2_J2U_BIT] = '\0';
+ check(pattern);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_ju_rsh_to_j2u_underflow.c b/libj2_ju_rsh_to_j2u_underflow.c
new file mode 100644
index 0000000..89969da
--- /dev/null
+++ b/libj2_ju_rsh_to_j2u_underflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_rsh_to_j2u_underflow(uintmax_t a, unsigned b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_ju_rsh_to_j2u.c */
+
+#endif
diff --git a/libj2_ju_sub_j2u_to_j2u.c b/libj2_ju_sub_j2u_to_j2u.c
new file mode 100644
index 0000000..6e85181
--- /dev/null
+++ b/libj2_ju_sub_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_sub_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */
+
+#endif
diff --git a/libj2_ju_sub_j2u_to_j2u_overflow.c b/libj2_ju_sub_j2u_to_j2u_overflow.c
new file mode 100644
index 0000000..5fef105
--- /dev/null
+++ b/libj2_ju_sub_j2u_to_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_sub_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */
+
+#endif
diff --git a/libj2_ju_sub_ju_to_j2u.c b/libj2_ju_sub_ju_to_j2u.c
new file mode 100644
index 0000000..b61e96a
--- /dev/null
+++ b/libj2_ju_sub_ju_to_j2u.c
@@ -0,0 +1,64 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_sub_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *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 a, uintmax_t b)
+{
+ struct libj2_j2u r, expected;
+ int expected_overflow;
+
+ libj2_ju_to_j2u(a, &expected);
+ expected_overflow = libj2_j2u_sub_ju_overflow(&expected, b);
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_sub_ju_to_j2u(a, b, &r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ EXPECT(libj2_ju_sub_ju_to_j2u_overflow(a, b, &r) == expected_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+}
+
+
+int
+main(void)
+{
+ unsigned i;
+
+ srand((unsigned)time(NULL));
+
+ check(0, 0);
+ check(0, UINTMAX_MAX);
+ check(UINTMAX_MAX, 0);
+ check(UINTMAX_MAX, UINTMAX_MAX);
+ for (i = 0; i < 256; i++) {
+ check(0, random_ju());
+ check(UINTMAX_MAX, random_ju());
+ check(random_ju(), 0);
+ check(random_ju(), random_ju());
+ check(random_ju(), UINTMAX_MAX);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_ju_sub_ju_to_j2u_overflow.c b/libj2_ju_sub_ju_to_j2u_overflow.c
new file mode 100644
index 0000000..cd3c67b
--- /dev/null
+++ b/libj2_ju_sub_ju_to_j2u_overflow.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_sub_ju_to_j2u_overflow(uintmax_t a, uintmax_t b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_ju_sub_ju_to_j2u.c */
+
+#endif
diff --git a/libj2_ju_to_j2u.c b/libj2_ju_to_j2u.c
new file mode 100644
index 0000000..ce3ccb6
--- /dev/null
+++ b/libj2_ju_to_j2u.c
@@ -0,0 +1,29 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_to_j2u(uintmax_t a, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u value;
+
+ value = (struct libj2_j2u){1, 2};
+ libj2_ju_to_j2u(5, &value);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == 5);
+
+ value = (struct libj2_j2u){1, 2};
+ libj2_ju_to_j2u(10, &value);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == 10);
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_ju_xnor_j2u_to_j2u.c b/libj2_ju_xnor_j2u_to_j2u.c
new file mode 100644
index 0000000..5611187
--- /dev/null
+++ b/libj2_ju_xnor_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_xnor_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_xnor_j2u.c */
+
+#endif
diff --git a/libj2_ju_xor_j2u_to_j2u.c b/libj2_ju_xor_j2u_to_j2u.c
new file mode 100644
index 0000000..62e6b40
--- /dev/null
+++ b/libj2_ju_xor_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ju_xor_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_xor_j2u.c */
+
+#endif
diff --git a/libj2_max_j2u.c b/libj2_max_j2u.c
new file mode 100644
index 0000000..edef85c
--- /dev/null
+++ b/libj2_max_j2u.c
@@ -0,0 +1,177 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_max_j2u(struct libj2_j2u *a, ... /*, NULL */);
+/* TODO Add man page */
+
+
+#else
+
+static struct libj2_j2u v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13;
+
+static void
+reset(void)
+{
+ const uintmax_t max = UINTMAX_MAX;
+ v1 = (struct libj2_j2u){0, 0};
+ v2 = (struct libj2_j2u){0, 1};
+ v3 = (struct libj2_j2u){0, 2};
+ v4 = (struct libj2_j2u){0, max - 1};
+ v5 = (struct libj2_j2u){1, 0};
+ v6 = (struct libj2_j2u){1, 1};
+ v7 = (struct libj2_j2u){max - 1, 0};
+ v8 = (struct libj2_j2u){max - 1, 1};
+ v9 = (struct libj2_j2u){max - 1, max};
+ v10 = (struct libj2_j2u){max, 0};
+ v11 = (struct libj2_j2u){max, 1};
+ v12 = (struct libj2_j2u){max, max - 1};
+ v13 = (struct libj2_j2u){max, max};
+}
+
+static void
+expect_untouched(void)
+{
+ const uintmax_t max = UINTMAX_MAX;
+ EXPECT(libj2_j2u_eq_j2u(&v1, &(struct libj2_j2u){0, 0}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v2, &(struct libj2_j2u){0, 1}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v3, &(struct libj2_j2u){0, 2}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v4, &(struct libj2_j2u){0, max - 1}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v5, &(struct libj2_j2u){1, 0}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v6, &(struct libj2_j2u){1, 1}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v7, &(struct libj2_j2u){max - 1, 0}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v8, &(struct libj2_j2u){max - 1, 1}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v9, &(struct libj2_j2u){max - 1, max}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v10, &(struct libj2_j2u){max, 0}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v11, &(struct libj2_j2u){max, 1}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v12, &(struct libj2_j2u){max, max - 1}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v13, &(struct libj2_j2u){max, max}) == 1);
+}
+
+#define HEAD(X, ...) X
+#define TAIL(X, ...) __VA_ARGS__
+
+#define CHECK(MAX, ...)\
+ do {\
+ reset();\
+ \
+ r = *(HEAD(__VA_ARGS__));\
+ libj2_max_j2u(&r, TAIL(__VA_ARGS__));\
+ expect_untouched();\
+ EXPECT(libj2_j2u_eq_j2u(&(MAX), &r));\
+ \
+ p = libj2_max_j2u_return(__VA_ARGS__);\
+ expect_untouched();\
+ EXPECT(p != NULL);\
+ EXPECT(libj2_j2u_eq_j2u(&(MAX), p));\
+ \
+ r = (struct libj2_j2u){111, 222};\
+ libj2_max_j2u_to_j2u(__VA_ARGS__, &r);\
+ expect_untouched();\
+ EXPECT(libj2_j2u_eq_j2u(&(MAX), &r));\
+ } while (0)
+
+int
+main(void)
+{
+ struct libj2_j2u r;
+ const struct libj2_j2u *p;
+
+ CHECK(v1, &v1, NULL);
+ CHECK(v2, &v2, NULL);
+ CHECK(v3, &v3, NULL);
+
+ CHECK(v2, &v1, &v2, NULL);
+ CHECK(v2, &v2, &v1, NULL);
+ CHECK(v3, &v2, &v3, NULL);
+ CHECK(v3, &v3, &v2, NULL);
+ CHECK(v4, &v3, &v4, NULL);
+ CHECK(v4, &v4, &v3, NULL);
+ CHECK(v5, &v4, &v5, NULL);
+ CHECK(v5, &v5, &v4, NULL);
+ CHECK(v6, &v5, &v6, NULL);
+ CHECK(v6, &v6, &v5, NULL);
+ CHECK(v7, &v6, &v7, NULL);
+ CHECK(v7, &v7, &v6, NULL);
+ CHECK(v8, &v7, &v8, NULL);
+ CHECK(v8, &v8, &v7, NULL);
+ CHECK(v9, &v8, &v9, NULL);
+ CHECK(v9, &v9, &v8, NULL);
+ CHECK(v10, &v9, &v10, NULL);
+ CHECK(v10, &v10, &v9, NULL);
+ CHECK(v11, &v10, &v11, NULL);
+ CHECK(v11, &v11, &v10, NULL);
+ CHECK(v12, &v11, &v12, NULL);
+ CHECK(v12, &v12, &v11, NULL);
+ CHECK(v13, &v12, &v13, NULL);
+ CHECK(v13, &v13, &v12, NULL);
+
+ CHECK(v6, &v1, &v2, &v3, &v4, &v5, &v6, NULL);
+ CHECK(v6, &v1, &v2, &v3, &v4, &v6, &v5, NULL);
+ CHECK(v6, &v1, &v2, &v3, &v6, &v4, &v5, NULL);
+ CHECK(v6, &v1, &v2, &v6, &v3, &v4, &v5, NULL);
+ CHECK(v6, &v1, &v6, &v2, &v3, &v4, &v5, NULL);
+ CHECK(v6, &v6, &v1, &v2, &v3, &v4, &v5, NULL);
+
+ CHECK(v6, &v6, &v5, &v4, &v3, &v2, &v1, NULL);
+ CHECK(v6, &v5, &v6, &v4, &v3, &v2, &v1, NULL);
+ CHECK(v6, &v5, &v4, &v6, &v3, &v2, &v1, NULL);
+ CHECK(v6, &v5, &v4, &v3, &v6, &v2, &v1, NULL);
+ CHECK(v6, &v5, &v4, &v3, &v2, &v6, &v1, NULL);
+ CHECK(v6, &v5, &v4, &v3, &v2, &v1, &v6, NULL);
+
+ CHECK(v13, &v1, &v6, &v9, &v11, &v12, &v4, &v8, &v2, &v3, &v10, &v7, &v5, &v13, NULL);
+ CHECK(v13, &v12, &v2, &v11, &v13, &v7, &v4, &v9, &v10, &v1, &v6, &v3, &v8, &v5, NULL);
+ CHECK(v13, &v5, &v13, &v6, &v12, &v8, &v10, &v3, &v9, &v7, &v2, &v11, &v1, &v4, NULL);
+ CHECK(v13, &v4, &v13, &v10, &v11, &v5, &v12, &v9, &v3, &v7, &v6, &v1, &v8, &v2, NULL);
+ CHECK(v13, &v5, &v7, &v6, &v3, &v2, &v1, &v11, &v12, &v8, &v4, &v9, &v13, &v10, NULL);
+ CHECK(v13, &v3, &v8, &v7, &v10, &v1, &v11, &v13, &v12, &v5, &v4, &v2, &v6, &v9, NULL);
+ CHECK(v13, &v11, &v2, &v8, &v3, &v5, &v12, &v4, &v13, &v1, &v10, &v7, &v6, &v9, NULL);
+ CHECK(v13, &v8, &v6, &v2, &v10, &v9, &v13, &v12, &v4, &v7, &v1, &v11, &v5, &v3, NULL);
+ CHECK(v13, &v4, &v8, &v7, &v12, &v13, &v1, &v6, &v11, &v2, &v3, &v10, &v9, &v5, NULL);
+ CHECK(v13, &v13, &v11, &v1, &v4, &v8, &v10, &v12, &v5, &v3, &v2, &v9, &v7, &v6, NULL);
+ CHECK(v13, &v13, &v3, &v12, &v8, &v10, &v11, &v7, &v2, &v4, &v1, &v9, &v6, &v5, NULL);
+ CHECK(v13, &v9, &v8, &v13, &v7, &v1, &v5, &v6, &v11, &v12, &v4, &v3, &v2, &v10, NULL);
+ CHECK(v13, &v9, &v8, &v10, &v6, &v3, &v1, &v12, &v2, &v5, &v11, &v4, &v7, &v13, NULL);
+ CHECK(v13, &v5, &v4, &v12, &v13, &v8, &v7, &v9, &v1, &v6, &v10, &v3, &v2, &v11, NULL);
+ CHECK(v13, &v5, &v4, &v11, &v9, &v8, &v7, &v10, &v6, &v2, &v3, &v1, &v13, &v12, NULL);
+ CHECK(v13, &v12, &v1, &v13, &v10, &v7, &v6, &v5, &v2, &v11, &v4, &v3, &v8, &v9, NULL);
+ CHECK(v13, &v2, &v1, &v8, &v7, &v13, &v5, &v9, &v10, &v6, &v3, &v11, &v12, &v4, NULL);
+ CHECK(v13, &v3, &v7, &v13, &v9, &v6, &v8, &v5, &v12, &v4, &v11, &v2, &v10, &v1, NULL);
+ CHECK(v13, &v12, &v3, &v6, &v5, &v2, &v9, &v4, &v11, &v8, &v10, &v13, &v1, &v7, NULL);
+ CHECK(v13, &v1, &v13, &v7, &v4, &v3, &v12, &v2, &v9, &v5, &v10, &v11, &v6, &v8, NULL);
+ CHECK(v13, &v7, &v3, &v8, &v1, &v2, &v4, &v13, &v5, &v6, &v10, &v9, &v11, &v12, NULL);
+ CHECK(v13, &v2, &v3, &v13, &v8, &v12, &v5, &v11, &v1, &v9, &v10, &v4, &v7, &v6, NULL);
+ CHECK(v13, &v10, &v6, &v7, &v5, &v11, &v9, &v1, &v3, &v13, &v4, &v2, &v8, &v12, NULL);
+ CHECK(v13, &v6, &v9, &v12, &v7, &v2, &v1, &v10, &v4, &v13, &v11, &v3, &v5, &v8, NULL);
+ CHECK(v13, &v5, &v1, &v9, &v6, &v4, &v8, &v7, &v11, &v13, &v3, &v2, &v12, &v10, NULL);
+ CHECK(v13, &v1, &v10, &v11, &v2, &v9, &v12, &v7, &v5, &v3, &v8, &v13, &v6, &v4, NULL);
+ CHECK(v13, &v3, &v10, &v2, &v4, &v8, &v9, &v11, &v7, &v5, &v1, &v13, &v6, &v12, NULL);
+ CHECK(v13, &v8, &v10, &v11, &v6, &v5, &v2, &v9, &v4, &v3, &v13, &v7, &v12, &v1, NULL);
+ CHECK(v13, &v4, &v12, &v11, &v7, &v3, &v13, &v10, &v2, &v5, &v9, &v1, &v6, &v8, NULL);
+ CHECK(v13, &v7, &v13, &v12, &v3, &v4, &v8, &v11, &v9, &v1, &v10, &v6, &v2, &v5, NULL);
+ CHECK(v13, &v5, &v4, &v2, &v1, &v8, &v7, &v13, &v10, &v11, &v3, &v9, &v6, &v12, NULL);
+ CHECK(v13, &v7, &v8, &v10, &v2, &v4, &v1, &v11, &v9, &v12, &v6, &v13, &v5, &v3, NULL);
+ CHECK(v13, &v3, &v7, &v2, &v13, &v5, &v10, &v12, &v6, &v8, &v1, &v11, &v9, &v4, NULL);
+ CHECK(v13, &v12, &v13, &v6, &v9, &v4, &v11, &v8, &v3, &v2, &v1, &v7, &v10, &v5, NULL);
+ CHECK(v13, &v2, &v9, &v10, &v13, &v1, &v3, &v5, &v8, &v7, &v6, &v11, &v4, &v12, NULL);
+ CHECK(v13, &v7, &v5, &v10, &v11, &v3, &v12, &v4, &v9, &v6, &v13, &v1, &v2, &v8, NULL);
+ CHECK(v13, &v1, &v3, &v4, &v8, &v2, &v13, &v11, &v7, &v10, &v5, &v6, &v12, &v9, NULL);
+ CHECK(v13, &v7, &v2, &v1, &v13, &v5, &v10, &v3, &v9, &v6, &v4, &v11, &v8, &v12, NULL);
+ CHECK(v13, &v6, &v5, &v3, &v11, &v8, &v9, &v1, &v12, &v7, &v13, &v4, &v10, &v2, NULL);
+ CHECK(v13, &v13, &v6, &v5, &v4, &v3, &v8, &v1, &v2, &v7, &v9, &v10, &v11, &v12, NULL);
+ CHECK(v13, &v13, &v12, &v4, &v3, &v11, &v6, &v1, &v7, &v10, &v2, &v5, &v9, &v8, NULL);
+ CHECK(v13, &v13, &v6, &v7, &v2, &v8, &v4, &v1, &v5, &v12, &v11, &v3, &v10, &v9, NULL);
+ CHECK(v13, &v13, &v5, &v12, &v11, &v10, &v9, &v2, &v6, &v4, &v8, &v3, &v1, &v7, NULL);
+ CHECK(v13, &v1, &v8, &v7, &v6, &v13, &v9, &v3, &v11, &v10, &v4, &v2, &v12, &v5, NULL);
+ CHECK(v13, &v8, &v9, &v3, &v7, &v1, &v11, &v2, &v13, &v4, &v6, &v12, &v10, &v5, NULL);
+ CHECK(v13, &v4, &v5, &v13, &v2, &v7, &v8, &v9, &v10, &v11, &v1, &v3, &v6, &v12, NULL);
+ CHECK(v13, &v7, &v4, &v11, &v9, &v6, &v12, &v3, &v5, &v10, &v8, &v1, &v2, &v13, NULL);
+ CHECK(v13, &v8, &v9, &v6, &v2, &v11, &v5, &v13, &v1, &v3, &v7, &v10, &v12, &v4, NULL);
+ CHECK(v13, &v10, &v4, &v5, &v6, &v3, &v7, &v13, &v8, &v12, &v2, &v9, &v1, &v11, NULL);
+ CHECK(v13, &v9, &v1, &v3, &v8, &v12, &v5, &v6, &v2, &v10, &v11, &v4, &v7, &v13, NULL);
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_max_j2u_return.c b/libj2_max_j2u_return.c
new file mode 100644
index 0000000..8887178
--- /dev/null
+++ b/libj2_max_j2u_return.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline const struct libj2_j2u *libj2_max_j2u_return(const struct libj2_j2u *a, ... /*, NULL */);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_max_j2u.c */
+
+#endif
diff --git a/libj2_max_j2u_to_j2u.c b/libj2_max_j2u_to_j2u.c
new file mode 100644
index 0000000..2b82706
--- /dev/null
+++ b/libj2_max_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_max_j2u_to_j2u(const struct libj2_j2u *a, ... /*, NULL, struct libj2_j2u *res */);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_max_j2u.c */
+
+#endif
diff --git a/libj2_min_j2u.c b/libj2_min_j2u.c
new file mode 100644
index 0000000..729bbfd
--- /dev/null
+++ b/libj2_min_j2u.c
@@ -0,0 +1,189 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_min_j2u(struct libj2_j2u *a, ... /*, NULL */);
+/* TODO Add man page */
+
+
+#else
+
+static struct libj2_j2u v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13;
+
+static void
+reset(void)
+{
+ const uintmax_t max = UINTMAX_MAX;
+ v1 = (struct libj2_j2u){0, 0};
+ v2 = (struct libj2_j2u){0, 1};
+ v3 = (struct libj2_j2u){0, 2};
+ v4 = (struct libj2_j2u){0, max - 1};
+ v5 = (struct libj2_j2u){1, 0};
+ v6 = (struct libj2_j2u){1, 1};
+ v7 = (struct libj2_j2u){max - 1, 0};
+ v8 = (struct libj2_j2u){max - 1, 1};
+ v9 = (struct libj2_j2u){max - 1, max};
+ v10 = (struct libj2_j2u){max, 0};
+ v11 = (struct libj2_j2u){max, 1};
+ v12 = (struct libj2_j2u){max, max - 1};
+ v13 = (struct libj2_j2u){max, max};
+}
+
+static void
+expect_untouched(void)
+{
+ const uintmax_t max = UINTMAX_MAX;
+ EXPECT(libj2_j2u_eq_j2u(&v1, &(struct libj2_j2u){0, 0}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v2, &(struct libj2_j2u){0, 1}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v3, &(struct libj2_j2u){0, 2}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v4, &(struct libj2_j2u){0, max - 1}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v5, &(struct libj2_j2u){1, 0}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v6, &(struct libj2_j2u){1, 1}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v7, &(struct libj2_j2u){max - 1, 0}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v8, &(struct libj2_j2u){max - 1, 1}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v9, &(struct libj2_j2u){max - 1, max}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v10, &(struct libj2_j2u){max, 0}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v11, &(struct libj2_j2u){max, 1}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v12, &(struct libj2_j2u){max, max - 1}) == 1);
+ EXPECT(libj2_j2u_eq_j2u(&v13, &(struct libj2_j2u){max, max}) == 1);
+}
+
+#define HEAD(X, ...) X
+#define TAIL(X, ...) __VA_ARGS__
+
+#define CHECK(MIN, ...)\
+ do {\
+ reset();\
+ \
+ r = *(HEAD(__VA_ARGS__));\
+ libj2_min_j2u(&r, TAIL(__VA_ARGS__));\
+ expect_untouched();\
+ EXPECT(libj2_j2u_eq_j2u(&(MIN), &r));\
+ \
+ p = libj2_min_j2u_return(__VA_ARGS__);\
+ expect_untouched();\
+ EXPECT(p != NULL);\
+ EXPECT(libj2_j2u_eq_j2u(&(MIN), p));\
+ \
+ r = (struct libj2_j2u){111, 222};\
+ libj2_min_j2u_to_j2u(__VA_ARGS__, &r);\
+ expect_untouched();\
+ EXPECT(libj2_j2u_eq_j2u(&(MIN), &r));\
+ } while (0)
+
+int
+main(void)
+{
+ struct libj2_j2u r;
+ const struct libj2_j2u *p;
+
+ CHECK(v1, &v1, NULL);
+ CHECK(v2, &v2, NULL);
+ CHECK(v3, &v3, NULL);
+
+ CHECK(v1, &v1, &v2, NULL);
+ CHECK(v1, &v2, &v1, NULL);
+ CHECK(v2, &v2, &v3, NULL);
+ CHECK(v2, &v3, &v2, NULL);
+ CHECK(v3, &v3, &v4, NULL);
+ CHECK(v3, &v4, &v3, NULL);
+ CHECK(v4, &v4, &v5, NULL);
+ CHECK(v4, &v5, &v4, NULL);
+ CHECK(v5, &v5, &v6, NULL);
+ CHECK(v5, &v6, &v5, NULL);
+ CHECK(v6, &v6, &v7, NULL);
+ CHECK(v6, &v7, &v6, NULL);
+ CHECK(v7, &v7, &v8, NULL);
+ CHECK(v7, &v8, &v7, NULL);
+ CHECK(v8, &v8, &v9, NULL);
+ CHECK(v8, &v9, &v8, NULL);
+ CHECK(v9, &v9, &v10, NULL);
+ CHECK(v9, &v10, &v9, NULL);
+ CHECK(v10, &v10, &v11, NULL);
+ CHECK(v10, &v11, &v10, NULL);
+ CHECK(v11, &v11, &v12, NULL);
+ CHECK(v11, &v12, &v11, NULL);
+ CHECK(v12, &v12, &v13, NULL);
+ CHECK(v12, &v13, &v12, NULL);
+
+ CHECK(v1, &v1, &v2, &v3, &v4, &v5, &v6, NULL);
+ CHECK(v1, &v2, &v1, &v3, &v4, &v5, &v6, NULL);
+ CHECK(v1, &v2, &v3, &v1, &v4, &v5, &v6, NULL);
+ CHECK(v1, &v2, &v3, &v4, &v1, &v5, &v6, NULL);
+ CHECK(v1, &v2, &v3, &v4, &v5, &v1, &v6, NULL);
+ CHECK(v1, &v2, &v3, &v4, &v5, &v6, &v1, NULL);
+
+ CHECK(v1, &v6, &v5, &v4, &v3, &v2, &v1, NULL);
+ CHECK(v1, &v6, &v5, &v4, &v3, &v1, &v2, NULL);
+ CHECK(v1, &v6, &v5, &v4, &v1, &v3, &v2, NULL);
+ CHECK(v1, &v6, &v5, &v1, &v4, &v3, &v2, NULL);
+ CHECK(v1, &v6, &v1, &v5, &v4, &v3, &v2, NULL);
+ CHECK(v1, &v1, &v6, &v5, &v4, &v3, &v2, NULL);
+
+ CHECK(v2, &v2, &v3, &v4, &v5, &v6, NULL);
+ CHECK(v2, &v3, &v2, &v4, &v5, &v6, NULL);
+ CHECK(v2, &v3, &v4, &v2, &v5, &v6, NULL);
+ CHECK(v2, &v3, &v4, &v5, &v2, &v6, NULL);
+ CHECK(v2, &v3, &v4, &v5, &v6, &v2, NULL);
+
+ CHECK(v2, &v6, &v5, &v4, &v3, &v2, NULL);
+ CHECK(v2, &v6, &v5, &v4, &v2, &v3, NULL);
+ CHECK(v2, &v6, &v5, &v2, &v4, &v3, NULL);
+ CHECK(v2, &v6, &v2, &v5, &v4, &v3, NULL);
+ CHECK(v2, &v2, &v6, &v5, &v4, &v3, NULL);
+
+ CHECK(v2, &v6, &v9, &v11, &v12, &v4, &v8, &v2, &v3, &v10, &v7, &v5, &v13, NULL);
+ CHECK(v2, &v12, &v2, &v11, &v13, &v7, &v4, &v9, &v10, &v6, &v3, &v8, &v5, NULL);
+ CHECK(v2, &v5, &v13, &v6, &v12, &v8, &v10, &v3, &v9, &v7, &v2, &v11, &v4, NULL);
+ CHECK(v2, &v4, &v13, &v10, &v11, &v5, &v12, &v9, &v3, &v7, &v6, &v8, &v2, NULL);
+ CHECK(v2, &v5, &v7, &v6, &v3, &v2, &v11, &v12, &v8, &v4, &v9, &v13, &v10, NULL);
+ CHECK(v2, &v3, &v8, &v7, &v10, &v11, &v13, &v12, &v5, &v4, &v2, &v6, &v9, NULL);
+ CHECK(v2, &v11, &v2, &v8, &v3, &v5, &v12, &v4, &v13, &v10, &v7, &v6, &v9, NULL);
+ CHECK(v2, &v8, &v6, &v2, &v10, &v9, &v13, &v12, &v4, &v7, &v11, &v5, &v3, NULL);
+ CHECK(v2, &v4, &v8, &v7, &v12, &v13, &v6, &v11, &v2, &v3, &v10, &v9, &v5, NULL);
+ CHECK(v2, &v13, &v11, &v4, &v8, &v10, &v12, &v5, &v3, &v2, &v9, &v7, &v6, NULL);
+ CHECK(v2, &v13, &v3, &v12, &v8, &v10, &v11, &v7, &v2, &v4, &v9, &v6, &v5, NULL);
+ CHECK(v2, &v9, &v8, &v13, &v7, &v5, &v6, &v11, &v12, &v4, &v3, &v2, &v10, NULL);
+ CHECK(v2, &v9, &v8, &v10, &v6, &v3, &v12, &v2, &v5, &v11, &v4, &v7, &v13, NULL);
+ CHECK(v2, &v5, &v4, &v12, &v13, &v8, &v7, &v9, &v6, &v10, &v3, &v2, &v11, NULL);
+ CHECK(v2, &v5, &v4, &v11, &v9, &v8, &v7, &v10, &v6, &v2, &v3, &v13, &v12, NULL);
+ CHECK(v2, &v12, &v13, &v10, &v7, &v6, &v5, &v2, &v11, &v4, &v3, &v8, &v9, NULL);
+ CHECK(v2, &v2, &v8, &v7, &v13, &v5, &v9, &v10, &v6, &v3, &v11, &v12, &v4, NULL);
+ CHECK(v2, &v3, &v7, &v13, &v9, &v6, &v8, &v5, &v12, &v4, &v11, &v2, &v10, NULL);
+ CHECK(v2, &v12, &v3, &v6, &v5, &v2, &v9, &v4, &v11, &v8, &v10, &v13, &v7, NULL);
+ CHECK(v2, &v13, &v7, &v4, &v3, &v12, &v2, &v9, &v5, &v10, &v11, &v6, &v8, NULL);
+ CHECK(v2, &v7, &v3, &v8, &v2, &v4, &v13, &v5, &v6, &v10, &v9, &v11, &v12, NULL);
+ CHECK(v2, &v2, &v3, &v13, &v8, &v12, &v5, &v11, &v9, &v10, &v4, &v7, &v6, NULL);
+ CHECK(v2, &v10, &v6, &v7, &v5, &v11, &v9, &v3, &v13, &v4, &v2, &v8, &v12, NULL);
+ CHECK(v2, &v6, &v9, &v12, &v7, &v2, &v10, &v4, &v13, &v11, &v3, &v5, &v8, NULL);
+ CHECK(v2, &v5, &v9, &v6, &v4, &v8, &v7, &v11, &v13, &v3, &v2, &v12, &v10, NULL);
+ CHECK(v2, &v10, &v11, &v2, &v9, &v12, &v7, &v5, &v3, &v8, &v13, &v6, &v4, NULL);
+ CHECK(v2, &v3, &v10, &v2, &v4, &v8, &v9, &v11, &v7, &v5, &v13, &v6, &v12, NULL);
+ CHECK(v2, &v8, &v10, &v11, &v6, &v5, &v2, &v9, &v4, &v3, &v13, &v7, &v12, NULL);
+ CHECK(v2, &v4, &v12, &v11, &v7, &v3, &v13, &v10, &v2, &v5, &v9, &v6, &v8, NULL);
+ CHECK(v2, &v7, &v13, &v12, &v3, &v4, &v8, &v11, &v9, &v10, &v6, &v2, &v5, NULL);
+ CHECK(v2, &v5, &v4, &v2, &v8, &v7, &v13, &v10, &v11, &v3, &v9, &v6, &v12, NULL);
+ CHECK(v2, &v7, &v8, &v10, &v2, &v4, &v11, &v9, &v12, &v6, &v13, &v5, &v3, NULL);
+ CHECK(v2, &v3, &v7, &v2, &v13, &v5, &v10, &v12, &v6, &v8, &v11, &v9, &v4, NULL);
+ CHECK(v2, &v12, &v13, &v6, &v9, &v4, &v11, &v8, &v3, &v2, &v7, &v10, &v5, NULL);
+ CHECK(v2, &v2, &v9, &v10, &v13, &v3, &v5, &v8, &v7, &v6, &v11, &v4, &v12, NULL);
+ CHECK(v2, &v7, &v5, &v10, &v11, &v3, &v12, &v4, &v9, &v6, &v13, &v2, &v8, NULL);
+ CHECK(v2, &v3, &v4, &v8, &v2, &v13, &v11, &v7, &v10, &v5, &v6, &v12, &v9, NULL);
+ CHECK(v2, &v7, &v2, &v13, &v5, &v10, &v3, &v9, &v6, &v4, &v11, &v8, &v12, NULL);
+ CHECK(v2, &v6, &v5, &v3, &v11, &v8, &v9, &v12, &v7, &v13, &v4, &v10, &v2, NULL);
+ CHECK(v2, &v13, &v6, &v5, &v4, &v3, &v8, &v2, &v7, &v9, &v10, &v11, &v12, NULL);
+ CHECK(v2, &v13, &v12, &v4, &v3, &v11, &v6, &v7, &v10, &v2, &v5, &v9, &v8, NULL);
+ CHECK(v2, &v13, &v6, &v7, &v2, &v8, &v4, &v5, &v12, &v11, &v3, &v10, &v9, NULL);
+ CHECK(v2, &v13, &v5, &v12, &v11, &v10, &v9, &v2, &v6, &v4, &v8, &v3, &v7, NULL);
+ CHECK(v2, &v8, &v7, &v6, &v13, &v9, &v3, &v11, &v10, &v4, &v2, &v12, &v5, NULL);
+ CHECK(v2, &v8, &v9, &v3, &v7, &v11, &v2, &v13, &v4, &v6, &v12, &v10, &v5, NULL);
+ CHECK(v2, &v4, &v5, &v13, &v2, &v7, &v8, &v9, &v10, &v11, &v3, &v6, &v12, NULL);
+ CHECK(v2, &v7, &v4, &v11, &v9, &v6, &v12, &v3, &v5, &v10, &v8, &v2, &v13, NULL);
+ CHECK(v2, &v8, &v9, &v6, &v2, &v11, &v5, &v13, &v3, &v7, &v10, &v12, &v4, NULL);
+ CHECK(v2, &v10, &v4, &v5, &v6, &v3, &v7, &v13, &v8, &v12, &v2, &v9, &v11, NULL);
+ CHECK(v2, &v9, &v3, &v8, &v12, &v5, &v6, &v2, &v10, &v11, &v4, &v7, &v13, NULL);
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_min_j2u_return.c b/libj2_min_j2u_return.c
new file mode 100644
index 0000000..38bc3f3
--- /dev/null
+++ b/libj2_min_j2u_return.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline const struct libj2_j2u *libj2_min_j2u_return(const struct libj2_j2u *a, ... /*, NULL */);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_min_j2u.c */
+
+#endif
diff --git a/libj2_min_j2u_to_j2u.c b/libj2_min_j2u_to_j2u.c
new file mode 100644
index 0000000..3e0d187
--- /dev/null
+++ b/libj2_min_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_min_j2u_to_j2u(const struct libj2_j2u *a, ... /*, NULL, struct libj2_j2u *res */);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_min_j2u.c */
+
+#endif
diff --git a/libj2_minus_j2u.c b/libj2_minus_j2u.c
new file mode 100644
index 0000000..c0609f9
--- /dev/null
+++ b/libj2_minus_j2u.c
@@ -0,0 +1,79 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_minus_j2u(struct libj2_j2u *a);
+/* 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
+minus_j2u(struct libj2_j2u *a)
+{
+ struct libj2_j2u r, a_saved = *a;
+ r = (struct libj2_j2u){111, 222};
+ libj2_minus_j2u_to_j2u(a, &r);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ libj2_minus_j2u(a);
+ EXPECT(libj2_j2u_eq_j2u(a, &r));
+}
+
+
+int
+main(void)
+{
+ unsigned i;
+ struct libj2_j2u a, b;
+ uintmax_t v;
+
+ libj2_j2u_zero(&a);
+ minus_j2u(&a);
+ EXPECT(libj2_j2u_is_zero(&a));
+
+ a = (struct libj2_j2u){.high = 0, .low = 1};
+ minus_j2u(&a);
+ EXPECT(libj2_j2u_eq_j2u(&a, &(struct libj2_j2u){.high = UINTMAX_MAX, .low = UINTMAX_MAX}));
+
+ a = (struct libj2_j2u){.high = UINTMAX_MAX, .low = UINTMAX_MAX};
+ minus_j2u(&a);
+ EXPECT(libj2_j2u_eq_j2u(&a, &(struct libj2_j2u){.high = 0, .low = 1}));
+
+ for (i = 0; i < 256; i++) {
+ a.high = 0;
+ a.low = v = random_ju();
+ minus_j2u(&a);
+ EXPECT(a.high == UINTMAX_MAX);
+ EXPECT(a.low == 0U - v);
+
+ a.high = UINTMAX_MAX;
+ a.low = v = random_ju();
+ minus_j2u(&a);
+ EXPECT(a.high == 0);
+ EXPECT(a.low == 0U - v);
+ }
+
+ for (i = 0; i < 256; i++) {
+ a.high = b.high = random_ju();
+ a.low = b.low = random_ju();
+ minus_j2u(&a);
+ libj2_j2u_add_j2u(&a, &b);
+ EXPECT(libj2_j2u_is_zero(&a));
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_minus_j2u_to_j2u.c b/libj2_minus_j2u_to_j2u.c
new file mode 100644
index 0000000..1198d4e
--- /dev/null
+++ b/libj2_minus_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_minus_j2u_to_j2u(const struct libj2_j2u *a, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_minus_j2u.c */
+
+#endif
diff --git a/libj2_not_j2u.c b/libj2_not_j2u.c
new file mode 100644
index 0000000..2a59b50
--- /dev/null
+++ b/libj2_not_j2u.c
@@ -0,0 +1,34 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_not_j2u(struct libj2_j2u *a);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u a;
+
+ a.high = 0;
+ a.low = 0;
+ libj2_not_j2u(&a);
+ EXPECT(a.high == UINTMAX_MAX);
+ EXPECT(a.low == UINTMAX_MAX);
+ libj2_not_j2u(&a);
+ EXPECT(a.high == 0);
+ EXPECT(a.low == 0);
+
+ a.high = UINTMAX_C(0x45FF23);
+ a.low = UINTMAX_C(0x5245FBA4);
+ libj2_not_j2u(&a);
+ EXPECT(a.high == ~(uintmax_t)UINTMAX_C(0x45FF23));
+ EXPECT(a.low == ~(uintmax_t)UINTMAX_C(0x5245FBA4));
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_not_j2u_to_j2u.c b/libj2_not_j2u_to_j2u.c
new file mode 100644
index 0000000..6a19c17
--- /dev/null
+++ b/libj2_not_j2u_to_j2u.c
@@ -0,0 +1,46 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_not_j2u_to_j2u(const struct libj2_j2u *a, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u a, r, a_saved;
+
+ a.high = 0;
+ a.low = 0;
+ a_saved = a;
+ r = (struct libj2_j2u){111, 222};
+ libj2_not_j2u_to_j2u(&a, &r);
+ EXPECT(r.high == UINTMAX_MAX);
+ EXPECT(r.low == UINTMAX_MAX);
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ a.high = UINTMAX_MAX;
+ a.low = UINTMAX_MAX;
+ a_saved = a;
+ r = (struct libj2_j2u){111, 222};
+ libj2_not_j2u_to_j2u(&a, &r);
+ EXPECT(r.high == 0);
+ EXPECT(r.low == 0);
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ a.high = UINTMAX_C(0x45FF23);
+ a.low = UINTMAX_C(0x5245FBA4);
+ a_saved = a;
+ r = (struct libj2_j2u){111, 222};
+ libj2_not_j2u_to_j2u(&a, &r);
+ EXPECT(r.high == ~(uintmax_t)UINTMAX_C(0x45FF23));
+ EXPECT(r.low == ~(uintmax_t)UINTMAX_C(0x5245FBA4));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_not_ju_to_j2u.c b/libj2_not_ju_to_j2u.c
new file mode 100644
index 0000000..aee0715
--- /dev/null
+++ b/libj2_not_ju_to_j2u.c
@@ -0,0 +1,34 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_not_ju_to_j2u(uintmax_t a, struct libj2_j2u *res);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u r;
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_not_ju_to_j2u(0, &r);
+ EXPECT(r.high == UINTMAX_MAX);
+ EXPECT(r.low == UINTMAX_MAX);
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_not_ju_to_j2u(UINTMAX_MAX, &r);
+ EXPECT(r.high == UINTMAX_MAX);
+ EXPECT(r.low == 0);
+
+ r = (struct libj2_j2u){111, 222};
+ libj2_not_ju_to_j2u(UINTMAX_C(0x5245FBA4), &r);
+ EXPECT(r.high == UINTMAX_MAX);
+ EXPECT(r.low == ~(uintmax_t)UINTMAX_C(0x5245FBA4));
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_sgn_j2u.c b/libj2_sgn_j2u.c
new file mode 100644
index 0000000..d20aa6f
--- /dev/null
+++ b/libj2_sgn_j2u.c
@@ -0,0 +1,197 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_sgn_j2u(const struct libj2_j2u *a);
+/* TODO Add man page */
+
+
+#else
+
+int
+main(void)
+{
+ struct libj2_j2u value;
+ uintmax_t a, b;
+ int i, j;
+
+ for (i = 0; i < CHAR_BIT * (int)sizeof(uintmax_t); i++) {
+ for (j = 0; j < CHAR_BIT * (int)sizeof(uintmax_t); j++) {
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b = (uintmax_t)(j + 1);
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b = (uintmax_t)(j + 1);
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b = (uintmax_t)1 << j;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b = (uintmax_t)1 << j;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b = ~((uintmax_t)(j + 1));
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b = ~((uintmax_t)(j + 1));
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b = ~((uintmax_t)1 << j);
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b = ~((uintmax_t)1 << j);
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+ }
+
+ value.high = 0;
+ value.low = a = (uintmax_t)(i + 1);
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = 0;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = (uintmax_t)1 << i;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = 0;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = ~((uintmax_t)(i + 1));
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = 0;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = 0;
+ value.low = a = ~((uintmax_t)1 << i);
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = 0;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ b = ~(uintmax_t)0;
+
+ value.high = b;
+ value.low = a = (uintmax_t)(i + 1);
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)(i + 1);
+ value.low = b;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = (uintmax_t)1 << i;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = (uintmax_t)1 << i;
+ value.low = b;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = ~((uintmax_t)(i + 1));
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)(i + 1));
+ value.low = b;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+
+ value.high = b;
+ value.low = a = ~((uintmax_t)1 << i);
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == b);
+ EXPECT(value.low == a);
+
+ value.high = a = ~((uintmax_t)1 << i);
+ value.low = b;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == b);
+ }
+
+ value.high = 0;
+ value.low = 0;
+ EXPECT(libj2_sgn_j2u(&value) == 0);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == 0);
+
+ a = ~(uintmax_t)0;
+
+ value.high = 0;
+ value.low = a;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == 0);
+ EXPECT(value.low == a);
+
+ value.high = a;
+ value.low = 0;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == 0);
+
+ value.high = a;
+ value.low = a;
+ EXPECT(libj2_sgn_j2u(&value) == +1);
+ EXPECT(value.high == a);
+ EXPECT(value.low == a);
+
+ return 0;
+}
+
+#endif
diff --git a/libj2_vmax_j2u.c b/libj2_vmax_j2u.c
new file mode 100644
index 0000000..1296902
--- /dev/null
+++ b/libj2_vmax_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_vmax_j2u(struct libj2_j2u *a, va_list args);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested via libj2_max_j2u */
+
+#endif
diff --git a/libj2_vmax_j2u_return.c b/libj2_vmax_j2u_return.c
new file mode 100644
index 0000000..b512ccd
--- /dev/null
+++ b/libj2_vmax_j2u_return.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline const struct libj2_j2u *libj2_vmax_j2u_return(const struct libj2_j2u *a, va_list args);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested via libj2_max_j2u_return */
+
+#endif
diff --git a/libj2_vmax_j2u_to_j2u.c b/libj2_vmax_j2u_to_j2u.c
new file mode 100644
index 0000000..9b421dc
--- /dev/null
+++ b/libj2_vmax_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_vmax_j2u_to_j2u(const struct libj2_j2u *a, va_list args);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested via libj2_vmax_j2u_to_j2u */
+
+#endif
diff --git a/libj2_vmin_j2u.c b/libj2_vmin_j2u.c
new file mode 100644
index 0000000..c723719
--- /dev/null
+++ b/libj2_vmin_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_vmin_j2u(struct libj2_j2u *a, va_list args);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested via libj2_min_j2u */
+
+#endif
diff --git a/libj2_vmin_j2u_return.c b/libj2_vmin_j2u_return.c
new file mode 100644
index 0000000..e10fb23
--- /dev/null
+++ b/libj2_vmin_j2u_return.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline const struct libj2_j2u *libj2_vmin_j2u_return(const struct libj2_j2u *a, va_list args);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested via libj2_min_j2u_return */
+
+#endif
diff --git a/libj2_vmin_j2u_to_j2u.c b/libj2_vmin_j2u_to_j2u.c
new file mode 100644
index 0000000..021e5ee
--- /dev/null
+++ b/libj2_vmin_j2u_to_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_vmin_j2u_to_j2u(const struct libj2_j2u *a, va_list args);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested via libj2_vmin_j2u_to_j2u */
+
+#endif
diff --git a/mk/linux.mk b/mk/linux.mk
new file mode 100644
index 0000000..ad58f69
--- /dev/null
+++ b/mk/linux.mk
@@ -0,0 +1,6 @@
+LIBEXT = so
+LIBFLAGS = -shared -Wl,-soname,lib$(LIB_NAME).$(LIBEXT).$(LIB_MAJOR)
+LIBMAJOREXT = $(LIBEXT).$(LIB_MAJOR)
+LIBMINOREXT = $(LIBEXT).$(LIB_VERSION)
+
+FIX_INSTALL_NAME = :
diff --git a/mk/macos.mk b/mk/macos.mk
new file mode 100644
index 0000000..ca39133
--- /dev/null
+++ b/mk/macos.mk
@@ -0,0 +1,6 @@
+LIBEXT = dylib
+LIBFLAGS = -dynamiclib -Wl,-compatibility_version,$(LIB_MAJOR) -Wl,-current_version,$(LIB_VERSION)
+LIBMAJOREXT = $(LIB_MAJOR).$(LIBEXT)
+LIBMINOREXT = $(LIB_VERSION).$(LIBEXT)
+
+FIX_INSTALL_NAME = install_name_tool -id "$(PREFIX)/lib/libj2.$(LIBMAJOREXT)"
diff --git a/mk/windows.mk b/mk/windows.mk
new file mode 100644
index 0000000..ed5ec8d
--- /dev/null
+++ b/mk/windows.mk
@@ -0,0 +1,6 @@
+LIBEXT = dll
+LIBFLAGS = -shared
+LIBMAJOREXT = $(LIB_MAJOR).$(LIBEXT)
+LIBMINOREXT = $(LIB_VERSION).$(LIBEXT)
+
+FIX_INSTALL_NAME = :