From 2bf851de6dd3a64f91a72a9afba2b3637dbbe154 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Thu, 4 Dec 2025 19:25:47 +0100 Subject: First commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- .gitignore | 15 + LICENSE | 15 + Makefile | 300 ++++++++++ README | 15 + common.h | 29 + config.mk | 8 + libj2.7 | 20 + libj2.h | 62 ++ libj2/addition.h | 313 ++++++++++ libj2/bit-shifting.h | 573 ++++++++++++++++++ libj2/bitwise-logic.h | 980 +++++++++++++++++++++++++++++++ libj2/constants.h | 94 +++ libj2/constructors.h | 24 + libj2/division.h | 534 +++++++++++++++++ libj2/multiplication.h | 366 ++++++++++++ libj2/sign-shifting.h | 43 ++ libj2/signum.h | 45 ++ libj2/subtraction.h | 493 ++++++++++++++++ libj2/unsigned-comparsion.h | 774 ++++++++++++++++++++++++ libj2_j2u_add_j2u.c | 201 +++++++ libj2_j2u_add_j2u_overflow.c | 13 + libj2_j2u_add_j2u_to_j2u.c | 13 + libj2_j2u_add_j2u_to_j2u_overflow.c | 13 + libj2_j2u_add_ju.c | 301 ++++++++++ libj2_j2u_add_ju_overflow.c | 13 + libj2_j2u_add_ju_to_j2u.c | 13 + libj2_j2u_add_ju_to_j2u_overflow.c | 13 + libj2_j2u_and_j2u.c | 140 +++++ libj2_j2u_and_j2u_to_j2u.c | 13 + libj2_j2u_and_ju.c | 13 + libj2_j2u_and_ju_to_j2u.c | 13 + libj2_j2u_cmp_j2u.c | 200 +++++++ libj2_j2u_cmp_ju.c | 145 +++++ libj2_j2u_div_j2u.c | 13 + libj2_j2u_div_j2u_return.c | 13 + libj2_j2u_div_j2u_to_j2u.c | 13 + libj2_j2u_div_ju.c | 13 + libj2_j2u_div_ju_return.c | 13 + libj2_j2u_div_ju_to_j2u.c | 13 + libj2_j2u_divmod_j2u.c | 13 + libj2_j2u_divmod_j2u_to_j2u.c | 389 ++++++++++++ libj2_j2u_divmod_j2u_to_j2u_j2u.c | 14 + libj2_j2u_divmod_ju.c | 13 + libj2_j2u_divmod_ju_to_j2u.c | 13 + libj2_j2u_divmod_ju_to_j2u_j2u.c | 13 + libj2_j2u_eq_j2u.c | 13 + libj2_j2u_eq_ju.c | 13 + libj2_j2u_ge_j2u.c | 13 + libj2_j2u_ge_ju.c | 13 + libj2_j2u_gt_j2u.c | 13 + libj2_j2u_gt_ju.c | 13 + libj2_j2u_if_j2u.c | 140 +++++ libj2_j2u_if_j2u_to_j2u.c | 13 + libj2_j2u_if_ju.c | 13 + libj2_j2u_if_ju_to_j2u.c | 13 + libj2_j2u_imply_j2u.c | 140 +++++ libj2_j2u_imply_j2u_to_j2u.c | 13 + libj2_j2u_imply_ju.c | 13 + libj2_j2u_imply_ju_to_j2u.c | 13 + libj2_j2u_is_max.c | 197 +++++++ libj2_j2u_is_min.c | 197 +++++++ libj2_j2u_is_positive.c | 197 +++++++ libj2_j2u_is_zero.c | 197 +++++++ libj2_j2u_le_j2u.c | 13 + libj2_j2u_le_ju.c | 13 + libj2_j2u_lrot.c | 81 +++ libj2_j2u_lrot_to_j2u.c | 13 + libj2_j2u_lsh.c | 172 ++++++ libj2_j2u_lsh_overflow.c | 13 + libj2_j2u_lsh_to_j2u.c | 13 + libj2_j2u_lsh_to_j2u_overflow.c | 13 + libj2_j2u_lt_j2u.c | 13 + libj2_j2u_lt_ju.c | 13 + libj2_j2u_max.c | 27 + libj2_j2u_max_j2u.c | 13 + libj2_j2u_max_j2u_to_j2u.c | 13 + libj2_j2u_max_ju.c | 13 + libj2_j2u_max_ju_to_j2u.c | 13 + libj2_j2u_min.c | 27 + libj2_j2u_min_j2u.c | 13 + libj2_j2u_min_j2u_to_j2u.c | 13 + libj2_j2u_min_ju.c | 13 + libj2_j2u_min_ju_to_j2u.c | 13 + libj2_j2u_mod_j2u.c | 13 + libj2_j2u_mod_j2u_to_j2u.c | 13 + libj2_j2u_mod_ju.c | 13 + libj2_j2u_mod_ju_to_j2u.c | 13 + libj2_j2u_mul_j2u.c | 13 + libj2_j2u_mul_j2u_destructive.c | 267 +++++++++ libj2_j2u_mul_j2u_overflow.c | 13 + libj2_j2u_mul_j2u_overflow_destructive.c | 13 + libj2_j2u_mul_j2u_to_j2u.c | 13 + libj2_j2u_mul_j2u_to_j2u_overflow.c | 13 + libj2_j2u_mul_ju.c | 197 +++++++ libj2_j2u_mul_ju_overflow.c | 13 + libj2_j2u_mul_ju_to_j2u.c | 13 + libj2_j2u_mul_ju_to_j2u_overflow.c | 13 + libj2_j2u_nand_j2u.c | 143 +++++ libj2_j2u_nand_j2u_to_j2u.c | 13 + libj2_j2u_nand_ju.c | 13 + libj2_j2u_nand_ju_to_j2u.c | 13 + libj2_j2u_ne_j2u.c | 13 + libj2_j2u_ne_ju.c | 13 + libj2_j2u_nif_j2u.c | 140 +++++ libj2_j2u_nif_j2u_to_j2u.c | 13 + libj2_j2u_nif_ju.c | 13 + libj2_j2u_nif_ju_to_j2u.c | 13 + libj2_j2u_nimply_j2u.c | 140 +++++ libj2_j2u_nimply_j2u_to_j2u.c | 13 + libj2_j2u_nimply_ju.c | 13 + libj2_j2u_nimply_ju_to_j2u.c | 13 + libj2_j2u_nor_j2u.c | 143 +++++ libj2_j2u_nor_j2u_to_j2u.c | 13 + libj2_j2u_nor_ju.c | 13 + libj2_j2u_nor_ju_to_j2u.c | 13 + libj2_j2u_or_j2u.c | 140 +++++ libj2_j2u_or_j2u_to_j2u.c | 13 + libj2_j2u_or_ju.c | 13 + libj2_j2u_or_ju_to_j2u.c | 13 + libj2_j2u_rdiv_j2u.c | 13 + libj2_j2u_rdivmod_j2u.c | 13 + libj2_j2u_rdivmod_j2u_to_j2u.c | 13 + libj2_j2u_rmod_j2u.c | 13 + libj2_j2u_rrot.c | 13 + libj2_j2u_rrot_to_j2u.c | 13 + libj2_j2u_rsh.c | 129 ++++ libj2_j2u_rsh_to_j2u.c | 13 + libj2_j2u_rsh_to_j2u_underflow.c | 13 + libj2_j2u_rsh_underflow.c | 13 + libj2_j2u_rsub_j2u.c | 13 + libj2_j2u_rsub_j2u_overflow.c | 13 + libj2_j2u_rsub_ju.c | 13 + libj2_j2u_rsub_ju_overflow.c | 13 + libj2_j2u_sub_j2u.c | 213 +++++++ libj2_j2u_sub_j2u_overflow.c | 13 + libj2_j2u_sub_j2u_to_j2u.c | 13 + libj2_j2u_sub_j2u_to_j2u_overflow.c | 13 + libj2_j2u_sub_ju.c | 142 +++++ libj2_j2u_sub_ju_overflow.c | 13 + libj2_j2u_sub_ju_to_j2u.c | 13 + libj2_j2u_sub_ju_to_j2u_overflow.c | 13 + libj2_j2u_test_bit.c | 39 ++ libj2_j2u_test_high_ju.c | 35 ++ libj2_j2u_test_j2u.c | 90 +++ libj2_j2u_test_ju.c | 35 ++ libj2_j2u_xnor_j2u.c | 140 +++++ libj2_j2u_xnor_j2u_to_j2u.c | 13 + libj2_j2u_xnor_ju.c | 13 + libj2_j2u_xnor_ju_to_j2u.c | 13 + libj2_j2u_xor_j2u.c | 140 +++++ libj2_j2u_xor_j2u_to_j2u.c | 13 + libj2_j2u_xor_ju.c | 13 + libj2_j2u_xor_ju_to_j2u.c | 13 + libj2_j2u_zero.c | 27 + libj2_ju_add_j2u_to_j2u.c | 13 + libj2_ju_add_j2u_to_j2u_overflow.c | 13 + libj2_ju_add_ju_to_j2u.c | 95 +++ libj2_ju_and_j2u_to_j2u.c | 13 + libj2_ju_cmp_j2u.c | 13 + libj2_ju_eq_j2u.c | 13 + libj2_ju_ge_j2u.c | 13 + libj2_ju_gt_j2u.c | 13 + libj2_ju_if_j2u_to_j2u.c | 13 + libj2_ju_imply_j2u_to_j2u.c | 13 + libj2_ju_le_j2u.c | 13 + libj2_ju_lrot_to_j2u.c | 64 ++ libj2_ju_lsh_to_j2u.c | 171 ++++++ libj2_ju_lsh_to_j2u_overflow.c | 13 + libj2_ju_lt_j2u.c | 13 + libj2_ju_mul_j2u_to_j2u.c | 13 + libj2_ju_mul_j2u_to_j2u_overflow.c | 13 + libj2_ju_mul_ju_to_j2u.c | 149 +++++ libj2_ju_nand_j2u_to_j2u.c | 13 + libj2_ju_ne_j2u.c | 13 + libj2_ju_nif_j2u_to_j2u.c | 13 + libj2_ju_nimply_j2u_to_j2u.c | 13 + libj2_ju_nor_j2u_to_j2u.c | 13 + libj2_ju_or_j2u_to_j2u.c | 13 + libj2_ju_rrot_to_j2u.c | 13 + libj2_ju_rsh_to_j2u.c | 121 ++++ libj2_ju_rsh_to_j2u_underflow.c | 13 + libj2_ju_sub_j2u_to_j2u.c | 13 + libj2_ju_sub_j2u_to_j2u_overflow.c | 13 + libj2_ju_sub_ju_to_j2u.c | 64 ++ libj2_ju_sub_ju_to_j2u_overflow.c | 13 + libj2_ju_to_j2u.c | 29 + libj2_ju_xnor_j2u_to_j2u.c | 13 + libj2_ju_xor_j2u_to_j2u.c | 13 + libj2_max_j2u.c | 177 ++++++ libj2_max_j2u_return.c | 13 + libj2_max_j2u_to_j2u.c | 13 + libj2_min_j2u.c | 189 ++++++ libj2_min_j2u_return.c | 13 + libj2_min_j2u_to_j2u.c | 13 + libj2_minus_j2u.c | 79 +++ libj2_minus_j2u_to_j2u.c | 13 + libj2_not_j2u.c | 34 ++ libj2_not_j2u_to_j2u.c | 46 ++ libj2_not_ju_to_j2u.c | 34 ++ libj2_sgn_j2u.c | 197 +++++++ libj2_vmax_j2u.c | 13 + libj2_vmax_j2u_return.c | 13 + libj2_vmax_j2u_to_j2u.c | 13 + libj2_vmin_j2u.c | 13 + libj2_vmin_j2u_return.c | 13 + libj2_vmin_j2u_to_j2u.c | 13 + mk/linux.mk | 6 + mk/macos.mk | 6 + mk/windows.mk | 6 + 209 files changed, 12902 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README create mode 100644 common.h create mode 100644 config.mk create mode 100644 libj2.7 create mode 100644 libj2.h create mode 100644 libj2/addition.h create mode 100644 libj2/bit-shifting.h create mode 100644 libj2/bitwise-logic.h create mode 100644 libj2/constants.h create mode 100644 libj2/constructors.h create mode 100644 libj2/division.h create mode 100644 libj2/multiplication.h create mode 100644 libj2/sign-shifting.h create mode 100644 libj2/signum.h create mode 100644 libj2/subtraction.h create mode 100644 libj2/unsigned-comparsion.h create mode 100644 libj2_j2u_add_j2u.c create mode 100644 libj2_j2u_add_j2u_overflow.c create mode 100644 libj2_j2u_add_j2u_to_j2u.c create mode 100644 libj2_j2u_add_j2u_to_j2u_overflow.c create mode 100644 libj2_j2u_add_ju.c create mode 100644 libj2_j2u_add_ju_overflow.c create mode 100644 libj2_j2u_add_ju_to_j2u.c create mode 100644 libj2_j2u_add_ju_to_j2u_overflow.c create mode 100644 libj2_j2u_and_j2u.c create mode 100644 libj2_j2u_and_j2u_to_j2u.c create mode 100644 libj2_j2u_and_ju.c create mode 100644 libj2_j2u_and_ju_to_j2u.c create mode 100644 libj2_j2u_cmp_j2u.c create mode 100644 libj2_j2u_cmp_ju.c create mode 100644 libj2_j2u_div_j2u.c create mode 100644 libj2_j2u_div_j2u_return.c create mode 100644 libj2_j2u_div_j2u_to_j2u.c create mode 100644 libj2_j2u_div_ju.c create mode 100644 libj2_j2u_div_ju_return.c create mode 100644 libj2_j2u_div_ju_to_j2u.c create mode 100644 libj2_j2u_divmod_j2u.c create mode 100644 libj2_j2u_divmod_j2u_to_j2u.c create mode 100644 libj2_j2u_divmod_j2u_to_j2u_j2u.c create mode 100644 libj2_j2u_divmod_ju.c create mode 100644 libj2_j2u_divmod_ju_to_j2u.c create mode 100644 libj2_j2u_divmod_ju_to_j2u_j2u.c create mode 100644 libj2_j2u_eq_j2u.c create mode 100644 libj2_j2u_eq_ju.c create mode 100644 libj2_j2u_ge_j2u.c create mode 100644 libj2_j2u_ge_ju.c create mode 100644 libj2_j2u_gt_j2u.c create mode 100644 libj2_j2u_gt_ju.c create mode 100644 libj2_j2u_if_j2u.c create mode 100644 libj2_j2u_if_j2u_to_j2u.c create mode 100644 libj2_j2u_if_ju.c create mode 100644 libj2_j2u_if_ju_to_j2u.c create mode 100644 libj2_j2u_imply_j2u.c create mode 100644 libj2_j2u_imply_j2u_to_j2u.c create mode 100644 libj2_j2u_imply_ju.c create mode 100644 libj2_j2u_imply_ju_to_j2u.c create mode 100644 libj2_j2u_is_max.c create mode 100644 libj2_j2u_is_min.c create mode 100644 libj2_j2u_is_positive.c create mode 100644 libj2_j2u_is_zero.c create mode 100644 libj2_j2u_le_j2u.c create mode 100644 libj2_j2u_le_ju.c create mode 100644 libj2_j2u_lrot.c create mode 100644 libj2_j2u_lrot_to_j2u.c create mode 100644 libj2_j2u_lsh.c create mode 100644 libj2_j2u_lsh_overflow.c create mode 100644 libj2_j2u_lsh_to_j2u.c create mode 100644 libj2_j2u_lsh_to_j2u_overflow.c create mode 100644 libj2_j2u_lt_j2u.c create mode 100644 libj2_j2u_lt_ju.c create mode 100644 libj2_j2u_max.c create mode 100644 libj2_j2u_max_j2u.c create mode 100644 libj2_j2u_max_j2u_to_j2u.c create mode 100644 libj2_j2u_max_ju.c create mode 100644 libj2_j2u_max_ju_to_j2u.c create mode 100644 libj2_j2u_min.c create mode 100644 libj2_j2u_min_j2u.c create mode 100644 libj2_j2u_min_j2u_to_j2u.c create mode 100644 libj2_j2u_min_ju.c create mode 100644 libj2_j2u_min_ju_to_j2u.c create mode 100644 libj2_j2u_mod_j2u.c create mode 100644 libj2_j2u_mod_j2u_to_j2u.c create mode 100644 libj2_j2u_mod_ju.c create mode 100644 libj2_j2u_mod_ju_to_j2u.c create mode 100644 libj2_j2u_mul_j2u.c create mode 100644 libj2_j2u_mul_j2u_destructive.c create mode 100644 libj2_j2u_mul_j2u_overflow.c create mode 100644 libj2_j2u_mul_j2u_overflow_destructive.c create mode 100644 libj2_j2u_mul_j2u_to_j2u.c create mode 100644 libj2_j2u_mul_j2u_to_j2u_overflow.c create mode 100644 libj2_j2u_mul_ju.c create mode 100644 libj2_j2u_mul_ju_overflow.c create mode 100644 libj2_j2u_mul_ju_to_j2u.c create mode 100644 libj2_j2u_mul_ju_to_j2u_overflow.c create mode 100644 libj2_j2u_nand_j2u.c create mode 100644 libj2_j2u_nand_j2u_to_j2u.c create mode 100644 libj2_j2u_nand_ju.c create mode 100644 libj2_j2u_nand_ju_to_j2u.c create mode 100644 libj2_j2u_ne_j2u.c create mode 100644 libj2_j2u_ne_ju.c create mode 100644 libj2_j2u_nif_j2u.c create mode 100644 libj2_j2u_nif_j2u_to_j2u.c create mode 100644 libj2_j2u_nif_ju.c create mode 100644 libj2_j2u_nif_ju_to_j2u.c create mode 100644 libj2_j2u_nimply_j2u.c create mode 100644 libj2_j2u_nimply_j2u_to_j2u.c create mode 100644 libj2_j2u_nimply_ju.c create mode 100644 libj2_j2u_nimply_ju_to_j2u.c create mode 100644 libj2_j2u_nor_j2u.c create mode 100644 libj2_j2u_nor_j2u_to_j2u.c create mode 100644 libj2_j2u_nor_ju.c create mode 100644 libj2_j2u_nor_ju_to_j2u.c create mode 100644 libj2_j2u_or_j2u.c create mode 100644 libj2_j2u_or_j2u_to_j2u.c create mode 100644 libj2_j2u_or_ju.c create mode 100644 libj2_j2u_or_ju_to_j2u.c create mode 100644 libj2_j2u_rdiv_j2u.c create mode 100644 libj2_j2u_rdivmod_j2u.c create mode 100644 libj2_j2u_rdivmod_j2u_to_j2u.c create mode 100644 libj2_j2u_rmod_j2u.c create mode 100644 libj2_j2u_rrot.c create mode 100644 libj2_j2u_rrot_to_j2u.c create mode 100644 libj2_j2u_rsh.c create mode 100644 libj2_j2u_rsh_to_j2u.c create mode 100644 libj2_j2u_rsh_to_j2u_underflow.c create mode 100644 libj2_j2u_rsh_underflow.c create mode 100644 libj2_j2u_rsub_j2u.c create mode 100644 libj2_j2u_rsub_j2u_overflow.c create mode 100644 libj2_j2u_rsub_ju.c create mode 100644 libj2_j2u_rsub_ju_overflow.c create mode 100644 libj2_j2u_sub_j2u.c create mode 100644 libj2_j2u_sub_j2u_overflow.c create mode 100644 libj2_j2u_sub_j2u_to_j2u.c create mode 100644 libj2_j2u_sub_j2u_to_j2u_overflow.c create mode 100644 libj2_j2u_sub_ju.c create mode 100644 libj2_j2u_sub_ju_overflow.c create mode 100644 libj2_j2u_sub_ju_to_j2u.c create mode 100644 libj2_j2u_sub_ju_to_j2u_overflow.c create mode 100644 libj2_j2u_test_bit.c create mode 100644 libj2_j2u_test_high_ju.c create mode 100644 libj2_j2u_test_j2u.c create mode 100644 libj2_j2u_test_ju.c create mode 100644 libj2_j2u_xnor_j2u.c create mode 100644 libj2_j2u_xnor_j2u_to_j2u.c create mode 100644 libj2_j2u_xnor_ju.c create mode 100644 libj2_j2u_xnor_ju_to_j2u.c create mode 100644 libj2_j2u_xor_j2u.c create mode 100644 libj2_j2u_xor_j2u_to_j2u.c create mode 100644 libj2_j2u_xor_ju.c create mode 100644 libj2_j2u_xor_ju_to_j2u.c create mode 100644 libj2_j2u_zero.c create mode 100644 libj2_ju_add_j2u_to_j2u.c create mode 100644 libj2_ju_add_j2u_to_j2u_overflow.c create mode 100644 libj2_ju_add_ju_to_j2u.c create mode 100644 libj2_ju_and_j2u_to_j2u.c create mode 100644 libj2_ju_cmp_j2u.c create mode 100644 libj2_ju_eq_j2u.c create mode 100644 libj2_ju_ge_j2u.c create mode 100644 libj2_ju_gt_j2u.c create mode 100644 libj2_ju_if_j2u_to_j2u.c create mode 100644 libj2_ju_imply_j2u_to_j2u.c create mode 100644 libj2_ju_le_j2u.c create mode 100644 libj2_ju_lrot_to_j2u.c create mode 100644 libj2_ju_lsh_to_j2u.c create mode 100644 libj2_ju_lsh_to_j2u_overflow.c create mode 100644 libj2_ju_lt_j2u.c create mode 100644 libj2_ju_mul_j2u_to_j2u.c create mode 100644 libj2_ju_mul_j2u_to_j2u_overflow.c create mode 100644 libj2_ju_mul_ju_to_j2u.c create mode 100644 libj2_ju_nand_j2u_to_j2u.c create mode 100644 libj2_ju_ne_j2u.c create mode 100644 libj2_ju_nif_j2u_to_j2u.c create mode 100644 libj2_ju_nimply_j2u_to_j2u.c create mode 100644 libj2_ju_nor_j2u_to_j2u.c create mode 100644 libj2_ju_or_j2u_to_j2u.c create mode 100644 libj2_ju_rrot_to_j2u.c create mode 100644 libj2_ju_rsh_to_j2u.c create mode 100644 libj2_ju_rsh_to_j2u_underflow.c create mode 100644 libj2_ju_sub_j2u_to_j2u.c create mode 100644 libj2_ju_sub_j2u_to_j2u_overflow.c create mode 100644 libj2_ju_sub_ju_to_j2u.c create mode 100644 libj2_ju_sub_ju_to_j2u_overflow.c create mode 100644 libj2_ju_to_j2u.c create mode 100644 libj2_ju_xnor_j2u_to_j2u.c create mode 100644 libj2_ju_xor_j2u_to_j2u.c create mode 100644 libj2_max_j2u.c create mode 100644 libj2_max_j2u_return.c create mode 100644 libj2_max_j2u_to_j2u.c create mode 100644 libj2_min_j2u.c create mode 100644 libj2_min_j2u_return.c create mode 100644 libj2_min_j2u_to_j2u.c create mode 100644 libj2_minus_j2u.c create mode 100644 libj2_minus_j2u_to_j2u.c create mode 100644 libj2_not_j2u.c create mode 100644 libj2_not_j2u_to_j2u.c create mode 100644 libj2_not_ju_to_j2u.c create mode 100644 libj2_sgn_j2u.c create mode 100644 libj2_vmax_j2u.c create mode 100644 libj2_vmax_j2u_return.c create mode 100644 libj2_vmax_j2u_to_j2u.c create mode 100644 libj2_vmin_j2u.c create mode 100644 libj2_vmin_j2u_return.c create mode 100644 libj2_vmin_j2u_to_j2u.c create mode 100644 mk/linux.mk create mode 100644 mk/macos.mk create mode 100644 mk/windows.mk 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 + +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 + + 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 +# include +# include +# include +# 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 +.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 +#include +#include + +#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 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 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 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 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 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 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 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 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 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 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 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 = : -- cgit v1.2.3-70-g09d2