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