diff options
Diffstat (limited to '')
209 files changed, 12902 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..63f1b10 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*\#* +*~ +*.o +*.a +*.lo +*.su +*.so +*.so.* +*.dll +*.dylib +*.gch +*.gcov +*.gcno +*.gcda +*.t @@ -0,0 +1,15 @@ +ISC License + +© 2025 Mattias Andrée <m@maandree.se> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..482e2b3 --- /dev/null +++ b/Makefile @@ -0,0 +1,300 @@ +.POSIX: + +CONFIGFILE = config.mk +include $(CONFIGFILE) + +OS = linux +# Linux: linux +# Mac OS: macos +# Windows: windows +include mk/$(OS).mk + + +LIB_MAJOR = 1 +LIB_MINOR = 0 +LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR) +LIB_NAME = j2 + + +OBJ =\ + libj2_j2u_add_j2u.o\ + libj2_j2u_add_j2u_overflow.o\ + libj2_j2u_add_j2u_to_j2u.o\ + libj2_j2u_add_j2u_to_j2u_overflow.o\ + libj2_j2u_add_ju.o\ + libj2_j2u_add_ju_overflow.o\ + libj2_j2u_add_ju_to_j2u.o\ + libj2_j2u_add_ju_to_j2u_overflow.o\ + libj2_j2u_and_j2u.o\ + libj2_j2u_and_j2u_to_j2u.o\ + libj2_j2u_and_ju.o\ + libj2_j2u_and_ju_to_j2u.o\ + libj2_j2u_cmp_j2u.o\ + libj2_j2u_cmp_ju.o\ + libj2_j2u_div_j2u.o\ + libj2_j2u_div_j2u_return.o\ + libj2_j2u_div_j2u_to_j2u.o\ + libj2_j2u_div_ju.o\ + libj2_j2u_div_ju_return.o\ + libj2_j2u_div_ju_to_j2u.o\ + libj2_j2u_divmod_j2u.o\ + libj2_j2u_divmod_j2u_to_j2u.o\ + libj2_j2u_divmod_j2u_to_j2u_j2u.o\ + libj2_j2u_divmod_ju.o\ + libj2_j2u_divmod_ju_to_j2u.o\ + libj2_j2u_divmod_ju_to_j2u_j2u.o\ + libj2_j2u_eq_j2u.o\ + libj2_j2u_eq_ju.o\ + libj2_j2u_ge_j2u.o\ + libj2_j2u_ge_ju.o\ + libj2_j2u_gt_j2u.o\ + libj2_j2u_gt_ju.o\ + libj2_j2u_if_j2u.o\ + libj2_j2u_if_j2u_to_j2u.o\ + libj2_j2u_if_ju.o\ + libj2_j2u_if_ju_to_j2u.o\ + libj2_j2u_imply_j2u.o\ + libj2_j2u_imply_j2u_to_j2u.o\ + libj2_j2u_imply_ju.o\ + libj2_j2u_imply_ju_to_j2u.o\ + libj2_j2u_is_max.o\ + libj2_j2u_is_min.o\ + libj2_j2u_is_positive.o\ + libj2_j2u_is_zero.o\ + libj2_j2u_le_j2u.o\ + libj2_j2u_le_ju.o\ + libj2_j2u_lrot.o\ + libj2_j2u_lrot_to_j2u.o\ + libj2_j2u_lsh.o\ + libj2_j2u_lsh_overflow.o\ + libj2_j2u_lsh_to_j2u.o\ + libj2_j2u_lsh_to_j2u_overflow.o\ + libj2_j2u_lt_j2u.o\ + libj2_j2u_lt_ju.o\ + libj2_j2u_max.o\ + libj2_j2u_max_j2u.o\ + libj2_j2u_max_j2u_to_j2u.o\ + libj2_j2u_max_ju.o\ + libj2_j2u_max_ju_to_j2u.o\ + libj2_j2u_min.o\ + libj2_j2u_min_j2u.o\ + libj2_j2u_min_j2u_to_j2u.o\ + libj2_j2u_min_ju.o\ + libj2_j2u_min_ju_to_j2u.o\ + libj2_j2u_mod_j2u.o\ + libj2_j2u_mod_j2u_to_j2u.o\ + libj2_j2u_mod_ju.o\ + libj2_j2u_mod_ju_to_j2u.o\ + libj2_j2u_mul_j2u.o\ + libj2_j2u_mul_j2u_destructive.o\ + libj2_j2u_mul_j2u_overflow.o\ + libj2_j2u_mul_j2u_overflow_destructive.o\ + libj2_j2u_mul_j2u_to_j2u.o\ + libj2_j2u_mul_j2u_to_j2u_overflow.o\ + libj2_j2u_mul_ju.o\ + libj2_j2u_mul_ju_overflow.o\ + libj2_j2u_mul_ju_to_j2u.o\ + libj2_j2u_mul_ju_to_j2u_overflow.o\ + libj2_j2u_nand_j2u.o\ + libj2_j2u_nand_j2u_to_j2u.o\ + libj2_j2u_nand_ju.o\ + libj2_j2u_nand_ju_to_j2u.o\ + libj2_j2u_ne_j2u.o\ + libj2_j2u_ne_ju.o\ + libj2_j2u_nif_j2u.o\ + libj2_j2u_nif_j2u_to_j2u.o\ + libj2_j2u_nif_ju.o\ + libj2_j2u_nif_ju_to_j2u.o\ + libj2_j2u_nimply_j2u.o\ + libj2_j2u_nimply_j2u_to_j2u.o\ + libj2_j2u_nimply_ju.o\ + libj2_j2u_nimply_ju_to_j2u.o\ + libj2_j2u_nor_j2u.o\ + libj2_j2u_nor_j2u_to_j2u.o\ + libj2_j2u_nor_ju.o\ + libj2_j2u_nor_ju_to_j2u.o\ + libj2_j2u_or_j2u.o\ + libj2_j2u_or_j2u_to_j2u.o\ + libj2_j2u_or_ju.o\ + libj2_j2u_or_ju_to_j2u.o\ + libj2_j2u_rdiv_j2u.o\ + libj2_j2u_rdivmod_j2u.o\ + libj2_j2u_rdivmod_j2u_to_j2u.o\ + libj2_j2u_rmod_j2u.o\ + libj2_j2u_rrot.o\ + libj2_j2u_rrot_to_j2u.o\ + libj2_j2u_rsh.o\ + libj2_j2u_rsh_to_j2u.o\ + libj2_j2u_rsh_to_j2u_underflow.o\ + libj2_j2u_rsh_underflow.o\ + libj2_j2u_rsub_j2u.o\ + libj2_j2u_rsub_j2u_overflow.o\ + libj2_j2u_rsub_ju.o\ + libj2_j2u_rsub_ju_overflow.o\ + libj2_j2u_sub_j2u.o\ + libj2_j2u_sub_j2u_overflow.o\ + libj2_j2u_sub_j2u_to_j2u.o\ + libj2_j2u_sub_j2u_to_j2u_overflow.o\ + libj2_j2u_sub_ju.o\ + libj2_j2u_sub_ju_overflow.o\ + libj2_j2u_sub_ju_to_j2u.o\ + libj2_j2u_sub_ju_to_j2u_overflow.o\ + libj2_j2u_test_bit.o\ + libj2_j2u_test_high_ju.o\ + libj2_j2u_test_j2u.o\ + libj2_j2u_test_ju.o\ + libj2_j2u_xnor_j2u.o\ + libj2_j2u_xnor_j2u_to_j2u.o\ + libj2_j2u_xnor_ju.o\ + libj2_j2u_xnor_ju_to_j2u.o\ + libj2_j2u_xor_j2u.o\ + libj2_j2u_xor_j2u_to_j2u.o\ + libj2_j2u_xor_ju.o\ + libj2_j2u_xor_ju_to_j2u.o\ + libj2_j2u_zero.o\ + libj2_ju_add_j2u_to_j2u.o\ + libj2_ju_add_j2u_to_j2u_overflow.o\ + libj2_ju_add_ju_to_j2u.o\ + libj2_ju_and_j2u_to_j2u.o\ + libj2_ju_cmp_j2u.o\ + libj2_ju_eq_j2u.o\ + libj2_ju_ge_j2u.o\ + libj2_ju_gt_j2u.o\ + libj2_ju_if_j2u_to_j2u.o\ + libj2_ju_imply_j2u_to_j2u.o\ + libj2_ju_le_j2u.o\ + libj2_ju_lrot_to_j2u.o\ + libj2_ju_lsh_to_j2u.o\ + libj2_ju_lsh_to_j2u_overflow.o\ + libj2_ju_lt_j2u.o\ + libj2_ju_mul_j2u_to_j2u.o\ + libj2_ju_mul_j2u_to_j2u_overflow.o\ + libj2_ju_mul_ju_to_j2u.o\ + libj2_ju_nand_j2u_to_j2u.o\ + libj2_ju_ne_j2u.o\ + libj2_ju_nif_j2u_to_j2u.o\ + libj2_ju_nimply_j2u_to_j2u.o\ + libj2_ju_nor_j2u_to_j2u.o\ + libj2_ju_or_j2u_to_j2u.o\ + libj2_ju_rrot_to_j2u.o\ + libj2_ju_rsh_to_j2u.o\ + libj2_ju_rsh_to_j2u_underflow.o\ + libj2_ju_sub_j2u_to_j2u.o\ + libj2_ju_sub_j2u_to_j2u_overflow.o\ + libj2_ju_sub_ju_to_j2u.o\ + libj2_ju_sub_ju_to_j2u_overflow.o\ + libj2_ju_to_j2u.o\ + libj2_ju_xnor_j2u_to_j2u.o\ + libj2_ju_xor_j2u_to_j2u.o\ + libj2_max_j2u.o\ + libj2_max_j2u_return.o\ + libj2_max_j2u_to_j2u.o\ + libj2_min_j2u.o\ + libj2_min_j2u_return.o\ + libj2_min_j2u_to_j2u.o\ + libj2_minus_j2u.o\ + libj2_minus_j2u_to_j2u.o\ + libj2_not_j2u.o\ + libj2_not_j2u_to_j2u.o\ + libj2_not_ju_to_j2u.o\ + libj2_sgn_j2u.o\ + libj2_vmax_j2u.o\ + libj2_vmax_j2u_return.o\ + libj2_vmax_j2u_to_j2u.o\ + libj2_vmin_j2u.o\ + libj2_vmin_j2u_return.o\ + libj2_vmin_j2u_to_j2u.o + +SUBHDR =\ + libj2/constants.h\ + libj2/signum.h\ + libj2/constructors.h\ + libj2/unsigned-comparsion.h\ + libj2/bitwise-logic.h\ + libj2/bit-shifting.h\ + libj2/sign-shifting.h\ + libj2/addition.h\ + libj2/subtraction.h\ + libj2/multiplication.h\ + libj2/division.h + +HDR =\ + $(SUBHDR)\ + libj2.h\ + common.h + +LOBJ = $(OBJ:.o=.lo) +TOBJ = $(OBJ:.o=.to) +TEST = $(OBJ:.o=.t) + +MAN7 = libj2.7 + + +all: libj2.a libj2.$(LIBEXT) $(TEST) +$(OBJ): $(HDR) +$(LOBJ): $(HDR) +$(TOBJ): $(HDR) +$(TEST): libj2.a + +.c.o: + $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) + +.c.to: + $(CC) -c -o $@ $< -DTEST $(CFLAGS) $(CPPFLAGS) + +.to.t: + $(CC) -o $@ $< libj2.a $(LDFLAGS) + +.c.t: + $(CC) -o $@ $< libj2.a -DTEST $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) + +.c.lo: + $(CC) -fPIC -c -o $@ $< $(CFLAGS) $(CPPFLAGS) + +libj2.a: $(OBJ) + @rm -f -- $@ + $(AR) rc $@ $(OBJ) + $(AR) ts $@ > /dev/null + +libj2.$(LIBEXT): $(LOBJ) + $(CC) $(LIBFLAGS) -o $@ $(LOBJ) $(LDFLAGS) + +check: $(TEST) + @set -e;\ + for t in $(TEST); do\ + printf '%s ' $(CHECK_PREFIX) "./$$t"; printf '\n';\ + $(CHECK_PREFIX) ./"$$t";\ + done + +install: libj2.a libj2.$(LIBEXT) + mkdir -p -- "$(DESTDIR)$(PREFIX)/lib" + mkdir -p -- "$(DESTDIR)$(PREFIX)/include/libj2" + mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man7" + cp -- libj2.a "$(DESTDIR)$(PREFIX)/lib/" + cp -- libj2.$(LIBEXT) "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBMINOREXT)" + $(FIX_INSTALL_NAME) "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBMINOREXT)" + ln -sf -- libj2.$(LIBMINOREXT) "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBMAJOREXT)" + ln -sf -- libj2.$(LIBMAJOREXT) "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBEXT)" + cp -- libj2.h "$(DESTDIR)$(PREFIX)/include/" + cp -- $(SUBHDR) "$(DESTDIR)$(PREFIX)/include/libj2/" + cp -- $(MAN7) "$(DESTDIR)$(MANPREFIX)/man7/" + +uninstall: + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libj2.a" + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBMAJOREXT)" + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBMINOREXT)" + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libj2.$(LIBEXT)" + -rm -f -- "$(DESTDIR)$(PREFIX)/include/libj2.h" + -cd -- "$(DESTDIR)$(PREFIX)/include/" && rm -f -- $(SUBHDR) + -rmdir -- "$(DESTDIR)$(PREFIX)/include/libj2" + -cd -- "$(DESTDIR)$(MANPREFIX)/man7/" && rm -f -- $(MAN7) + +clean: + -rm -f -- *.o *.a *.lo *.su *.so *.so.* *.dll *.dylib + -rm -f -- *.gch *.gcov *.gcno *.gcda *.$(LIBEXT) + -rm -f -- *.to *.t + +.SUFFIXES: +.SUFFIXES: .lo .o .c .to .t + +.PHONY: all install uninstall clean @@ -0,0 +1,15 @@ +NAME + libj2 - Double-max precision integers + +SYNOPSIS + #include <libj2.h> + + Link with -lj2. + +DESCRIPTION + libj2 provides integer data types with double the width of + uintmax_t, along with functions for preforming standard + integer operations, with optional overflow-detection. + +SEE ALSO + libzahl(7) diff --git a/common.h b/common.h new file mode 100644 index 0000000..876d2ef --- /dev/null +++ b/common.h @@ -0,0 +1,29 @@ +/* See LICENSE file for copyright and license details. */ +#include "libj2.h" + +#if defined(__GNUC__) +# define CONST __attribute__((__const__)) +# define PURE __attribute__((__pure__)) +#else +# define CONST +# define PURE +#endif + +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* broken warning, spams false positives */ +# pragma clang diagnostic ignored "-Wimplicit-void-ptr-cast" /* C++-incompatiblity warning, bad idea, specially in non-header files */ +#endif + +#ifdef TEST +# include <stdlib.h> +# include <stdio.h> +# include <string.h> +# include <time.h> +# define EXPECT(EXPR)\ + do {\ + if (EXPR)\ + break;\ + fprintf(stderr, "Assertion failed at %s:%i: %s\n", __FILE__, __LINE__, #EXPR);\ + exit(1);\ + } while (0) +#endif diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..f4adf12 --- /dev/null +++ b/config.mk @@ -0,0 +1,8 @@ +PREFIX = /usr +MANPREFIX = $(PREFIX)/share/man + +CC = c99 + +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE +CFLAGS = +LDFLAGS = @@ -0,0 +1,20 @@ +.TH LIBJ2 7 LIBJ2 +.SH NAME +libj2 \- Double-max precision integers + +.SH SYNOPSIS +.nf #include <libj2.h> +.fi +.PP +Link with +.IR -lj2 . + +.SH DESCRIPTION +.B libj2 +provides integer data types with double the width of +.BR uintmax_t , +along with functions for preforming standard +integer operations, with optional overflow-detection. + +.SH SEE ALSO +.BR libzahl (7) @@ -0,0 +1,62 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBJ2_H +#define LIBJ2_H + +#include <limits.h> +#include <stdint.h> +#include <stdarg.h> + +#if 1 +# if defined(__GNUC__) +# define LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_ +# endif +#endif + + +/** + * The number of bits in an `uintmax_t` + */ +#define LIBJ2_JU_BIT ((unsigned)CHAR_BIT * (unsigned)sizeof(uintmax_t)) + +/** + * The number of bits in an `struct libj2_j2u` + */ +#define LIBJ2_J2U_BIT (2U * LIBJ2_JU_BIT) + + +/** + * Unsigned double-maximum precision integer + * + * If `uintmax_t` is a 64-bit type, this `struct` is a 128-bit type + */ +struct libj2_j2u { + /** + * Most significant half + */ + uintmax_t high; + + /** + * Least significant half + */ + uintmax_t low; +}; + + +#include "libj2/constants.h" +#include "libj2/signum.h" +#include "libj2/constructors.h" +#include "libj2/unsigned-comparsion.h" +#include "libj2/bitwise-logic.h" +#include "libj2/bit-shifting.h" +#include "libj2/sign-shifting.h" +#include "libj2/addition.h" +#include "libj2/subtraction.h" +#include "libj2/multiplication.h" +#include "libj2/division.h" + + +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) +# undef LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_ +#endif + +#endif diff --git a/libj2/addition.h b/libj2/addition.h new file mode 100644 index 0000000..d900622 --- /dev/null +++ b/libj2/addition.h @@ -0,0 +1,313 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBJ2_H +# error Do not include this header directly, include <libj2.h> instead +#endif + + +/** + * Calculate the sum of an unsigned double-max precision + * integer and an unsigned max precision integer + * + * `libj2_j2u_add_ju(a, b)` implements `*a += b` + * + * @param a The augend, and output parameter for the sum + * @param b The addend + */ +inline void +libj2_j2u_add_ju(struct libj2_j2u *a, uintmax_t b) +{ +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_add_overflow(a->low, b, &a->low)) + a->high += 1U; +#else + if (a->low > UINTMAX_MAX - b) + a->high += 1U; + a->low += b; +#endif +} + + +/** + * Calculate the sum of an unsigned double-max precision + * integer and an unsigned max precision integer + * + * `libj2_j2u_add_ju_overflow(a, b)` implements `*a += b` + * with overflow-detection + * + * @param a The augend, and output parameter for the sum + * @param b The addend + * @return 1 on overflow (the highest set bit in the sum + * cannot be stored in the result), 0 otherwise + */ +inline int +libj2_j2u_add_ju_overflow(struct libj2_j2u *a, uintmax_t b) +{ +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_add_overflow(a->low, b, &a->low)) + return __builtin_add_overflow(a->high, 1U, &a->high); + return 0; +#else + int overflow = 0; + if (a->low > UINTMAX_MAX - b) { + if (a->high == UINTMAX_MAX) + overflow = 1; + a->high += 1U; + } + a->low += b; + return overflow; +#endif +} + + +/** + * Calculate the sum of an unsigned double-max precision + * integer and an unsigned max precision integer + * + * `libj2_j2u_add_ju_to_j2u(a, b, res)` implements + * `*res = *a + b` + * + * @param a The augend + * @param b The addend + * @param res Output parameter for the sum + */ +inline void +libj2_j2u_add_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + res->high = a->high; +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_add_overflow(a->low, b, &res->low)) + res->high += 1U; +#else + if (a->low > UINTMAX_MAX - b) + res->high += 1U; + res->low = a->low + b; +#endif +} + + +/** + * Calculate the sum of an unsigned max precision + * integer and an unsigned double-max precision integer + * + * `libj2_ju_add_j2u_to_j2u(a, b, res)` implements + * `*res = a + *b` + * + * @param a The augend + * @param b The addend + * @param res Output parameter for the sum + */ +inline void +libj2_ju_add_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_add_ju_to_j2u(b, a, res); +} + + +/** + * Calculate the sum of an unsigned double-max precision + * integer and an unsigned max precision integer + * + * `libj2_j2u_add_ju_to_j2u_overflow(a, b, res)` implements + * `*res = *a + b` with overflow-detection + * + * @param a The augend + * @param b The addend + * @param res Output parameter for the sum + * @return 1 on overflow (the highest set bit in the sum + * cannot be stored in the result), 0 otherwise + */ +inline int +libj2_j2u_add_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_add_overflow(a->low, b, &res->low)) + return __builtin_add_overflow(a->high, 1U, &res->high); + res->high = a->high; + return 0; +#else + int overflow = 0; + res->high = a->high; + if (a->low > UINTMAX_MAX - b) { + if (a->high == UINTMAX_MAX) + overflow = 1; + res->high += 1U; + } + res->low = a->low + b; + return overflow; +#endif +} + + +/** + * Calculate the sum of an unsigned max precision + * integer and an unsigned double-max precision integer + * + * `libj2_ju_add_j2u_to_j2u_overflow(a, b, res)` implements + * `*res = a + *b` with overflow-detection + * + * @param a The augend + * @param b The addend + * @param res Output parameter for the sum + * @return 1 on overflow (the highest set bit in the sum + * cannot be stored in the result), 0 otherwise + */ +inline int +libj2_ju_add_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + return libj2_j2u_add_ju_to_j2u_overflow(b, a, res); +} + + +/** + * Calculate the sum, as an unsigned double-max precision + * integer, of two unsigned double-max precision integers + * + * `libj2_ju_add_ju_to_j2u(a, b, res)` implements + * `*res = a + b`, where `a` and `b` are converted to + * `struct libj2_j2u`'s + * + * @param a The augend + * @param b The addend + * @param res Output parameter for the sum + */ +inline void +libj2_ju_add_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *res) +{ +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + res->high = __builtin_add_overflow(a, b, &res->low) ? 1U : 0U; +#else + res->high = (a > UINTMAX_MAX - b); + res->low = a + b; +#endif +} + + +/** + * Calculate the sum of two unsigned double-max precision + * integers + * + * `libj2_j2u_add_j2u(a, b)` implements `*a += *b` + * + * @param a The augend, and output parameter for the sum + * @param b The addend + */ +inline void +libj2_j2u_add_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + if (a == b) { + a->high <<= 1; + a->high |= a->low >> (LIBJ2_JU_BIT - 1U); + a->low <<= 1; + } else { + libj2_j2u_add_ju(a, b->low); + a->high += b->high; + } +} + + +/** + * Calculate the sum of two unsigned double-max precision + * integers + * + * `libj2_j2u_add_j2u_to_j2u(a, b, res)` implements `*res = *a + *b` + * + * @param a The augend + * @param b The addend + * @param res Output parameter for the sum + */ +inline void +libj2_j2u_add_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + if (a == b) { + res->high = a->high << 1; + res->high |= a->low >> (LIBJ2_JU_BIT - 1U); + res->low = a->low << 1; + } else if (b == res) { + libj2_j2u_add_ju_to_j2u(b, a->low, res); + res->high += a->high; + } else { + libj2_j2u_add_ju_to_j2u(a, b->low, res); + res->high += b->high; + } +} + + +/** + * Calculate the sum of two unsigned double-max precision + * integers + * + * `libj2_j2u_add_j2u_overflow(a, b)` implements `*a += *b` + * with overflow-detection + * + * @param a The augend, and output parameter for the sum + * @param b The addend + * @return 1 on overflow (the highest set bit in the sum + * cannot be stored in the result), 0 otherwise + */ +inline int +libj2_j2u_add_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + if (a == b) { + int overflow = (int)(a->high >> (LIBJ2_JU_BIT - 1U)); + a->high <<= 1; + a->high |= a->low >> (LIBJ2_JU_BIT - 1U); + a->low <<= 1; + return overflow; + } else { + int overflow = libj2_j2u_add_ju_overflow(a, b->low); +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + return __builtin_add_overflow(a->high, b->high, &a->high) || overflow; +#else + if (a->high > UINTMAX_MAX - b->high) + overflow = 1; + a->high += b->high; + return overflow; +#endif + } +} + + +/** + * Calculate the sum of two unsigned double-max precision + * integers + * + * `libj2_j2u_add_j2u_to_j2u_overflow(a, b, res)` implements + * `*res = *a + *b` with overflow-detection + * + * @param a The augend + * @param b The addend + * @param res Output parameter for the sum + * @return 1 on overflow (the highest set bit in the sum + * cannot be stored in the result), 0 otherwise + */ +inline int +libj2_j2u_add_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + if (a == b) { + int overflow = (int)(a->high >> (LIBJ2_JU_BIT - 1U)); + res->high = a->high << 1; + res->high |= a->low >> (LIBJ2_JU_BIT - 1U); + res->low = a->low << 1; + return overflow; + } else if (b == res) { + int overflow = libj2_j2u_add_ju_to_j2u_overflow(b, a->low, res); +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + return __builtin_add_overflow(res->high, a->high, &res->high) || overflow; +#else + if (res->high > UINTMAX_MAX - a->high) + overflow = 1; + res->high += a->high; + return overflow; +#endif + } else { + int overflow = libj2_j2u_add_ju_to_j2u_overflow(a, b->low, res); +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + return __builtin_add_overflow(res->high, b->high, &res->high) || overflow; +#else + if (res->high > UINTMAX_MAX - b->high) + overflow = 1; + res->high += b->high; + return overflow; +#endif + } +} diff --git a/libj2/bit-shifting.h b/libj2/bit-shifting.h new file mode 100644 index 0000000..a0c36d1 --- /dev/null +++ b/libj2/bit-shifting.h @@ -0,0 +1,573 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBJ2_H +# error Do not include this header directly, include <libj2.h> instead +#endif + + +/** + * Shift the bits an unsigned double-max precision + * integer to more signficant positions (left-shift) + * + * Bits shifted out of precision will be discarded, + * and positions without any new bit will be assigned + * the bit value 0 + * + * `libj2_j2u_lsh(a, b)` implements `*a <<= b` + * + * This is equivalent to multiplying `a` by the `b`th + * power of 2 + * + * @param a The integer to shift, also used as the + * output parameter for the result + * @param b The number of positions to shift each bit + */ +inline void +libj2_j2u_lsh(struct libj2_j2u *a, unsigned b) +{ + if (b >= LIBJ2_JU_BIT) { + if (b >= LIBJ2_J2U_BIT) + a->high = 0; + else + a->high = a->low << (b - LIBJ2_JU_BIT); + a->low = 0U; + } else if (b) { + a->high <<= b; + a->high |= a->low >> (LIBJ2_JU_BIT - b); + a->low <<= b; + } +} + + +/** + * Shift the bits an unsigned double-max precision + * integer to more signficant positions (left-shift) + * + * Bits shifted out of precision will be discarded, + * and positions without any new bit will be assigned + * the bit value 0 + * + * `libj2_j2u_lsh_to_j2u(a, b, res)` implements `*res = *a << b` + * + * This is equivalent to multiplying `a` by the `b`th + * power of 2 + * + * @param a The integer to shift + * @param b The number of positions to shift each bit + * @param res Output parameter for the result + */ +inline void +libj2_j2u_lsh_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res) +{ + *res = *a; + libj2_j2u_lsh(res, b); +} + + +/** + * Shift the bits an unsigned double-max precision + * integer, represented by an unsigned max precision + * integer and whose high part is treated as having + * the value 0, to more signficant positions (left-shift) + * + * Bits shifted out of precision will be discarded, + * and positions without any new bit will be assigned + * the bit value 0 + * + * `libj2_ju_lsh_to_j2u(a, b, res)` implements `*res = a << b`, + * where `a` is converted to a `struct libj2_j2u` + * + * This is equivalent to multiplying `a` by the `b`th + * power of 2 + * + * You can rely on `libj2_ju_lsh_to_j2u(1, LIBJ2_J2U_BIT, res)` + * overflowing and assigning 0 to `*res`, and thus, subtracting + * 1 from `*res` afterwards will set all bits; and so, + * `libj2_ju_lsh_to_j2u(1, n, a), libj2_j2u_sub_j2(a, 1)` will + * always set the `n` least significant bits in `a` and clear + * all other bits + * + * @param a The integer to shift + * @param b The number of positions to shift each bit + * @param res Output parameter for the result + */ +inline void +libj2_ju_lsh_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res) +{ + libj2_ju_to_j2u(a, res); + libj2_j2u_lsh(res, b); +} + + +/** + * Shift the bits an unsigned double-max precision + * integer to more signficant positions (left-shift) + * + * Bits shifted out of precision will be discarded, + * and positions without any new bit will be assigned + * the bit value 0 + * + * `libj2_j2u_lsh_overflow(a, b)` implements + * `(*a << b) >> b == *a ? (*a <<= b, 0) : (*a <<= b, 1)` + * + * This is equivalent to multiplying `a` by the `b`th + * power of 2 + * + * @param a The integer to shift, also used as the + * output parameter for the result + * @param b The number of positions to shift each bit + * @return 1 if any set bit was discarded because + * it was shifted out, 0 otherwise + */ +inline int +libj2_j2u_lsh_overflow(struct libj2_j2u *a, unsigned b) +{ + if (b >= LIBJ2_J2U_BIT) { + int overflow = a->high || a->low; + a->high = 0; + a->low = 0; + return overflow; + } else if (b > LIBJ2_JU_BIT) { + int overflow = a->high || a->low >> (LIBJ2_J2U_BIT - b); + a->high = a->low << (b - LIBJ2_JU_BIT); + a->low = 0U; + return overflow; + } else if (b == LIBJ2_JU_BIT) { + int overflow = !!a->high; + a->high = a->low; + a->low = 0U; + return overflow; + } else if (b) { + int overflow = !!(a->high >> (LIBJ2_JU_BIT - b)); + a->high <<= b; + a->high |= a->low >> (LIBJ2_JU_BIT - b); + a->low <<= b; + return overflow; + } else { + return 0; + } +} + + +/** + * Shift the bits an unsigned double-max precision + * integer to more signficant positions (left-shift) + * + * Bits shifted out of precision will be discarded, + * and positions without any new bit will be assigned + * the bit value 0 + * + * `libj2_j2u_lsh_to_j2u_overflow(a, b, res)` implements + * `*res = *a << b, a != *res >> b` + * + * This is equivalent to multiplying `a` by the `b`th + * power of 2 + * + * @param a The integer to shift + * @param b The number of positions to shift each bit + * @param res Output parameter for the result + * @return 1 if any set bit was discarded because + * it was shifted out, 0 otherwise + */ +inline int +libj2_j2u_lsh_to_j2u_overflow(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res) +{ + *res = *a; + return libj2_j2u_lsh_overflow(res, b); +} + + +/** + * Shift the bits an unsigned double-max precision + * integer, represented by an unsigned max precision + * integer and whose high part is treated as having + * the value 0, to more signficant positions (left-shift) + * + * Bits shifted out of precision will be discarded, + * and positions without any new bit will be assigned + * the bit value 0 + * + * `libj2_ju_lsh_to_j2u_overflow(a, b, res)` implements + * `*res = a << b, a != *res >> b`, where `a` is converted + * to a `struct libj2_j2u` + * + * This is equivalent to multiplying `a` by the `b`th + * power of 2 + * + * @param a The integer to shift + * @param b The number of positions to shift each bit + * @param res Output parameter for the result + * @return 1 if any set bit was discarded because + * it was shifted out, 0 otherwise + */ +inline int +libj2_ju_lsh_to_j2u_overflow(uintmax_t a, unsigned b, struct libj2_j2u *res) +{ + libj2_ju_to_j2u(a, res); + return libj2_j2u_lsh_overflow(res, b); +} + + +/** + * Shift the bits an unsigned double-max precision + * integer to less signficant positions (right-shift) + * + * Bits shifted out of precision will be discarded, + * and positions without any new bit will be assigned + * the bit value 0 + * + * `libj2_j2u_rsh(a, b)` implements `*a >>= b` + * + * This is equivalent to dividing `a` by the `b`th + * power of 2 + * + * @param a The integer to shift, also used as the + * output parameter for the result + * @param b The number of positions to shift each bit + */ +inline void +libj2_j2u_rsh(struct libj2_j2u *a, unsigned b) +{ + if (b >= LIBJ2_JU_BIT) { + if (b >= LIBJ2_J2U_BIT) + a->low = 0; + else + a->low = a->high >> (b - LIBJ2_JU_BIT); + a->high = 0U; + } else if (b) { + a->low >>= b; + a->low |= a->high << (LIBJ2_JU_BIT - b); + a->high >>= b; + } +} + + +/** + * Shift the bits an unsigned double-max precision + * integer to less signficant positions (right-shift) + * + * Bits shifted out of precision will be discarded, + * and positions without any new bit will be assigned + * the bit value 0 + * + * `libj2_j2u_rsh_to_j2u(a, b, res)` implements `*res = *a >> b` + * + * This is equivalent to dividing `a` by the `b`th + * power of 2 + * + * @param a The integer to shift + * @param b The number of positions to shift each bit + * @param res Output parameter for the result + */ +inline void +libj2_j2u_rsh_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res) +{ + *res = *a; + libj2_j2u_rsh(res, b); +} + + +/** + * Shift the bits an unsigned double-max precision + * integer, represented by an unsigned max precision + * integer and whose high part is treated as having + * the value 0, to less signficant positions (right-shift) + * + * Bits shifted out of precision will be discarded, + * and positions without any new bit will be assigned + * the bit value 0 + * + * `libj2_ju_rsh_to_j2u(a, b, res)` implements `*res = a >> b`, + * where `a` is converted to a `struct libj2_j2u` + * + * This is equivalent to dividing `a` by the `b`th + * power of 2 + * + * @param a The integer to shift + * @param b The number of positions to shift each bit + * @param res Output parameter for the result + */ +inline void +libj2_ju_rsh_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res) +{ + libj2_ju_to_j2u(a, res); + libj2_j2u_rsh(res, b); +} + + +/** + * Shift the bits an unsigned double-max precision + * integer to less signficant positions (right-shift) + * + * Bits shifted out of precision will be discarded, + * and positions without any new bit will be assigned + * the bit value 0 + * + * `libj2_j2u_rsh_underflow(a, b)` implements + * `(*a >> b) << b == *a ? (*a >>= b, 0) : (*a >>= b, 1)` + * + * This is equivalent to dividing `a` by the `b`th + * power of 2 + * + * @param a The integer to shift, also used as the + * output parameter for the result + * @param b The number of positions to shift each bit + * @return 1 if any set bit was discarded because + * it was shifted out, 0 otherwise + */ +inline int +libj2_j2u_rsh_underflow(struct libj2_j2u *a, unsigned b) +{ + if (b >= LIBJ2_J2U_BIT) { + int underflow = a->high || a->low; + a->high = 0; + a->low = 0; + return underflow; + } else if (b > LIBJ2_JU_BIT) { + int underflow = a->low || a->high >> (LIBJ2_J2U_BIT - b); + a->low = a->high >> (b - LIBJ2_JU_BIT); + a->high = 0U; + return underflow; + } else if (b == LIBJ2_JU_BIT) { + int underflow = !!a->low; + a->low = a->high; + a->high = 0U; + return underflow; + } else if (b) { + int underflow = !!(a->low << (LIBJ2_JU_BIT - b)); + a->low >>= b; + a->low |= a->high << (LIBJ2_JU_BIT - b); + a->high >>= b; + return underflow; + } else { + return 0; + } +} + + +/** + * Shift the bits an unsigned double-max precision + * integer to less signficant positions (right-shift) + * + * Bits shifted out of precision will be discarded, + * and positions without any new bit will be assigned + * the bit value 0 + * + * `libj2_j2u_rsh_to_j2u_underflow(a, b, res)` implements + * `*res = *a >> b, a != *res << b` + * + * This is equivalent to dividing `a` by the `b`th + * power of 2 + * + * @param a The integer to shift + * @param b The number of positions to shift each bit + * @param res Output parameter for the result + * @return 1 if any set bit was discarded because + * it was shifted out, 0 otherwise + */ +inline int +libj2_j2u_rsh_to_j2u_underflow(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res) +{ + *res = *a; + return libj2_j2u_rsh_underflow(res, b); +} + + +/** + * Shift the bits an unsigned double-max precision + * integer, represented by an unsigned max precision + * integer and whose high part is treated as having + * the value 0, to less signficant positions (right-shift) + * + * Bits shifted out of precision will be discarded, + * and positions without any new bit will be assigned + * the bit value 0 + * + * `libj2_ju_rsh_to_j2u_underflow(a, b, res)` implements + * `*res = a >> b, a != *res << b`, where `a` is converted + * to a `struct libj2_j2u` + * + * This is equivalent to dividing `a` by the `b`th + * power of 2 + * + * @param a The integer to shift + * @param b The number of positions to shift each bit + * @param res Output parameter for the result + * @return 1 if any set bit was discarded because + * it was shifted out, 0 otherwise + */ +inline int +libj2_ju_rsh_to_j2u_underflow(uintmax_t a, unsigned b, struct libj2_j2u *res) +{ + libj2_ju_to_j2u(a, res); + return libj2_j2u_rsh_underflow(res, b); +} + + +/** + * Shift the bits an unsigned double-max precision + * integer to more signficant positions + * + * Bits shifted out of precision are wrapped around + * to the other edge of the bit array + * + * `libj2_j2u_lrot(a, b)` implements + * `*a = (*a << b) | (*a >> (n - b))`, where + * `n` is the number of bits in `*a` + * + * @param a The integer to rotate, also used as the + * output parameter for the result + * @param b The number of positions to shift each bit + */ +inline void +libj2_j2u_lrot(struct libj2_j2u *a, unsigned b) +{ + uintmax_t c; + b %= LIBJ2_J2U_BIT; + if (b >= LIBJ2_JU_BIT) { + b -= LIBJ2_JU_BIT; + c = a->high; + a->high = a->low; + a->low = c; + } + if (b) { + c = a->high; + a->high <<= b; + a->high |= a->low >> (LIBJ2_JU_BIT - b); + a->low <<= b; + a->low |= c >> (LIBJ2_JU_BIT - b); + } +} + + +/** + * Shift the bits an unsigned double-max precision + * integer to more signficant positions + * + * Bits shifted out of precision are wrapped around + * to the other edge of the bit array + * + * `libj2_j2u_lrot_to_j2u(a, b, res)` implements + * `*res = (*a << b) | (*a >> (n - b))`, where + * `n` is the number of bits in `*a` + * + * @param a The integer to rotate + * @param b The number of positions to shift each bit + * @param res Output parameter for the result + */ +inline void +libj2_j2u_lrot_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res) +{ + *res = *a; + libj2_j2u_lrot(res, b); +} + + +/** + * Shift the bits an unsigned double-max precision + * integer, represented by an unsigned max precision + * integer and whose high part is treated as having + * the value 0, to more signficant positions + * + * Bits shifted out of precision are wrapped around + * to the other edge of the bit array + * + * `libj2_ju_lrot_to_j2u(a, b, res)` implements + * `*res = (a << b) | (a >> (n - b))`, where + * `n` is the number of bits in `a`, and where + * `a` is converted to a `struct libj2_j2u` + * + * @param a The integer to rotate + * @param b The number of positions to shift each bit + * @param res Output parameter for the result + */ +inline void +libj2_ju_lrot_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res) +{ + libj2_ju_to_j2u(a, res); + libj2_j2u_lrot(res, b); +} + + +/** + * Shift the bits an unsigned double-max precision + * integer to less signficant positions + * + * Bits shifted out of precision are wrapped around + * to the other edge of the bit array + * + * `libj2_j2u_rrot(a, b)` implements + * `*a = (*a >> b) | (*a << (n - b))`, where + * `n` is the number of bits in `*a` + * + * @param a The integer to rotate, also used as the + * output parameter for the result + * @param b The number of positions to shift each bit + */ +inline void +libj2_j2u_rrot(struct libj2_j2u *a, unsigned b) +{ + uintmax_t c; + b %= LIBJ2_J2U_BIT; + if (b >= LIBJ2_JU_BIT) { + b -= LIBJ2_JU_BIT; + c = a->high; + a->high = a->low; + a->low = c; + } + if (b) { + c = a->high; + a->high >>= b; + a->high |= a->low << (LIBJ2_JU_BIT - b); + a->low >>= b; + a->low |= c << (LIBJ2_JU_BIT - b); + } +} + + +/** + * Shift the bits an unsigned double-max precision + * integer to less signficant positions + * + * Bits shifted out of precision are wrapped around + * to the other edge of the bit array + * + * `libj2_j2u_rrot_to_j2u(a, b, res)` implements + * `*res = (*a >> b) | (*a << (n - b))`, where + * `n` is the number of bits in `*a` + * + * @param a The integer to rotate + * @param b The number of positions to shift each bit + * @param res Output parameter for the result + */ +inline void +libj2_j2u_rrot_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res) +{ + *res = *a; + libj2_j2u_rrot(res, b); +} + + +/** + * Shift the bits an unsigned double-max precision + * integer, represented by an unsigned max precision + * integer and whose high part is treated as having + * the value 0, to less signficant positions + * + * Bits shifted out of precision are wrapped around + * to the other edge of the bit array + * + * `libj2_ju_rrot_to_j2u(a, b, res)` implements + * `*res = (a >> b) | (a << (n - b))`, where + * `n` is the number of bits in `a`, and where + * `a` is converted to a `struct libj2_j2u` + * + * @param a The integer to rotate + * @param b The number of positions to shift each bit + * @param res Output parameter for the result + */ +inline void +libj2_ju_rrot_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res) +{ + libj2_ju_to_j2u(a, res); + libj2_j2u_rrot(res, b); +} diff --git a/libj2/bitwise-logic.h b/libj2/bitwise-logic.h new file mode 100644 index 0000000..6ec362e --- /dev/null +++ b/libj2/bitwise-logic.h @@ -0,0 +1,980 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBJ2_H +# error Do not include this header directly, include <libj2.h> instead +#endif + + +/** + * Test whether a specific bit in an unsigned + * double-max precision integer is set + * + * @param a The integer to inspect + * @param b The index of the bit to test, + * 0 for the least significant bit + * @return 1 if the bit is set, 0 otherwise + */ +inline int +libj2_j2u_test_bit(const struct libj2_j2u *a, unsigned b) +{ + if (b >= LIBJ2_J2U_BIT) + return 0; + else if (b >= LIBJ2_JU_BIT) + return (int)((a->high >> (b - LIBJ2_JU_BIT)) & 1U); + else + return (int)((a->low >> b) & 1U); +} + + +/** + * Test whether two unsigned double-max precision + * integers have commonly set bits + * + * @param a One of the integers + * @param b The other integer + * @return 1 if the two integers have set bits + * in common, 0 otherwise + */ +inline int +libj2_j2u_test_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + return (a->high & b->high) || (a->low & b->low); +} + + +/** + * Test whether an unsigned double-max precision + * integer have commonly set bits with an unsigned + * max precision integer + * + * @param a The double-max precision integer + * @param b The max precision integer + * @return 1 if the two integers have set bits + * in common, 0 otherwise + */ +inline int +libj2_j2u_test_ju(const struct libj2_j2u *a, uintmax_t b) +{ + return !!(a->low & b); +} + + +/** + * Test whether the high part of an unsigned double-max + * precision integer have commonly set bits with an unsigned + * max precision integer + * + * @param a The double-max precision integer + * @param b The max precision integer + * @return 1 if high part of `a` have set bits + * in common with `b`, 0 otherwise + */ +inline int +libj2_j2u_test_high_ju(const struct libj2_j2u *a, uintmax_t b) +{ + return !!(a->high & b); +} + + +/** + * Calculate the bitwise NOT of an unsigned + * double-max precision integer + * + * @param a The integer, also used as output + * parameter for the result + */ +inline void +libj2_not_j2u(struct libj2_j2u *a) +{ + a->high = ~a->high; + a->low = ~a->low; +} + + +/** + * Calculate the bitwise NOT of an unsigned + * double-max precision integer + * + * @param a The integer + * @param res Output parameter for the result + */ +inline void +libj2_not_j2u_to_j2u(const struct libj2_j2u *a, struct libj2_j2u *res) +{ + res->high = ~a->high; + res->low = ~a->low; +} + + +/** + * Calculate the bitwise NOT of an unsigned double-max + * precision integer represented by an unsigned max + * precision integer (the high part is of the unsigned + * double-max precision integer is treated as 0) + * + * @param a The integer + * @param res Output parameter for the result + */ +inline void +libj2_not_ju_to_j2u(uintmax_t a, struct libj2_j2u *res) +{ + res->high = UINTMAX_MAX; + res->low = ~a; +} + + +/** + * Calculate the bitwise AND of two unsigned double-max + * precision integers + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_and_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + a->high &= b->high; + a->low &= b->low; +} + + +/** + * Calculate the bitwise AND of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_and_ju(struct libj2_j2u *a, uintmax_t b) +{ + a->high = 0; + a->low &= b; +} + + +/** + * Calculate the bitwise AND of two unsigned double-max + * precision integers + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_and_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + res->high = a->high & b->high; + res->low = a->low & b->low; +} + + +/** + * Calculate the bitwise AND of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_and_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + res->high = 0; + res->low = a->low & b; +} + + +/** + * Calculate the bitwise AND of an unsigned max + * precision integer (left-hand) and an unsigned + * double-max precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_ju_and_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_and_ju_to_j2u(b, a, res); +} + + +/** + * Calculate the bitwise OR of two unsigned double-max + * precision integers + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_or_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + a->high |= b->high; + a->low |= b->low; +} + + +/** + * Calculate the bitwise OR of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_or_ju(struct libj2_j2u *a, uintmax_t b) +{ + a->low |= b; +} + + +/** + * Calculate the bitwise OR of two unsigned double-max + * precision integers + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_or_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + res->high = a->high | b->high; + res->low = a->low | b->low; +} + + +/** + * Calculate the bitwise OR of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_or_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + res->high = a->high; + res->low = a->low | b; +} + + +/** + * Calculate the bitwise OR of an unsigned max + * precision integer (left-hand) and an unsigned + * double-max precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_ju_or_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_or_ju_to_j2u(b, a, res); +} + + +/** + * Calculate the bitwise XOR of two unsigned double-max + * precision integers + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_xor_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + a->high ^= b->high; + a->low ^= b->low; +} + + +/** + * Calculate the bitwise XOR of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_xor_ju(struct libj2_j2u *a, uintmax_t b) +{ + a->low ^= b; +} + + +/** + * Calculate the bitwise XOR of two unsigned double-max + * precision integers + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_xor_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + res->high = a->high ^ b->high; + res->low = a->low ^ b->low; +} + + +/** + * Calculate the bitwise XOR of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_xor_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + res->high = a->high; + res->low = a->low ^ b; +} + + +/** + * Calculate the bitwise XOR of an unsigned max + * precision integer (left-hand) and an unsigned + * double-max precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_ju_xor_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_xor_ju_to_j2u(b, a, res); +} + + +/** + * Calculate the bitwise NAND of two unsigned double-max + * precision integers + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_nand_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + libj2_j2u_and_j2u(a, b); + libj2_not_j2u(a); +} + + +/** + * Calculate the bitwise NAND of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_nand_ju(struct libj2_j2u *a, uintmax_t b) +{ + libj2_j2u_and_ju(a, b); + libj2_not_j2u(a); +} + + +/** + * Calculate the bitwise NAND of two unsigned double-max + * precision integers + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_nand_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_and_j2u_to_j2u(a, b, res); + libj2_not_j2u(res); +} + + +/** + * Calculate the bitwise NAND of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_nand_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + libj2_j2u_and_ju_to_j2u(a, b, res); + libj2_not_j2u(res); +} + + +/** + * Calculate the bitwise NAND of an unsigned max + * precision integer (left-hand) and an unsigned + * double-max precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_ju_nand_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_nand_ju_to_j2u(b, a, res); +} + + +/** + * Calculate the bitwise NOR of two unsigned double-max + * precision integers + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_nor_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + libj2_j2u_or_j2u(a, b); + libj2_not_j2u(a); +} + + +/** + * Calculate the bitwise NOR of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_nor_ju(struct libj2_j2u *a, uintmax_t b) +{ + libj2_j2u_or_ju(a, b); + libj2_not_j2u(a); +} + + +/** + * Calculate the bitwise NOR of two unsigned double-max + * precision integers + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_nor_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_or_j2u_to_j2u(a, b, res); + libj2_not_j2u(res); +} + + +/** + * Calculate the bitwise NOR of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_nor_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + libj2_j2u_or_ju_to_j2u(a, b, res); + libj2_not_j2u(res); +} + + +/** + * Calculate the bitwise NOR of an unsigned max + * precision integer (left-hand) and an unsigned + * double-max precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_ju_nor_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_nor_ju_to_j2u(b, a, res); +} + + +/** + * Calculate the bitwise XNOR of two unsigned double-max + * precision integers + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_xnor_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + libj2_j2u_xor_j2u(a, b); + libj2_not_j2u(a); +} + + +/** + * Calculate the bitwise XNOR of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_xnor_ju(struct libj2_j2u *a, uintmax_t b) +{ + libj2_j2u_xor_ju(a, b); + libj2_not_j2u(a); +} + + +/** + * Calculate the bitwise XNOR of two unsigned double-max + * precision integers + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_xnor_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_xor_j2u_to_j2u(a, b, res); + libj2_not_j2u(res); +} + + +/** + * Calculate the bitwise XNOR of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_xnor_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + libj2_j2u_xor_ju_to_j2u(a, b, res); + libj2_not_j2u(res); +} + + +/** + * Calculate the bitwise XNOR of an unsigned max + * precision integer (left-hand) and an unsigned + * double-max precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_ju_xnor_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_xnor_ju_to_j2u(b, a, res); +} + + +/** + * Calculate the bitwise IMPLY of two unsigned double-max + * precision integers + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_imply_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + if (a == b) { + libj2_j2u_max(a); + } else { + libj2_not_j2u(a); + libj2_j2u_or_j2u(a, b); + } +} + + +/** + * Calculate the bitwise IMPLY of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_imply_ju(struct libj2_j2u *a, uintmax_t b) +{ + libj2_not_j2u(a); + libj2_j2u_or_ju(a, b); +} + + +/** + * Calculate the bitwise IMPLY of two unsigned + * double-max precision integers + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_imply_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + if (a == b) { + res->high = UINTMAX_MAX; + res->low = UINTMAX_MAX; + } else if (res == b) { + struct libj2_j2u c; + libj2_not_j2u_to_j2u(a, &c); + libj2_j2u_or_j2u(res, &c); + } else { + libj2_not_j2u_to_j2u(a, res); + libj2_j2u_or_j2u(res, b); + } +} + + +/** + * Calculate the bitwise IMPLY of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_imply_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + libj2_not_j2u_to_j2u(a, res); + libj2_j2u_or_ju(res, b); +} + + +/** + * Calculate the bitwise IF of two unsigned + * double-max precision integers + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_if_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + struct libj2_j2u c; + libj2_not_j2u_to_j2u(b, &c); + libj2_j2u_or_j2u(a, &c); +} + + +/** + * Calculate the bitwise NIF of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_if_ju(struct libj2_j2u *a, uintmax_t b) +{ + struct libj2_j2u c; + libj2_not_ju_to_j2u(b, &c); + libj2_j2u_or_j2u(a, &c); +} + + +/** + * Calculate the bitwise IF of two unsigned + * double-max precision integers + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_if_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_imply_j2u_to_j2u(b, a, res); +} + + +/** + * Calculate the bitwise IF of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_if_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + if (res == a) { + struct libj2_j2u c; + libj2_not_ju_to_j2u(b, &c); + libj2_j2u_or_j2u(res, &c); + } else { + libj2_not_ju_to_j2u(b, res); + libj2_j2u_or_j2u(res, a); + } +} + + +/** + * Calculate the bitwise IMPLY of an unsigned max + * precision integer (left-hand) and an unsigned + * double-max precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_ju_imply_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_if_ju_to_j2u(b, a, res); +} + + +/** + * Calculate the bitwise IF of an unsigned max + * precision integer (left-hand) and an unsigned + * double-max precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_ju_if_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_imply_ju_to_j2u(b, a, res); +} + + +/** + * Calculate the bitwise NIMPLY of two unsigned + * double-max precision integers + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_nimply_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + struct libj2_j2u c; + libj2_not_j2u_to_j2u(b, &c); + libj2_j2u_and_j2u(a, &c); +} + + +/** + * Calculate the bitwise NIMPLY of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_nimply_ju(struct libj2_j2u *a, uintmax_t b) +{ + struct libj2_j2u c; + libj2_not_ju_to_j2u(b, &c); + libj2_j2u_and_j2u(a, &c); +} + + +/** + * Calculate the bitwise NIMPLY of two unsigned + * double-max precision integers + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_nimply_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + if (a == b) { + res->high = 0; + res->low = 0; + } else if (res == a) { + struct libj2_j2u c; + libj2_not_j2u_to_j2u(b, &c); + libj2_j2u_and_j2u(res, &c); + } else { + libj2_not_j2u_to_j2u(b, res); + libj2_j2u_and_j2u(res, a); + } +} + + +/** + * Calculate the bitwise NIMPLY of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_nimply_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + if (res == a) { + struct libj2_j2u c; + libj2_not_ju_to_j2u(b, &c); + libj2_j2u_and_j2u(res, &c); + } else { + libj2_not_ju_to_j2u(b, res); + libj2_j2u_and_j2u(res, a); + } +} + + +/** + * Calculate the bitwise NIF of two unsigned + * double-max precision integers + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_nif_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + if (a == b) { + libj2_j2u_zero(a); + } else { + libj2_not_j2u(a); + libj2_j2u_and_j2u(a, b); + } +} + + +/** + * Calculate the bitwise NIF of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer, also used as the + * output parameter for result + * @param b The right-hand integer + */ +inline void +libj2_j2u_nif_ju(struct libj2_j2u *a, uintmax_t b) +{ + libj2_not_j2u(a); + libj2_j2u_and_ju(a, b); +} + + +/** + * Calculate the bitwise NIF of two unsigned + * double-max precision integers + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_nif_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_nimply_j2u_to_j2u(b, a, res); +} + + +/** + * Calculate the bitwise NIF of an unsigned double-max + * precision integer (left-hand) and an unsigned max + * precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_j2u_nif_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + libj2_not_j2u_to_j2u(a, res); + libj2_j2u_and_ju(res, b); +} + + +/** + * Calculate the bitwise NIMPLY of an unsigned max + * precision integer (left-hand) and an unsigned + * double-max precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_ju_nimply_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_nif_ju_to_j2u(b, a, res); +} + + +/** + * Calculate the bitwise NIF of an unsigned max + * precision integer (left-hand) and an unsigned + * double-max precision integer (right-hand) + * + * @param a The left-hand integer + * @param b The right-hand integer + * @param res Output parameter for the result + */ +inline void +libj2_ju_nif_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + libj2_j2u_nimply_ju_to_j2u(b, a, res); +} diff --git a/libj2/constants.h b/libj2/constants.h new file mode 100644 index 0000000..e33fbff --- /dev/null +++ b/libj2/constants.h @@ -0,0 +1,94 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBJ2_H +# error Do not include this header directly, include <libj2.h> instead +#endif + + +/** + * Check whether an unsigned double-max precision integer has + * the value 0 (or equivalently, a non-positive value) + * + * `libj2_j2u_is_zero(a)` implements `*a == 0` + * + * @param a The integer to inspect + * @return 1 if `a` has the value 0, 0 otherwise + */ +inline int +libj2_j2u_is_zero(const struct libj2_j2u *a) +{ + return !a->high && !a->low; +} + + +/** + * Assign the value 0 to unsigned double-max precision integer + * + * `libj2_j2u_zero(res)` implements `(void)(*res = 0)` + * + * @param res The integer to assign the value 0 to + */ +inline void +libj2_j2u_zero(struct libj2_j2u *res) +{ + res->high = res->low = 0; +} + + +/** + * Check whether an unsigned double-max precision integer has + * the highest representable value + * + * @param a The integer to inspect + * @return 1 if `a` has highest representable value, 0 otherwise + */ +inline int +libj2_j2u_is_max(const struct libj2_j2u *a) +{ + return a->high == UINTMAX_MAX && a->low == UINTMAX_MAX; +} + + +/** + * Assign the highest representable value to unsigned double-max + * precision integer + * + * @param res The integer to assign the value to + */ +inline void +libj2_j2u_max(struct libj2_j2u *res) +{ + res->high = res->low = UINTMAX_MAX; +} + + +/** + * Check whether an unsigned double-max precision integer has + * the lowest representable value + * + * Since the integer type is unsigned, this function + * does the same thing as `libj2_j2u_is_zero(a)` + * + * @param a The integer to inspect + * @return 1 if `a` has lowest representable value, 0 otherwise + */ +inline int +libj2_j2u_is_min(const struct libj2_j2u *a) +{ + return libj2_j2u_is_zero(a); +} + + +/** + * Assign the lowest representable value to unsigned double-max + * precision integer + * + * Since the integer type is unsigned, this function + * does the same thing as `libj2_j2u_zero(res)` + * + * @param res The integer to assign the value to + */ +inline void +libj2_j2u_min(struct libj2_j2u *res) +{ + libj2_j2u_zero(res); +} diff --git a/libj2/constructors.h b/libj2/constructors.h new file mode 100644 index 0000000..3f2b8fe --- /dev/null +++ b/libj2/constructors.h @@ -0,0 +1,24 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBJ2_H +# error Do not include this header directly, include <libj2.h> instead +#endif + + +/** + * Cast an unsigned max precision integer to an unsigned + * double-max precision integer + * + * `libj2_ju_to_j2u(a, res)` implements `*res = a` + * + * @param a The value to assign to `*res` + * @param res The integer to assign the value `a` to + */ +inline void +libj2_ju_to_j2u(uintmax_t a, struct libj2_j2u *res) +{ + res->high = 0; + res->low = a; +} + + +/* libj2_j2u_zero, libj2_j2u_max, libj2_j2u_min are located in constants.h */ diff --git a/libj2/division.h b/libj2/division.h new file mode 100644 index 0000000..9607b1b --- /dev/null +++ b/libj2/division.h @@ -0,0 +1,534 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBJ2_H +# error Do not include this header directly, include <libj2.h> instead +#endif + + +/** + * Calculate the integer quotient, rounded + * towards zero, and remainder of two unsigned + * double-max precision integers + * + * `libj2_j2u_divmod_j2u_to_j2u(a, b, res_q)` + * implements `*res_q = *a / *b, *a %= *b` + * + * For the quotient q, and remainder r, + * dividend n, and divisor d, it will be true + * that qd + r = n + * + * @param a The dividend (left-hand), also used as + * the output parameter for the remainder + * @param b The divisor (right-hand) + * @param res_q Output parameter for the quotient + */ +inline void +libj2_j2u_divmod_j2u_to_j2u(struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res_q) +{ + struct libj2_j2u q = {0, 0}; + struct libj2_j2u c; + const struct libj2_j2u d = *b; + unsigned e = LIBJ2_J2U_BIT; + int cmp = libj2_j2u_cmp_j2u(a, b); + + if (cmp <= 0) { + if (cmp == 0) { + q.low = 1U; + libj2_j2u_zero(a); + } + goto out; + } + + /* TODO e = leading_zeroes(a) - leading_zeroes(b) + 1 */ + + while (!libj2_j2u_is_zero(a) && e--) { + if (libj2_j2u_lsh_to_j2u_overflow(&d, e, &c)) + continue; + if (libj2_j2u_gt_j2u(&c, a)) + continue; + if (e < LIBJ2_JU_BIT) + q.low |= (uintmax_t)1 << e; + else + q.high |= (uintmax_t)1 << (e - LIBJ2_JU_BIT); + libj2_j2u_sub_j2u(a, &c); + } + +out: + *res_q = q; +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, and remainder of two unsigned + * double-max precision integers + * + * `libj2_j2u_divmod_j2u_to_j2u_j2u(a, b, res_q, res_r)` + * implements `*res_q = *a / *b, *res_r = *a % *b` + * + * For the quotient q, and remainder r, + * dividend n, and divisor d, it will be true + * that qd + r = n + * + * @param a The dividend (left-hand) + * @param b The divisor (right-hand) + * @param res_q Output parameter for the quotient + * @param res_r Output parameter for the remainder + */ +inline void +libj2_j2u_divmod_j2u_to_j2u_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, + struct libj2_j2u *res_q, struct libj2_j2u *res_r) +{ + if (res_r == b) { + struct libj2_j2u r = *a; + libj2_j2u_divmod_j2u_to_j2u(&r, b, res_q); + *res_r = r; + } else { + *res_r = *a; + libj2_j2u_divmod_j2u_to_j2u(res_r, b, res_q); + } +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, and remainder of two unsigned + * double-max precision integers + * + * `libj2_j2u_divmod_j2u(a, b)` implements + * `t = (uintmax_t)(*a / *b), *a %= *b, t` + * (using an intermediate variable `t`) + * + * For the quotient q, and remainder r, + * dividend n, and divisor d, it will be true + * that qd + r = n; however the high half + * of the q is discarded in this function's + * return value + * + * @param a The dividend (left-hand), also used as + * the output parameter for the remainder + * @param b The divisor (right-hand) + * @return The low half of the quotient + */ +inline uintmax_t +libj2_j2u_divmod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + struct libj2_j2u res; + libj2_j2u_divmod_j2u_to_j2u(a, b, &res); + return res.low; +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, and remainder of an unsigned + * double-max precision integer (dividend) and + * an unsigned max precision integer (divisor) + * + * `libj2_j2u_divmod_ju(a, b)` implements + * `t = (uintmax_t)(*a / b), *a %= b, t` + * (using an intermediate variable `t`) + * + * For the quotient q, and remainder r, + * dividend n, and divisor d, it will be true + * that qd + r = n; however the high half + * of the q is discarded in this function's + * return value + * + * @param a The dividend (left-hand), also used as + * the output parameter for the remainder + * @param b The divisor (right-hand) + * @return The low half of the quotient + */ +inline uintmax_t +libj2_j2u_divmod_ju(struct libj2_j2u *a, uintmax_t b) +{ + uintmax_t q = 0; + struct libj2_j2u c; + unsigned e = LIBJ2_J2U_BIT; + a->high %= b; + while (a->high && e--) { + if (libj2_ju_lsh_to_j2u_overflow(b, e, &c)) + continue; + if (libj2_j2u_gt_j2u(&c, a)) + continue; + q |= (uintmax_t)1 << e; + libj2_j2u_sub_j2u(a, &c); + } + q += a->low / b; + a->low %= b; + return q; +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, and remainder of an unsigned + * double-max precision integer (dividend) and + * an unsigned max precision integer (divisor) + * + * `libj2_j2u_divmod_ju_to_j2u(a, b, res_q)` + * implements `*res_q = *a / b, *a %= b` + * + * For the quotient q, and remainder r, + * dividend n, and divisor d, it will be true + * that qd + r = n + * + * @param a The dividend (left-hand), also used as + * the output parameter for the remainder + * @param b The divisor (right-hand) + * @param res_q Output parameter for the quotient + */ +inline void +libj2_j2u_divmod_ju_to_j2u(struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res_q) +{ + res_q->high = a->high / b; + res_q->low = libj2_j2u_divmod_ju(a, b); +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, and remainder of an unsigned + * double-max precision integer (dividend) and + * an unsigned max precision integer (divisor) + * + * `libj2_j2u_divmod_ju_to_j2u_j2u(a, b, res_q, res_r)` + * implements `*res_q = *a / b, *res_r = *a % b` + * + * For the quotient q, and remainder r, + * dividend n, and divisor d, it will be true + * that qd + r = n + * + * @param a The dividend (left-hand) + * @param b The divisor (right-hand) + * @param res_q Output parameter for the quotient + * @param res_r Output parameter for the remainder + */ +inline void +libj2_j2u_divmod_ju_to_j2u_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res_q, struct libj2_j2u *res_r) +{ + *res_r = *a; + res_q->high = res_r->high / b; + res_q->low = libj2_j2u_divmod_ju(res_r, b); +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, and remainder of two unsigned + * double-max precision integers; in this variant + * of `libj2_j2u_rdivmod_j2u_to_j2u`, the dividend + * (left-hand) is the second parameter and the + * divisor (right-hand) is the first parameter + * + * `libj2_j2u_rdivmod_j2u_to_j2u(a, b, res_q)` + * implements `*res_q = *b / *a, *a = *b % *a` + * + * For the quotient q, and remainder r, + * dividend n, and divisor d, it will be true + * that qd + r = n + * + * @param a The divisor (right-hand), also used as + * the output parameter for the remainder + * @param b The dividend (left-hand) + * @param res_q Output parameter for the quotient + */ +inline void +libj2_j2u_rdivmod_j2u_to_j2u(struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res_q) +{ + struct libj2_j2u res_r; + libj2_j2u_divmod_j2u_to_j2u_j2u(b, a, res_q, &res_r); + *a = res_r; +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, and remainder of two unsigned + * double-max precision integers; in this variant + * of `libj2_j2u_rdivmod_j2u_to_j2u`, the dividend + * (left-hand) is the second parameter and the + * divisor (right-hand) is the first parameter + * + * `libj2_j2u_rdivmod_j2u(a, b)` implements + * `t = (uintmax_t)(*b / *a), *a = *b % *a, t` + * (using an intermediate variable `t`) + * + * For the quotient q, and remainder r, + * dividend n, and divisor d, it will be true + * that qd + r = n; however the high half + * of the q is discarded in this function's + * return value + * + * @param a The divisor (right-hand), also used as + * the output parameter for the remainder + * @param b The dividend (left-hand) + * @return The low half of the quotient + */ +inline uintmax_t +libj2_j2u_rdivmod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + struct libj2_j2u q; + libj2_j2u_divmod_j2u_to_j2u_j2u(b, a, &q, a); + return q.low; +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, of two unsigned double-max + * precision integers + * + * `libj2_j2u_div_j2u(a, b)` implements `*a /= *b` + * + * @param a The dividend (left-hand), also used as + * the output parameter for the quotient + * @param b The divisor (right-hand) + */ +inline void +libj2_j2u_div_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + struct libj2_j2u c = *a; + libj2_j2u_divmod_j2u_to_j2u(&c, b, a); +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, of two unsigned double-max + * precision integers + * + * `libj2_j2u_div_j2u_to_j2u(a, b, res)` + * implements `*res = *a / *b` + * + * @param a The dividend (left-hand) + * @param b The divisor (right-hand) + * @param res Output parameter for the quotient + */ +inline void +libj2_j2u_div_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + struct libj2_j2u c = *a; + libj2_j2u_divmod_j2u_to_j2u(&c, b, res); +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, of two unsigned double-max + * precision integers + * + * `libj2_j2u_div_j2u_return(a, b)` + * implements `(uintmax_t)(*a / *b)` + * + * @param a The dividend (left-hand) + * @param b The divisor (right-hand) + * @return The low half of the quotient + */ +inline uintmax_t +libj2_j2u_div_j2u_return(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + struct libj2_j2u c = *a; + return libj2_j2u_divmod_j2u(&c, b); +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, of two unsigned double-max + * precision integers; in this variant + * of `libj2_j2u_div_j2u`, the dividend + * (left-hand) is the second parameter and the + * divisor (right-hand) is the first parameter + * + * `libj2_j2u_rdiv_j2u(a, b)` implements `*a = *b / *a` + * + * @param a The divisor (right-hand), also used as + * the output parameter for the quotient + * @param b The dividend (left-hand) + */ +inline void +libj2_j2u_rdiv_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + struct libj2_j2u c = *b; + libj2_j2u_divmod_j2u_to_j2u(&c, a, a); +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, of an unsigned double-max + * precision integer (dividend) and an + * unsigned max precision integer (divisor) + * + * `libj2_j2u_div_ju(a, b)` implements `*a /= b` + * + * @param a The dividend (left-hand), also used as + * the output parameter for the quotient + * @param b The divisor (right-hand) + */ +inline void +libj2_j2u_div_ju(struct libj2_j2u *a, uintmax_t b) +{ + struct libj2_j2u c = *a; + libj2_j2u_divmod_ju_to_j2u(&c, b, a); +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, of an unsigned double-max + * precision integer (dividend) and an + * unsigned max precision integer (divisor) + * + * `libj2_j2u_div_ju_to_j2u(a, b, res)` + * implements `*res = *a / b` + * + * @param a The dividend (left-hand) + * @param b The divisor (right-hand) + * @param res Output parameter for the quotient + */ +inline void +libj2_j2u_div_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + struct libj2_j2u c = *a; + libj2_j2u_divmod_ju_to_j2u(&c, b, res); +} + + +/** + * Calculate the integer quotient, rounded + * towards zero, of an unsigned double-max + * precision integer (dividend) and an + * unsigned max precision integer (divisor) + * + * `libj2_j2u_div_ju_return(a, b)` + * implements `(uintmax_t)(*a / b)` + * + * @param a The dividend (left-hand) + * @param b The divisor (right-hand) + * @return The low half of the quotient + */ +inline uintmax_t +libj2_j2u_div_ju_return(const struct libj2_j2u *a, uintmax_t b) +{ + struct libj2_j2u c = *a; + return libj2_j2u_divmod_ju(&c, b); +} + + +/** + * Calculate the integer remainder, for integer + * division with the quotient rounded towards zero, + * of two unsigned double-max precision integers + * + * `libj2_j2u_mod_j2u(a, b)` implements `*a %= *b` + * + * @param a The dividend (left-hand), also used as + * the output parameter for the remainder + * @param b The divisor (right-hand) + */ +inline void +libj2_j2u_mod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + (void) libj2_j2u_divmod_j2u(a, b); +} + + +/** + * Calculate the integer remainder, for integer + * division with the quotient rounded towards zero, + * of two unsigned double-max precision integers + * + * `libj2_j2u_mod_j2u_to_j2u(a, b, res)` + * implements `*res = *a % *b` + * + * @param a The dividend (left-hand) + * @param b The divisor (right-hand) + * @param res Output parameter for the remainder + */ +inline void +libj2_j2u_mod_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + if (res == b) { + struct libj2_j2u r = *a; + libj2_j2u_mod_j2u(&r, b); + *res = r; + } else { + *res = *a; + libj2_j2u_mod_j2u(res, b); + } +} + + +/** + * Calculate the integer remainder, for integer + * division with the quotient rounded towards zero, + * of two unsigned double-max precision integers; + * in this variant of `libj2_j2u_mod_j2u`, the + * dividend (left-hand) is the second parameter + * and the divisor (right-hand) is the first parameter + * + * `libj2_j2u_rmod_j2u_to_j2u(a, b)` implements + * `*a = *b % *a` + * + * @param a The divisor (right-hand), also used as + * the output parameter for the remainder + * @param b The dividend (left-hand) + */ +inline void +libj2_j2u_rmod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + libj2_j2u_mod_j2u_to_j2u(b, a, a); +} + + +/** + * Calculate the integer remainder, for integer + * division with the quotient rounded towards zero, + * of an unsigned double-max precision integer + * (dividend) and an unsigned max precision + * integer (divisor) + * + * `libj2_j2u_mod_ju(a, b)` implements `*a %= b` + * + * @param a The dividend (left-hand), also used as + * the output parameter for the remainder + * @param b The divisor (right-hand) + */ +inline void +libj2_j2u_mod_ju(struct libj2_j2u *a, uintmax_t b) +{ + struct libj2_j2u c; + unsigned e = LIBJ2_JU_BIT; + a->high %= b; + while (a->high && e--) { + libj2_ju_lsh_to_j2u(b, e, &c); + if (libj2_j2u_gt_j2u(&c, a)) + continue; + libj2_j2u_sub_j2u(a, &c); + } + a->low %= b; +} + + +/** + * Calculate the integer remainder, for integer + * division with the quotient rounded towards zero, + * of an unsigned double-max precision integer + * (dividend) and an unsigned max precision + * integer (divisor) + * + * `libj2_j2u_mod_ju_to_j2u(a, b, res)` + * implements `*res = *a % b` + * + * @param a The dividend (left-hand) + * @param b The divisor (right-hand) + * @param res Output parameter for the remainder + */ +inline void +libj2_j2u_mod_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + *res = *a; + libj2_j2u_mod_ju(res, b); +} diff --git a/libj2/multiplication.h b/libj2/multiplication.h new file mode 100644 index 0000000..005fa5d --- /dev/null +++ b/libj2/multiplication.h @@ -0,0 +1,366 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBJ2_H +# error Do not include this header directly, include <libj2.h> instead +#endif + + +/** + * Calculate the unsigned double-max precision integer + * product of two unsigned double-max precision integers + * + * `libj2_ju_mul_ju_to_j2u(a, b, res)` implements + * `*res = a * b`, where `a` and `b` are converted + * into `struct libj2_j2u`'s + * + * @param a The multiplier + * @param b The multiplicand + * @param res Output parameter for the product + */ +inline void +libj2_ju_mul_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *res) +{ + const int n = (int)LIBJ2_JU_BIT / 2; + uintmax_t a1, a2, b1, b2, c, c1, c2; + + a1 = a >> n; + b1 = b >> n; + a2 = a ^ (a1 << n); + b2 = b ^ (b1 << n); + + res->high = a1 * b1; + res->low = a2 * b2; + + c = a1 * b2; + c1 = c >> n; + c2 = c ^ (c1 << n); + c2 <<= n; + res->high += c1; +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_add_overflow(res->low, c2, &res->low)) + res->high += 1U; +#else + if (res->low > UINTMAX_MAX - c2) + res->high += 1U; + res->low += c2; +#endif + + c = a2 * b1; + c1 = c >> n; + c2 = c ^ (c1 << n); + c2 <<= n; + res->high += c1; +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_add_overflow(res->low, c2, &res->low)) + res->high += 1U; +#else + if (res->low > UINTMAX_MAX - c2) + res->high += 1U; + res->low += c2; +#endif +} + + +/** + * Calculate the product of an unsigned double-max + * precision integer (multiplier) and an unsigned + * max precision integer (multiplicand) + * + * `libj2_j2u_mul_ju_to_j2u(a, b)` implements `*a *= b`, + * where `b` are converted into an `struct libj2_j2u` + * + * @param a The multiplier, also used as the + * output parameter for the product + * @param b The multiplicand + */ +inline void +libj2_j2u_mul_ju(struct libj2_j2u *a, uintmax_t b) +{ + uintmax_t c = a->high * b; + libj2_ju_mul_ju_to_j2u(a->low, b, a); + a->high += c; +} + + +/** + * Calculate the product of an unsigned double-max + * precision integer (multiplier) and an unsigned + * max precision integer (multiplicand) + * + * `libj2_j2u_mul_ju_to_j2u(a, b, res)` implements + * `*res = *a * b`, where `b` are converted into + * an `struct libj2_j2u` + * + * @param a The multiplier + * @param b The multiplicand + * @param res Output parameter for the product + */ +inline void +libj2_j2u_mul_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + *res = *a; + libj2_j2u_mul_ju(res, b); +} + + +/** + * Calculate the product of an unsigned max + * precision integer (multiplier) and an unsigned + * double-max precision integer (multiplicand) + * + * `libj2_ju_mul_j2u_to_j2u(a, b, res)` implements + * `*res = a * *b`, where `a` are converted into + * an `struct libj2_j2u` + * + * @param a The multiplier + * @param b The multiplicand + * @param res Output parameter for the product + */ +inline void +libj2_ju_mul_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + *res = *b; + libj2_j2u_mul_ju(res, a); +} + + +/** + * Calculate the product of an unsigned double-max + * precision integer (multiplier) and an unsigned + * max precision integer (multiplicand) + * + * `libj2_j2u_mul_ju_to_overflow(a, b)` implements + * `*a *= b`, where `b` are converted into an + * `struct libj2_j2u`, with overflow-detection + * + * @param a The multiplier, also used as the + * output parameter for the product + * @param b The multiplicand + * @return 1 if the result overflowed, 0 otherwise + */ +inline int +libj2_j2u_mul_ju_overflow(struct libj2_j2u *a, uintmax_t b) +{ + int overflow = 0; + uintmax_t c; + +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + overflow |= __builtin_mul_overflow(a->high, b, &c); +#else + if (b && a->high > UINTMAX_MAX / b) + overflow = 1; + c = a->high * b; +#endif + + libj2_ju_mul_ju_to_j2u(a->low, b, a); + +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + overflow |= __builtin_add_overflow(a->high, c, &a->high); +#else + if (a->high > UINTMAX_MAX - c) + overflow = 1; + a->high += c; +#endif + + return overflow; +} + + +/** + * Calculate the product of an unsigned double-max + * precision integer (multiplier) and an unsigned + * max precision integer (multiplicand) + * + * `libj2_j2u_mul_ju_to_j2u_overflow(a, b, res)` + * implements `*res = *a * b`, where `b` are + * converted into an `struct libj2_j2u`, with + * overflow-detection + * + * @param a The multiplier + * @param b The multiplicand + * @param res Output parameter for the product + * @return 1 if the result overflowed, 0 otherwise + */ +inline int +libj2_j2u_mul_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + *res = *a; + return libj2_j2u_mul_ju_overflow(res, b); +} + + +/** + * Calculate the product of an unsigned max + * precision integer (multiplier) and an unsigned + * double-max precision integer (multiplicand) + * + * `libj2_ju_mul_j2u_to_j2u_overflow(a, b, res)` + * implements `*res = a * *b`, where `a` are + * converted into an `struct libj2_j2u`, with + * overflow-detection + * + * @param a The multiplier + * @param b The multiplicand + * @param res Output parameter for the product + * @return 1 if the result overflowed, 0 otherwise + */ +inline int +libj2_ju_mul_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + *res = *b; + return libj2_j2u_mul_ju_overflow(res, a); +} + + +/** + * Calculate the product of two unsigned double-max + * precision integers + * + * `libj2_j2u_mul_j2u_destructive(a, b)` + * implements `*a *= *b`, except that `*b` + * will be arbitrarily modified + * + * @param a The multiplier, also used as the + * output parameter for the product + * @param b The multiplicand; will be tainted + * + * `a` and `b` must not be the same pointers + */ +inline void +libj2_j2u_mul_j2u_destructive(struct libj2_j2u *restrict a /* result */, struct libj2_j2u *restrict b /* destructed */) +{ + a->high *= b->low; + b->high *= a->low; + b->high += a->high; + + libj2_ju_mul_ju_to_j2u(a->low, b->low, a); + a->high += b->high; +} + + +/** + * Calculate the product of two unsigned double-max + * precision integers + * + * `libj2_j2u_mul_j2u(a, b)` implements `*a *= *b` + * + * @param a The multiplier, also used as the + * output parameter for the product + * @param b The multiplicand + */ +inline void +libj2_j2u_mul_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + struct libj2_j2u c = *b; + libj2_j2u_mul_j2u_destructive(a, &c); +} + + +/** + * Calculate the product of two unsigned double-max + * precision integers + * + * `libj2_j2u_mul_j2u_overflow_destructive(a, b)` + * implements `*a *= *b`, except that `*b` + * will be arbitrarily modified, with + * overflow-detection + * + * @param a The multiplier, also used as the + * output parameter for the product + * @param b The multiplicand; will be tainted + * @return 1 if the result overflowed, 0 otherwise + * + * `a` and `b` must not be the same pointers + */ +inline int +libj2_j2u_mul_j2u_overflow_destructive(struct libj2_j2u *restrict a /* result */, struct libj2_j2u *restrict b /* destructed */) +{ + int overflow = a->high && b->high; + +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + overflow |= __builtin_mul_overflow(a->high, b->low, &a->high); + overflow |= __builtin_mul_overflow(b->high, a->low, &b->high); + overflow |= __builtin_add_overflow(b->high, a->high, &b->high); +#else + if (b->low && a->high > UINTMAX_MAX / b->low) + overflow = 1; + a->high *= b->low; + if (a->low && b->high > UINTMAX_MAX / a->low) + overflow = 1; + b->high *= a->low; + if (b->high > UINTMAX_MAX - a->high) + overflow = 1; + b->high += a->high; +#endif + + libj2_ju_mul_ju_to_j2u(a->low, b->low, a); + +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + overflow |= __builtin_add_overflow(a->high, b->high, &a->high); +#else + if (a->high > UINTMAX_MAX - b->high) + overflow = 1; + a->high += b->high; +#endif + + return overflow; +} + + +/** + * Calculate the product of two unsigned double-max + * precision integers + * + * `libj2_j2u_mul_j2u_overflow(a, b)` implements + * `*a *= *b` with overflow-detection + * + * @param a The multiplier, also used as the + * output parameter for the product + * @param b The multiplicand + * @return 1 if the result overflowed, 0 otherwise + */ +inline int +libj2_j2u_mul_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + struct libj2_j2u c = *b; + return libj2_j2u_mul_j2u_overflow_destructive(a, &c); +} + + +/** + * Calculate the product of two unsigned double-max + * precision integers + * + * `libj2_j2u_mul_j2u_to_j2u(a, b, res)` + * implements `*res = *a * *b` + * + * @param a The multiplier + * @param b The multiplicand + * @param res Output parameter for the product + */ +inline void +libj2_j2u_mul_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + struct libj2_j2u c = *b; + *res = *a; + libj2_j2u_mul_j2u_destructive(res, &c); +} + +/** + * Calculate the product of two unsigned double-max + * precision integers + * + * `libj2_j2u_mul_j2u_to_j2u_overflow(a, b, res)` + * implements `*res = *a * *b` with overflow-detection + * + * @param a The multiplier + * @param b The multiplicand + * @param res Output parameter for the product + * @return 1 if the result overflowed, 0 otherwise + */ +inline int +libj2_j2u_mul_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + struct libj2_j2u c = *b; + *res = *a; + return libj2_j2u_mul_j2u_overflow_destructive(res, &c); +} diff --git a/libj2/sign-shifting.h b/libj2/sign-shifting.h new file mode 100644 index 0000000..034259e --- /dev/null +++ b/libj2/sign-shifting.h @@ -0,0 +1,43 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBJ2_H +# error Do not include this header directly, include <libj2.h> instead +#endif + + +/** + * Calculate the additive inverse of an unsigned + * double-max precision integer + * + * `libj2_minus_j2u(a)` implements `*a = -*a` + * + * @param a The integer to invert, also used as the + * output parameter for the inverse + */ +inline void +libj2_minus_j2u(struct libj2_j2u *a) +{ + a->high = -a->high; + if (a->low) { + a->high -= 1U; + a->low = -a->low; + } +} + + +/** + * Calculate the additive inverse of an unsigned + * double-max precision integer + * + * `libj2_minus_j2u_j2u(a, res)` implements `*res = -*a` + * + * @param a The integer to invert + * @param res Output parameter for the inverse + */ +inline void +libj2_minus_j2u_to_j2u(const struct libj2_j2u *a, struct libj2_j2u *res) +{ + res->high = -a->high; + if (a->low) + res->high -= 1U; + res->low = -a->low; +} diff --git a/libj2/signum.h b/libj2/signum.h new file mode 100644 index 0000000..7ae1833 --- /dev/null +++ b/libj2/signum.h @@ -0,0 +1,45 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBJ2_H +# error Do not include this header directly, include <libj2.h> instead +#endif + + +/** + * Check whether an unsigned double-max precision integer has a + * positive value (or equivalently, a non-zero value) + * + * `libj2_j2u_is_positive(a)` implements `*a > 0` + * + * @param a The integer to inspect + * @return 1 if `a` has a positive value, 0 otherwise + */ +inline int +libj2_j2u_is_positive(const struct libj2_j2u *a) +{ + return a->high || a->low; +} + + +/** + * Get the sign (signum function) of an unsigned double-max + * precision integer + * + * `libj2_sgn_j2u(a)` implements `*a < 0 ? -1 : *a > 0 ? +1 : 0`, + * or equaivalently, since `a` is unsigned, `*a > 0 ? +1 : 0` + * + * Since the integer type is unsigned, this function + * does the same thing as `libj2_j2u_is_positive(res)` + * + * @param a The integer to inspect + * @return -1 if `a` is negative (impossible), + * +1 if `a` is positive, and + * 0 if `a` is 0 + */ +inline int +libj2_sgn_j2u(const struct libj2_j2u *a) +{ + return libj2_j2u_is_positive(a); +} + + +/* libj2_j2u_is_zero is located in constants.h */ diff --git a/libj2/subtraction.h b/libj2/subtraction.h new file mode 100644 index 0000000..27ae9d6 --- /dev/null +++ b/libj2/subtraction.h @@ -0,0 +1,493 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBJ2_H +# error Do not include this header directly, include <libj2.h> instead +#endif + + +/** + * Calculate the difference between an unsigned + * double-max precision integer (minuend) and an + * unsigned max precision integer (subtrahend) + * + * `libj2_j2u_sub_ju(a, b)` implements `*a -= b` + * + * @param a The minuend (left-hand), also used as the + * output parameter for the difference + * @param b The subtrahend (right-hand) + */ +inline void +libj2_j2u_sub_ju(struct libj2_j2u *a, uintmax_t b) +{ +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_sub_overflow(a->low, b, &a->low)) + a->high -= 1U; +#else + if (a->low < b) + a->high -= 1U; + a->low -= b; +#endif +} + + +/** + * Calculate the difference between an unsigned + * double-max precision integer (minuend) and an + * unsigned max precision integer (subtrahend) + * + * `libj2_j2u_sub_ju_overflow(a, b)` implements `*a -= b` + * with overflow-detection + * + * @param a The minuend (left-hand), also used as the + * output parameter for the difference + * @param b The subtrahend (right-hand) + * @return 1 if the result overflowed (`b` is greater than `*a`), + * so the result wrapped around (actual difference is + * negative), 0 otherwise + */ +inline int +libj2_j2u_sub_ju_overflow(struct libj2_j2u *a, uintmax_t b) +{ +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_sub_overflow(a->low, b, &a->low)) + return __builtin_sub_overflow(a->high, 1U, &a->high); + return 0; +#else + int overflow = 0; + if (a->low < b) { + if (!a->high) + overflow = 1; + a->high -= 1U; + } + a->low -= b; + return overflow; +#endif +} + + +/** + * Calculate the difference between an unsigned + * double-max precision integer (minuend) and an + * unsigned max precision integer (subtrahend) + * + * `libj2_j2u_sub_ju_to_j2u(a, b, res)` + * implements `*res = *a - b` + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @param res Output parameter for the difference + */ +inline void +libj2_j2u_sub_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + res->high = a->high; +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_sub_overflow(a->low, b, &res->low)) + res->high -= 1U; +#else + if (a->low < b) + res->high -= 1U; + res->low = a->low - b; +#endif +} + + +/** + * Calculate the difference between an unsigned + * double-max precision integer (minuend) and an + * unsigned max precision integer (subtrahend) + * + * `libj2_j2u_sub_ju_to_j2u_overflow(a, b, res)` + * implements `*res = *a - b` with overflow-detection + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @param res Output parameter for the difference + * @return 1 if the result overflowed (`b` is greater than `*a`), + * so the result wrapped around (actual difference is + * negative), 0 otherwise + */ +inline int +libj2_j2u_sub_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_sub_overflow(a->low, b, &res->low)) + return __builtin_sub_overflow(a->high, 1U, &res->high); + res->high = a->high; + return 0; +#else + int overflow = 0; + res->high = a->high; + if (a->low < b) { + if (!a->high) + overflow = 1; + res->high -= 1U; + } + res->low = a->low - b; + return overflow; +#endif +} + + +/** + * Calculate the difference between two unsigned + * max precision integers, as an unsigned double-max + * precision integer + * + * `libj2_ju_sub_ju_to_j2u_overflow(a, b, res)` + * implements `*res = a - b`, where `a` and `b` + * are converted into `struct libj2_j2u`'s + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @param res Output parameter for the difference + */ +inline void +libj2_ju_sub_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *res) +{ +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + res->high = -(uintmax_t)(__builtin_sub_overflow(a, b, &res->low) ? 1U : 0U); +#else + res->high = -(uintmax_t)(a < b); + res->low = a - b; +#endif +} + + +/** + * Calculate the difference between two unsigned + * max precision integers, as an unsigned double-max + * precision integer + * + * `libj2_ju_sub_ju_to_j2u_overflow(a, b, res)` + * implements `*res = a - b` with overflow-detection, + * and where `a` and `b` are converted into + * `struct libj2_j2u`'s + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @param res Output parameter for the difference + * @return 1 if the result overflowed (`b` is greater than `*a`), + * so the result wrapped around (actual difference is + * negative), 0 otherwise + */ +inline int +libj2_ju_sub_ju_to_j2u_overflow(uintmax_t a, uintmax_t b, struct libj2_j2u *res) +{ + int overflow; +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + overflow = __builtin_sub_overflow(a, b, &res->low) ? 1 : 0; +#else + overflow = a < b; + res->low = a - b; +#endif + res->high = -(uintmax_t)overflow; + return overflow; +} + + +/** + * Calculate the difference between two unsigned + * double-max precision integers + * + * `libj2_j2u_sub_j2u(a, b)` implements `*a -= *b` + * + * @param a The minuend (left-hand), also used + * as the output parameter for the difference + * @param b The subtrahend (right-hand) + */ +inline void +libj2_j2u_sub_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + libj2_j2u_sub_ju(a, b->low); + a->high -= b->high; +} + + +/** + * Calculate the difference between two unsigned + * double-max precision integers + * + * `libj2_j2u_sub_j2u_to_j2u(a, b, res)` implements + * `*res = *a - *b` + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @param res Output parameter for the difference + */ +inline void +libj2_j2u_sub_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + if (a == b) { + libj2_j2u_zero(res); + } else if (res == b) { + libj2_minus_j2u(res); + libj2_j2u_add_j2u(res, a); + } else { + libj2_j2u_sub_ju_to_j2u(a, b->low, res); + res->high -= b->high; + } +} + + +/** + * Calculate the difference between two unsigned + * double-max precision integers + * + * `libj2_j2u_sub_j2u_overflow(a, b)` + * implements `*a -= *b` with overflow-detection + * + * @param a The minuend (left-hand), also used + * as the output parameter for the difference + * @param b The subtrahend (right-hand) + * @return 1 if the result overflowed (`b` is greater than `*a`), + * so the result wrapped around (actual difference is + * negative), 0 otherwise + */ +inline int +libj2_j2u_sub_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + int overflow = libj2_j2u_sub_ju_overflow(a, b->low); +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + return __builtin_sub_overflow(a->high, b->high, &a->high) || overflow; +#else + if (a->high < b->high) + overflow = 1; + a->high -= b->high; + return overflow; +#endif +} + + +/** + * Calculate the difference between two unsigned + * double-max precision integers + * + * `libj2_j2u_sub_j2u_to_j2u_overflow(a, b, res)` + * implements `*res = *a - *b` with overflow-detection + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @param res Output parameter for the difference + * @return 1 if the result overflowed (`b` is greater than `*a`), + * so the result wrapped around (actual difference is + * negative), 0 otherwise + */ +inline int +libj2_j2u_sub_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + if (a == b) { + libj2_j2u_zero(res); + return 0; + } else if (res == b) { + int overflow = libj2_j2u_lt_j2u(a, res); + libj2_minus_j2u(res); + libj2_j2u_add_j2u(res, a); + return overflow; + } else { + int overflow = libj2_j2u_sub_ju_to_j2u_overflow(a, b->low, res); +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + return __builtin_sub_overflow(res->high, b->high, &res->high) || overflow; +#else + if (res->high < b->high) + overflow = 1; + res->high -= b->high; + return overflow; +#endif + } +} + + +/** + * Calculate the difference between an unsigned + * max precision integer (minuend) and an unsigned + * double-max precision integer (subtrahend) + * + * `libj2_ju_sub_j2u_to_j2u(a, b, res)` + * implements `*res = a - *b` + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @param res Output parameter for the difference + */ +inline void +libj2_ju_sub_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + if (res == b) { + libj2_minus_j2u(res); + libj2_j2u_add_ju(res, a); + } else { + res->high = 0; + res->low = a; + libj2_j2u_sub_j2u(res, b); + } +} + + +/** + * Calculate the difference between an unsigned + * max precision integer (minuend) and an unsigned + * double-max precision integer (subtrahend) + * + * `libj2_ju_sub_j2u_to_j2u_overflow(a, b, res)` + * implements `*res = a - *b` with overflow-detection + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @param res Output parameter for the difference + * @return 1 if the result overflowed (`*b` is greater than `a`), + * so the result wrapped around (actual difference is + * negative), 0 otherwise + */ +inline int +libj2_ju_sub_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + if (res == b) { + int overflow = b->high || b->low > a; + libj2_minus_j2u(res); + libj2_j2u_add_ju(res, a); + return overflow; + } else { + res->high = 0; + res->low = a; + return libj2_j2u_sub_j2u_overflow(res, b); + } +} + + +/** + * Calculate the difference between two unsigned + * max precision integers; in this variant of + * `libj2_j2u_sub_j2u`, the minuend (left-hand) + * is the second parameter and the subtrahend + * (right-hand) is the first parameter + * + * `libj2_j2u_rsub_j2u(a, b, res)` implements + * `*a = *b - *a` + * + * @param a The subtrahend (right-hand), also used as + * the output parameter for the difference + * @param b The minuend (left-hand) + */ +inline void +libj2_j2u_rsub_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + a->high = b->high - a->high; +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_sub_overflow(b->low, a->low, &a->low)) + a->high -= 1U; +#else + if (a->low > b->low) + a->high -= 1U; + a->low = b->low - a->low; +#endif +} + + +/** + * Calculate the difference between two unsigned + * max precision integers; in this variant of + * `libj2_j2u_sub_j2u`, the minuend (left-hand) + * is the second parameter and the subtrahend + * (right-hand) is the first parameter + * + * `libj2_j2u_rsub_j2u_overflow(a, b, res)` + * implements `*a = *b - *a` with overflow-detection + * + * @param a The subtrahend (right-hand), also used as + * the output parameter for the difference + * @param b The minuend (left-hand) + * @return 1 if the result overflowed (`*a` is greater than `*b`), + * so the result wrapped around (actual difference is + * negative), 0 otherwise + */ +inline int +libj2_j2u_rsub_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + int overflow; +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + overflow = __builtin_sub_overflow(b->high, a->high, &a->high); + if (__builtin_sub_overflow(b->low, a->low, &a->low)) + overflow |= __builtin_sub_overflow(a->high, 1U, &a->high); +#else + overflow = b->high < a->high; + a->high = b->high - a->high; + if (b->low < a->low) { + if (!a->high) + overflow = 1; + a->high -= 1U; + } + a->low = b->low - a->low; +#endif + return overflow; +} + + +/** + * Calculate the difference between an unsigned + * max precision integer (minuend) and an unsigned + * double-max precision integer (subtrahend); + * in this variant of `libj2_j2u_sub_ju`, the + * minuend (left-hand) is the second parameter + * and the subtrahend (right-hand) is the first + * parameter + * + * `libj2_j2u_rsub_ju(a, b, res)` implements `*a = b - *a` + * + * @param a The subtrahend (right-hand), also used as + * the output parameter for the difference + * @param b The minuend (left-hand) + */ +inline void +libj2_j2u_rsub_ju(struct libj2_j2u *a, uintmax_t b) +{ + a->high = -a->high; +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_sub_overflow(b, a->low, &a->low)) + a->high -= 1U; +#else + if (a->low > b) + a->high -= 1U; + a->low = b - a->low; +#endif +} + + +/** + * Calculate the difference between an unsigned + * max precision integer (minuend) and an unsigned + * double-max precision integer (subtrahend); + * in this variant of `libj2_j2u_sub_ju`, the + * minuend (left-hand) is the second parameter + * and the subtrahend (right-hand) is the first + * parameter + * + * `libj2_j2u_rsub_ju_overflow(a, b, res)` + * implements `*a = b - *a` with overflow-detection + * + * @param a The subtrahend (right-hand), also used as + * the output parameter for the difference + * @param b The minuend (left-hand) + * @return 1 if the result overflowed (`*a` is greater than `b`), + * so the result wrapped around (actual difference is + * negative), 0 otherwise + */ +inline int +libj2_j2u_rsub_ju_overflow(struct libj2_j2u *a, uintmax_t b) +{ + int overflow = !!a->high; + a->high = -a->high; +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_sub_overflow(b, a->low, &a->low)) + overflow |= __builtin_sub_overflow(a->high, 1U, &a->high); +#else + if (a->low > b) { + if (!a->high) + overflow = 1; + a->high -= 1U; + } + if (b < a->low) + overflow = 1; + a->low = b - a->low; +#endif + return overflow; +} diff --git a/libj2/unsigned-comparsion.h b/libj2/unsigned-comparsion.h new file mode 100644 index 0000000..3362753 --- /dev/null +++ b/libj2/unsigned-comparsion.h @@ -0,0 +1,774 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBJ2_H +# error Do not include this header directly, include <libj2.h> instead +#endif + + + +/** + * Check whether an unsigned double-max precision integer is + * less than another unsigned double-max precision integer + * + * `libj2_j2u_lt_j2u(a, b)` implements `*a < *b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `*a` is less than `*b`, 0 otherwise + */ +inline int +libj2_j2u_lt_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + return a->high < b->high || (a->high == b->high && a->low < b->low); +} + + +/** + * Check whether an unsigned double-max precision integer is less + * than or equal to another unsigned double-max precision integer + * + * `libj2_j2u_le_j2u(a, b)` implements `*a <= *b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `*a` is less than or equal to `*b`, 0 otherwise + */ +inline int +libj2_j2u_le_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + return a->high < b->high || (a->high == b->high && a->low <= b->low); +} + + +/** + * Check whether an unsigned double-max precision integer is + * greater than another unsigned double-max precision integer + * + * `libj2_j2u_gt_j2u(a, b)` implements `*a > *b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `*a` is greater than `*b`, 0 otherwise + */ +inline int +libj2_j2u_gt_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + return a->high > b->high || (a->high == b->high && a->low > b->low); +} + + +/** + * Check whether an unsigned double-max precision integer is greater + * than or equal to another unsigned double-max precision integer + * + * `libj2_j2u_ge_j2u(a, b)` implements `*a >= *b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `*a` is greater than or equal to `*b`, 0 otherwise + */ +inline int +libj2_j2u_ge_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + return a->high > b->high || (a->high == b->high && a->low >= b->low); +} + + +/** + * Check whether an unsigned double-max precision integer is + * equal to another unsigned double-max precision integer + * + * `libj2_j2u_eq_j2u(a, b)` implements `*a == *b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `*a` is equal to `*b`, 0 otherwise + */ +inline int +libj2_j2u_eq_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + return a->high == b->high && a->low == b->low; +} + + +/** + * Check whether an unsigned double-max precision integer is + * not equal to another unsigned double-max precision integer + * + * `libj2_j2u_eq_j2u(a, b)` implements `*a != *b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `*a` is not equal to `*b`, 0 otherwise + */ +inline int +libj2_j2u_ne_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + return a->high != b->high || a->low != b->low; +} + + +/** + * Compare an unsigned double-max precision integer + * to another unsigned double-max precision integer + * + * `libj2_j2u_cmp_j2u(a, b)` implements `*a < *b ? -1 : *a > *b ? +1 : 0`, + * or equivalently, the signum of `*a - *b` where the signum is 0 for 0 + * + * @param a The left-hand value + * @param b The right-hand value + * @return -1 if `*a` is less than `*b`, + * +1 if `*a` is greater than `*b`, + * 0 if `*a` is equal to `*b` + */ +inline int +libj2_j2u_cmp_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + return a->high < b->high ? -1 : a->high > b->high ? +1 : a->low < b->low ? -1 : a->low > b->low; +} + + +/** + * Check whether an unsigned double-max precision integer + * is less than an unsigned max precision integer + * + * `libj2_j2u_lt_ju(a, b)` implements `*a < b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `*a` is less than `b`, 0 otherwise + */ +inline int +libj2_j2u_lt_ju(const struct libj2_j2u *a, uintmax_t b) +{ + return !a->high && a->low < b; +} + + +/** + * Check whether an unsigned double-max precision integer is + * less than or equal to an unsigned max precision integer + * + * `libj2_j2u_le_ju(a, b)` implements `*a <= b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `*a` is less than or equal to `b`, 0 otherwise + */ +inline int +libj2_j2u_le_ju(const struct libj2_j2u *a, uintmax_t b) +{ + return !a->high && a->low <= b; +} + + +/** + * Check whether an unsigned double-max precision integer + * is greater than an unsigned max precision integer + * + * `libj2_j2u_gt_ju(a, b)` implements `*a > b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `*a` is less than `b`, 0 otherwise + */ +inline int +libj2_j2u_gt_ju(const struct libj2_j2u *a, uintmax_t b) +{ + return a->high || a->low > b; +} + + +/** + * Check whether an unsigned double-max precision integer is + * greater than or equal to an unsigned max precision integer + * + * `libj2_j2u_ge_ju(a, b)` implements `*a >= b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `*a` is greater than or equal to `b`, 0 otherwise + */ +inline int +libj2_j2u_ge_ju(const struct libj2_j2u *a, uintmax_t b) +{ + return a->high || a->low >= b; +} + + +/** + * Check whether an unsigned double-max precision integer + * is equal to an unsigned max precision integer + * + * `libj2_j2u_eq_ju(a, b)` implements `*a == b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `*a` is equal to `b`, 0 otherwise + */ +inline int +libj2_j2u_eq_ju(const struct libj2_j2u *a, uintmax_t b) +{ + return !a->high && a->low == b; +} + + +/** + * Check whether an unsigned double-max precision integer + * is not equal to an unsigned max precision integer + * + * `libj2_j2u_ne_ju(a, b)` implements `*a != b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `*a` is not equal to `b`, 0 otherwise + */ +inline int +libj2_j2u_ne_ju(const struct libj2_j2u *a, uintmax_t b) +{ + return a->high || a->low != b; +} + + +/** + * Compare an unsigned double-max precision integer + * to an unsigned max precision integer + * + * `libj2_j2u_cmp_ju(a, b)` implements `*a < b ? -1 : *a > b ? +1 : 0`, + * or equivalently, the signum of `*a - b` where the signum is 0 for 0 + * + * @param a The left-hand value + * @param b The right-hand value + * @return -1 if `*a` is less than `b`, + * +1 if `*a` is greater than `b`, + * 0 if `*a` is equal to `b` + */ +inline int +libj2_j2u_cmp_ju(const struct libj2_j2u *a, uintmax_t b) +{ + return a->high ? +1 : a->low < b ? -1 : a->low > b; +} + + +/** + * Check whether an unsigned max precision integer is + * less than an unsigned double-max precision integer + * + * `libj2_ju_lt_j2u(a, b)` implements `a < *b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `a` is less than `*b`, 0 otherwise + */ +inline int +libj2_ju_lt_j2u(uintmax_t a, const struct libj2_j2u *b) +{ + return libj2_j2u_gt_ju(b, a); +} + + +/** + * Check whether an unsigned max precision integer is less + * than or equal to an unsigned double-max precision integer + * + * `libj2_ju_le_j2u(a, b)` implements `a <= *b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `a` is less than or equal to `*b`, 0 otherwise + */ +inline int +libj2_ju_le_j2u(uintmax_t a, const struct libj2_j2u *b) +{ + return libj2_j2u_ge_ju(b, a); +} + + +/** + * Check whether an unsigned max precision integer is + * greater than an unsigned double-max precision integer + * + * `libj2_ju_gt_j2u(a, b)` implements `a > *b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `a` is less than `*b`, 0 otherwise + */ +inline int +libj2_ju_gt_j2u(uintmax_t a, const struct libj2_j2u *b) +{ + return libj2_j2u_lt_ju(b, a); +} + + +/** + * Check whether an unsigned max precision integer is greater + * than or equal to an unsigned double-max precision integer + * + * `libj2_ju_ge_j2u(a, b)` implements `a >= *b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `a` is greater than or equal to `*b`, 0 otherwise + */ +inline int +libj2_ju_ge_j2u(uintmax_t a, const struct libj2_j2u *b) +{ + return libj2_j2u_le_ju(b, a); +} + + +/** + * Check whether an unsigned max precision integer is + * equal to an unsigned double-max precision integer + * + * `libj2_ju_eq_j2u(a, b)` implements `a == *b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `a` is equal to `*b`, 0 otherwise + */ +inline int +libj2_ju_eq_j2u(uintmax_t a, const struct libj2_j2u *b) +{ + return libj2_j2u_eq_ju(b, a); +} + + +/** + * Check whether an unsigned max precision integer is + * not equal to an unsigned double-max precision integer + * + * `libj2_ju_ne_j2u(a, b)` implements `a != *b` + * + * @param a The left-hand value + * @param b The right-hand value + * @return 1 if `a` is not equal to `*b`, 0 otherwise + */ +inline int +libj2_ju_ne_j2u(uintmax_t a, const struct libj2_j2u *b) +{ + return libj2_j2u_ne_ju(b, a); +} + + +/** + * Compare an unsigned max precision integer + * to an unsigned double-max precision integer + * + * `libj2_ju_cmp_j2u(a, b)` implements `a < *b ? -1 : a > *b ? +1 : 0`, + * or equivalently, the signum of `a - *b` where the signum is 0 for 0 + * + * @param a The left-hand value + * @param b The right-hand value + * @return -1 if `a` is less than `*b`, + * +1 if `a` is greater than `*b`, + * 0 if `a` is equal to `*b` + */ +inline int +libj2_ju_cmp_j2u(uintmax_t a, const struct libj2_j2u *b) +{ + return b->high ? -1 : a < b->low ? -1 : a > b->low; +} + + + + + +/** + * Get the maximum of two unsigned double-max + * precision integers + * + * `libj2_j2u_max_j2u_to_ju2(a, b, res)` implements + * `*res = *a > *b ? *a : *b` + * + * @param a One of the values + * @param b The other value + * @param res Output parameter for the maximum of `*a` and `*b` + */ +inline void +libj2_j2u_max_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + *res = libj2_j2u_gt_j2u(a, b) ? *a : *b; +} + + +/** + * Get the maximum of two unsigned double-max + * precision integers + * + * `libj2_j2u_max_j2u(a, b)` implements + * `*a = *a > *b ? *a : *b` + * + * @param a One of the values, and output parameter + * for the maximum of `*a` and `*b` + * @param b The other value + */ +inline void +libj2_j2u_max_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + if (libj2_j2u_gt_j2u(b, a)) + *a = *b; +} + + +/** + * Get the maximum of an unsigned double-max + * precision integer and an unsigned precision + * integer + * + * `libj2_j2u_max_ju(a, b)` implements + * `*a = *a > b ? *a : b` + * + * @param a One of the values, and output parameter + * for the maximum of `*a` and `b` + * @param b The other value + */ +inline void +libj2_j2u_max_ju(struct libj2_j2u *a, uintmax_t b) +{ + if (!a->high && a->low < b) + a->low = b; +} + + +/** + * Get the maximum of an unsigned double-max + * precision integer and an unsigned precision + * integer + * + * `libj2_j2u_max_ju_to_j2u(a, b, res)` implements + * `*res = *a > b ? *a : b` + * + * @param a One of the values + * @param b The other value + * @param res Output parameter for the maximum of `*a` and `b` + */ +inline void +libj2_j2u_max_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + if (!a->high && a->low < b) { + res->high = 0; + res->low = b; + } else { + *res = *a; + } +} + + +/** + * Get the minimum of two unsigned double-max + * precision integers + * + * `libj2_j2u_min_j2u_to_ju2(a, b, res)` implements + * `*res = *a < *b ? *a : *b` + * + * @param a One of the values + * @param b The other value + * @param res Output parameter for the minimum of `*a` and `*b` + */ +inline void +libj2_j2u_min_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res) +{ + *res = libj2_j2u_lt_j2u(a, b) ? *a : *b; +} + + +/** + * Get the minimum of two unsigned double-max + * precision integers + * + * `libj2_j2u_min_j2u(a, b)` implements + * `*a = *a < *b ? *a : *b` + * + * @param a One of the values, and output parameter + * for the minimum of `*a` and `*b` + * @param b The other value + */ +inline void +libj2_j2u_min_j2u(struct libj2_j2u *a, const struct libj2_j2u *b) +{ + if (libj2_j2u_lt_j2u(b, a)) + *a = *b; +} + + +/** + * Get the minimum of an unsigned double-max + * precision integer and an unsigned precision + * integer + * + * `libj2_j2u_min_ju(a, b)` implements + * `*a = *a < b ? *a : b` + * + * @param a One of the values, and output parameter + * for the minimum of `*a` and `b` + * @param b The other value + */ +inline void +libj2_j2u_min_ju(struct libj2_j2u *a, uintmax_t b) +{ + if (a->high || a->low > b) { + a->high = 0; + a->low = b; + } +} + + +/** + * Get the minimum of an unsigned double-max + * precision integer and an unsigned precision + * integer + * + * `libj2_j2u_min_ju_to_j2u(a, b, res)` implements + * `*res = *a < b ? *a : b` + * + * @param a One of the values + * @param b The other value + * @param res Output parameter for the minimum of `*a` and `b` + */ +inline void +libj2_j2u_min_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res) +{ + if (a->high || a->low > b) { + res->high = 0; + res->low = b; + } else { + *res = *a; + } +} + + +/** + * Get the maximum of a set of unsigned double-max + * precision integers + * + * @param a One of the values, and output parameter for + * the maximum of the values + * @param args `NULL` terminated list of additional values; each + * argument shall have the type `const struct libj2_j2u *` + */ +inline void +libj2_vmax_j2u(struct libj2_j2u *a, va_list args) +{ + const struct libj2_j2u *b; + while ((b = va_arg(args, const struct libj2_j2u *))) + libj2_j2u_max_j2u(a, b); +} + + +/** + * Get the maximum of a set of unsigned double-max + * precision integers + * + * @param a One of the values, and output parameter for + * the maximum of the values + * @param ... `NULL` terminated list of additional values; each + * argument shall have the type `const struct libj2_j2u *` + */ +inline void +libj2_max_j2u(struct libj2_j2u *a, ... /*, NULL */) +{ + va_list args; + va_start(args, a); + libj2_vmax_j2u(a, args); + va_end(args); +} + + +/** + * Get the maximum of a set of unsigned double-max + * precision integers + * + * @param a One of the values + * @param args `NULL` terminated list of additional values; each + * argument shall have the type `const struct libj2_j2u *` + * @return One of the `const struct libj2_j2u *` that as the + * maximum of the values of each argument + */ +inline const struct libj2_j2u * +libj2_vmax_j2u_return(const struct libj2_j2u *a, va_list args) +{ + const struct libj2_j2u *b; + while ((b = va_arg(args, const struct libj2_j2u *))) + if (libj2_j2u_gt_j2u(b, a)) + a = b; + return a; +} + + +/** + * Get the maximum of a set of unsigned double-max + * precision integers + * + * @param a One of the values + * @param ... `NULL` terminated list of additional values; each + * argument shall have the type `const struct libj2_j2u *` + * @return One of the `const struct libj2_j2u *` that as the + * maximum of the values of each argument + */ +inline const struct libj2_j2u * +libj2_max_j2u_return(const struct libj2_j2u *a, ... /*, NULL */) +{ + va_list args; + va_start(args, a); + return libj2_vmax_j2u_return(a, args); + va_end(args); +} + + +/** + * Get the maximum of a set of unsigned double-max + * precision integers + * + * @param a One of the values + * @param args `NULL` terminated list of additional values, each + * argument shall have the type `const struct libj2_j2u *`, + * followed by a `struct libj2_j2u *` is used as the + * output parameter for the maximum of the values + */ +inline void +libj2_vmax_j2u_to_j2u(const struct libj2_j2u *a, va_list args) +{ + struct libj2_j2u *res; + a = libj2_vmax_j2u_return(a, args); + res = va_arg(args, struct libj2_j2u *); + *res = *a; +} + + +/** + * Get the maximum of a set of unsigned double-max + * precision integers + * + * @param a One of the values + * @param ... `NULL` terminated list of additional values, each + * argument shall have the type `const struct libj2_j2u *`, + * followed by a `struct libj2_j2u *` is used as the + * output parameter for the maximum of the values + */ +inline void +libj2_max_j2u_to_j2u(const struct libj2_j2u *a, ... /*, NULL, struct libj2_j2u *res */) +{ + va_list args; + va_start(args, a); + libj2_vmax_j2u_to_j2u(a, args); + va_end(args); +} + + +/** + * Get the minimum of a set of unsigned double-max + * precision integers + * + * @param a One of the values, and output parameter for + * the minimum of the values + * @param args `NULL` terminated list of additional values; each + * argument shall have the type `const struct libj2_j2u *` + */ +inline void +libj2_vmin_j2u(struct libj2_j2u *a, va_list args) +{ + const struct libj2_j2u *b; + while ((b = va_arg(args, const struct libj2_j2u *))) + libj2_j2u_min_j2u(a, b); +} + + +/** + * Get the minimum of a set of unsigned double-max + * precision integers + * + * @param a One of the values, and output parameter for + * the minimum of the values + * @param ... `NULL` terminated list of additional values; each + * argument shall have the type `const struct libj2_j2u *` + */ +inline void +libj2_min_j2u(struct libj2_j2u *a, ... /*, NULL */) +{ + va_list args; + va_start(args, a); + libj2_vmin_j2u(a, args); + va_end(args); +} + + +/** + * Get the minimum of a set of unsigned double-max + * precision integers + * + * @param a One of the values + * @param args `NULL` terminated list of additional values; each + * argument shall have the type `const struct libj2_j2u *` + * @return One of the `const struct libj2_j2u *` that as the + * minimum of the values of each argument + */ +inline const struct libj2_j2u * +libj2_vmin_j2u_return(const struct libj2_j2u *a, va_list args) +{ + const struct libj2_j2u *b; + while ((b = va_arg(args, const struct libj2_j2u *))) + if (libj2_j2u_lt_j2u(b, a)) + a = b; + return a; +} + + +/** + * Get the minimum of a set of unsigned double-max + * precision integers + * + * @param a One of the values + * @param ... `NULL` terminated list of additional values; each + * argument shall have the type `const struct libj2_j2u *` + * @return One of the `const struct libj2_j2u *` that as the + * minimum of the values of each argument + */ +inline const struct libj2_j2u * +libj2_min_j2u_return(const struct libj2_j2u *a, ... /*, NULL */) +{ + va_list args; + va_start(args, a); + return libj2_vmin_j2u_return(a, args); + va_end(args); +} + + +/** + * Get the minimum of a set of unsigned double-max + * precision integers + * + * @param a One of the values + * @param args `NULL` terminated list of additional values, each + * argument shall have the type `const struct libj2_j2u *`, + * followed by a `struct libj2_j2u *` is used as the + * output parameter for the minimum of the values + */ +inline void +libj2_vmin_j2u_to_j2u(const struct libj2_j2u *a, va_list args) +{ + struct libj2_j2u *res; + a = libj2_vmin_j2u_return(a, args); + res = va_arg(args, struct libj2_j2u *); + *res = *a; +} + + +/** + * Get the minimum of a set of unsigned double-max + * precision integers + * + * @param a One of the values + * @param ... `NULL` terminated list of additional values, each + * argument shall have the type `const struct libj2_j2u *`, + * followed by a `struct libj2_j2u *` is used as the + * output parameter for the minimum of the values + */ +inline void +libj2_min_j2u_to_j2u(const struct libj2_j2u *a, ... /*, NULL, struct libj2_j2u *res */) +{ + va_list args; + va_start(args, a); + libj2_vmin_j2u_to_j2u(a, args); + va_end(args); +} diff --git a/libj2_j2u_add_j2u.c b/libj2_j2u_add_j2u.c new file mode 100644 index 0000000..bd783a0 --- /dev/null +++ b/libj2_j2u_add_j2u.c @@ -0,0 +1,201 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_add_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static uintmax_t +random_ju(void) +{ + size_t n = LIBJ2_JU_BIT; + uintmax_t r = 0; + while (n--) + if (rand() < rand()) + r |= (uintmax_t)1 << n; + return r; +} + + +static void +check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low, + uintmax_t r_high, uintmax_t r_low, int r_overflow) +{ + struct libj2_j2u a, b, r, a_saved, b_saved, expected; + + a_saved = (struct libj2_j2u){.high = a_high, .low = a_low}; + b_saved = (struct libj2_j2u){.high = b_high, .low = b_low}; + expected = (struct libj2_j2u){.high = r_high, .low = r_low}; + + a = a_saved; + b = b_saved; + libj2_j2u_add_j2u(&a, &b); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + b = b_saved; + libj2_j2u_add_j2u_to_j2u(&a, &b, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + a = a_saved; + b = b_saved; + libj2_j2u_add_j2u_to_j2u(&a, &b, &a); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + a = a_saved; + b = b_saved; + libj2_j2u_add_j2u_to_j2u(&a, &b, &b); + EXPECT(libj2_j2u_eq_j2u(&b, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + b = b_saved; + EXPECT(libj2_j2u_add_j2u_overflow(&a, &b) == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + b = b_saved; + EXPECT(libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, &r) == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + a = a_saved; + b = b_saved; + EXPECT(libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, &a) == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + a = a_saved; + b = b_saved; + EXPECT(libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, &b) == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&b, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); +} + + +static void +check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low) +{ + uintmax_t r_high = 0, r_low = 0, carry = 0; + int r_overflow; + unsigned i; + + for (i = 0; i < LIBJ2_JU_BIT; i++) { + carry += (a_low >> i) & 1U; + carry += (b_low >> i) & 1U; + r_low |= (carry & 1U) << i; + carry >>= 1; + } + + for (i = 0; i < LIBJ2_JU_BIT; i++) { + carry += (a_high >> i) & 1U; + carry += (b_high >> i) & 1U; + r_high |= (carry & 1U) << i; + carry >>= 1; + } + + r_overflow = (int)carry; + check_(a_high, a_low, b_high, b_low, r_high, r_low, r_overflow); +} + + +static void +check_manual(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low, + uintmax_t r_high, uintmax_t r_low, int r_overflow) +{ + check_(a_high, a_low, b_high, b_low, r_high, r_low, r_overflow); + check(a_high, a_low, b_high, b_low); +} + + +static void +check_double(uintmax_t high, uintmax_t low) +{ + struct libj2_j2u a, r, a_saved, expected, b; + uintmax_t expected_high = (high << 1 | low >> (LIBJ2_JU_BIT - 1U)); + uintmax_t expected_low = low << 1; + int expected_overflow = !!(high >> (LIBJ2_JU_BIT - 1U)); + + a_saved = (struct libj2_j2u){.high = high, .low = low}; + expected = (struct libj2_j2u){.high = expected_high, .low = expected_low}; + + a = a_saved; + b = a_saved; + libj2_j2u_add_j2u(&a, &b); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + + a = a_saved; + libj2_j2u_add_j2u(&a, &a); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + libj2_j2u_add_j2u_to_j2u(&a, &a, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + a = a_saved; + libj2_j2u_add_j2u_to_j2u(&a, &a, &a); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + EXPECT(libj2_j2u_add_j2u_overflow(&a, &a) == expected_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + EXPECT(libj2_j2u_add_j2u_to_j2u_overflow(&a, &a, &r) == expected_overflow); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + a = a_saved; + EXPECT(libj2_j2u_add_j2u_to_j2u_overflow(&a, &a, &a) == expected_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); +} + + +int +main(void) +{ + unsigned i; + + srand((unsigned)time(NULL)); + + check_manual(0, 0, 0, 0, 0, 0, 0); + check_manual(0, 1, 0, 1, 0, 2, 0); + check_manual(0, UINTMAX_MAX, 0, 1, 1, 0, 0); + check_manual(0, UINTMAX_MAX, 0, UINTMAX_MAX, 1, UINTMAX_MAX - 1U, 0); + check_manual(UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX - 1U, 1); + + for (i = 0; i < 256; i++) + check(random_ju(), random_ju(), random_ju(), random_ju()); + + check_double(0, 0); + check_double(0, UINTMAX_MAX); + check_double(UINTMAX_MAX, 0); + check_double(UINTMAX_MAX, UINTMAX_MAX); + for (i = 0; i < 256; i++) { + check_double(0, random_ju()); + check_double(random_ju(), 0); + check_double(random_ju(), UINTMAX_MAX); + check_double(random_ju(), random_ju()); + check_double(UINTMAX_MAX, random_ju()); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_add_j2u_overflow.c b/libj2_j2u_add_j2u_overflow.c new file mode 100644 index 0000000..cab3cf6 --- /dev/null +++ b/libj2_j2u_add_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_add_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_j2u.c */ + +#endif diff --git a/libj2_j2u_add_j2u_to_j2u.c b/libj2_j2u_add_j2u_to_j2u.c new file mode 100644 index 0000000..ebd96da --- /dev/null +++ b/libj2_j2u_add_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_add_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_j2u.c */ + +#endif diff --git a/libj2_j2u_add_j2u_to_j2u_overflow.c b/libj2_j2u_add_j2u_to_j2u_overflow.c new file mode 100644 index 0000000..8a152ff --- /dev/null +++ b/libj2_j2u_add_j2u_to_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_add_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_j2u.c */ + +#endif diff --git a/libj2_j2u_add_ju.c b/libj2_j2u_add_ju.c new file mode 100644 index 0000000..8592662 --- /dev/null +++ b/libj2_j2u_add_ju.c @@ -0,0 +1,301 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_add_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +static uintmax_t +random_ju(void) +{ + size_t n = LIBJ2_JU_BIT; + uintmax_t r = 0; + while (n--) + if (rand() < rand()) + r |= (uintmax_t)1 << n; + return r; +} + + +static void +check_zero_low(uintmax_t high, uintmax_t low) +{ + struct libj2_j2u a, r; + + a = (struct libj2_j2u){.high = high, .low = 0}; + libj2_j2u_add_ju(&a, low); + EXPECT(a.high == high); + EXPECT(a.low == low); + + a = (struct libj2_j2u){.high = high, .low = 0}; + EXPECT(libj2_j2u_add_ju_overflow(&a, low) == 0); + EXPECT(a.high == high); + EXPECT(a.low == low); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = high, .low = 0}; + libj2_j2u_add_ju_to_j2u(&a, low, &r); + EXPECT(a.high == high); + EXPECT(a.low == 0); + EXPECT(r.high == high); + EXPECT(r.low == low); + + a = (struct libj2_j2u){.high = high, .low = 0}; + libj2_j2u_add_ju_to_j2u(&a, low, &a); + EXPECT(a.high == high); + EXPECT(a.low == low); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = high, .low = 0}; + EXPECT(libj2_j2u_add_ju_to_j2u_overflow(&a, low, &r) == 0); + EXPECT(a.high == high); + EXPECT(a.low == 0); + EXPECT(r.high == high); + EXPECT(r.low == low); + + a = (struct libj2_j2u){.high = high, .low = 0}; + EXPECT(libj2_j2u_add_ju_to_j2u_overflow(&a, low, &a) == 0); + EXPECT(a.high == high); + EXPECT(a.low == low); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = high, .low = 0}; + libj2_ju_add_j2u_to_j2u(low, &a, &r); + EXPECT(a.high == high); + EXPECT(a.low == 0); + EXPECT(r.high == high); + EXPECT(r.low == low); + + a = (struct libj2_j2u){.high = high, .low = 0}; + libj2_ju_add_j2u_to_j2u(low, &a, &a); + EXPECT(a.high == high); + EXPECT(a.low == low); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = high, .low = 0}; + EXPECT(libj2_ju_add_j2u_to_j2u_overflow(low, &a, &r) == 0); + EXPECT(a.high == high); + EXPECT(a.low == 0); + EXPECT(r.high == high); + EXPECT(r.low == low); + + a = (struct libj2_j2u){.high = high, .low = 0}; + EXPECT(libj2_ju_add_j2u_to_j2u_overflow(low, &a, &a) == 0); + EXPECT(a.high == high); + EXPECT(a.low == low); +} + + +static void +check_max_low(uintmax_t high, uintmax_t low) +{ + struct libj2_j2u a, r; + uintmax_t expected_high = high + (uintmax_t)!!low; + uintmax_t expected_low = low - 1U; + int expected_overflow = high == UINTMAX_MAX && low; + + a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX}; + libj2_j2u_add_ju(&a, low); + EXPECT(a.high == expected_high); + EXPECT(a.low == expected_low); + + a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX}; + EXPECT(libj2_j2u_add_ju_overflow(&a, low) == expected_overflow); + EXPECT(a.high == expected_high); + EXPECT(a.low == expected_low); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX}; + libj2_j2u_add_ju_to_j2u(&a, low, &r); + EXPECT(a.high == high); + EXPECT(a.low == UINTMAX_MAX); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); + + a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX}; + libj2_j2u_add_ju_to_j2u(&a, low, &a); + EXPECT(a.high == expected_high); + EXPECT(a.low == expected_low); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX}; + EXPECT(libj2_j2u_add_ju_to_j2u_overflow(&a, low, &r) == expected_overflow); + EXPECT(a.high == high); + EXPECT(a.low == UINTMAX_MAX); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); + + a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX}; + EXPECT(libj2_j2u_add_ju_to_j2u_overflow(&a, low, &a) == expected_overflow); + EXPECT(a.high == expected_high); + EXPECT(a.low == expected_low); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX}; + libj2_ju_add_j2u_to_j2u(low, &a, &r); + EXPECT(a.high == high); + EXPECT(a.low == UINTMAX_MAX); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); + + a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX}; + libj2_ju_add_j2u_to_j2u(low, &a, &a); + EXPECT(a.high == expected_high); + EXPECT(a.low == expected_low); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX}; + EXPECT(libj2_ju_add_j2u_to_j2u_overflow(low, &a, &r) == expected_overflow); + EXPECT(a.high == high); + EXPECT(a.low == UINTMAX_MAX); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); + + a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX}; + EXPECT(libj2_ju_add_j2u_to_j2u_overflow(low, &a, &a) == expected_overflow); + EXPECT(a.high == expected_high); + EXPECT(a.low == expected_low); +} + + +static void +self_check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low, + uintmax_t r_high, uintmax_t r_low, int r_overflow) +{ + uintmax_t carry = 0; + unsigned i; + + for (i = 0; i < LIBJ2_JU_BIT; i++) { + carry += (a_low >> i) & 1U; + carry += (b_low >> i) & 1U; + EXPECT((carry & 1U) == ((r_low >> i) & 1U)); + carry >>= 1; + } + + for (i = 0; i < LIBJ2_JU_BIT; i++) { + carry += (a_high >> i) & 1U; + carry += (b_high >> i) & 1U; + EXPECT((carry & 1U) == ((r_high >> i) & 1U)); + carry >>= 1; + } + + EXPECT((uintmax_t)r_overflow == carry); +} + + +static void +check(uintmax_t a_high, uintmax_t a_low, uintmax_t b) +{ + struct libj2_j2u a, r; + uintmax_t expected_high = a_high + (uintmax_t)(a_low > UINTMAX_MAX - b); + uintmax_t expected_low = a_low + b; + int expected_overflow = a_high && !expected_high; + + self_check(a_high, a_low, 0, b, expected_high, expected_low, expected_overflow); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + libj2_j2u_add_ju(&a, b); + EXPECT(a.high == expected_high); + EXPECT(a.low == expected_low); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_j2u_add_ju_overflow(&a, b) == expected_overflow); + EXPECT(a.high == expected_high); + EXPECT(a.low == expected_low); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + libj2_j2u_add_ju_to_j2u(&a, b, &r); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + libj2_j2u_add_ju_to_j2u(&a, b, &a); + EXPECT(a.high == expected_high); + EXPECT(a.low == expected_low); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_j2u_add_ju_to_j2u_overflow(&a, b, &r) == expected_overflow); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_j2u_add_ju_to_j2u_overflow(&a, b, &a) == expected_overflow); + EXPECT(a.high == expected_high); + EXPECT(a.low == expected_low); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + libj2_ju_add_j2u_to_j2u(b, &a, &r); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + libj2_ju_add_j2u_to_j2u(b, &a, &a); + EXPECT(a.high == expected_high); + EXPECT(a.low == expected_low); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_ju_add_j2u_to_j2u_overflow(b, &a, &r) == expected_overflow); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_ju_add_j2u_to_j2u_overflow(b, &a, &a) == expected_overflow); + EXPECT(a.high == expected_high); + EXPECT(a.low == expected_low); +} + + +int +main(void) +{ + unsigned i; + + srand((unsigned)time(NULL)); + + check_zero_low(0, 0); + check_zero_low(0, UINTMAX_MAX); + check_zero_low(UINTMAX_MAX, 0); + check_zero_low(UINTMAX_MAX, UINTMAX_MAX); + for (i = 0; i < 256; i++) { + check_zero_low(0, random_ju()); + check_zero_low(random_ju(), 0); + check_zero_low(random_ju(), random_ju()); + check_zero_low(random_ju(), UINTMAX_MAX); + check_zero_low(UINTMAX_MAX, random_ju()); + } + + check_max_low(0, 0); + check_max_low(0, UINTMAX_MAX); + check_max_low(UINTMAX_MAX, 0); + check_max_low(UINTMAX_MAX, UINTMAX_MAX); + for (i = 0; i < 256; i++) { + check_max_low(0, random_ju()); + check_max_low(random_ju(), 0); + check_max_low(random_ju(), 1); + check_max_low(random_ju(), random_ju()); + check_max_low(random_ju(), UINTMAX_MAX); + check_max_low(UINTMAX_MAX, random_ju()); + } + + for (i = 0; i < 256; i++) + check(random_ju(), random_ju(), random_ju()); + + return 0; +} + +#endif diff --git a/libj2_j2u_add_ju_overflow.c b/libj2_j2u_add_ju_overflow.c new file mode 100644 index 0000000..9c01dd2 --- /dev/null +++ b/libj2_j2u_add_ju_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_add_ju_overflow(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_ju.c */ + +#endif diff --git a/libj2_j2u_add_ju_to_j2u.c b/libj2_j2u_add_ju_to_j2u.c new file mode 100644 index 0000000..348cc2c --- /dev/null +++ b/libj2_j2u_add_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_add_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_ju.c */ + +#endif diff --git a/libj2_j2u_add_ju_to_j2u_overflow.c b/libj2_j2u_add_ju_to_j2u_overflow.c new file mode 100644 index 0000000..d93e76d --- /dev/null +++ b/libj2_j2u_add_ju_to_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_add_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_ju.c */ + +#endif diff --git a/libj2_j2u_and_j2u.c b/libj2_j2u_and_j2u.c new file mode 100644 index 0000000..4ae1347 --- /dev/null +++ b/libj2_j2u_and_j2u.c @@ -0,0 +1,140 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_and_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static void +check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected) +{ + struct libj2_j2u a_saved = *a, b_saved = *b, r; + + r = *a; + libj2_j2u_and_j2u(&r, b); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_and_j2u(&r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &a_saved)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_and_j2u_to_j2u(a, b, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_and_j2u_to_j2u(&r, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_j2u_and_j2u_to_j2u(a, &r, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_and_j2u_to_j2u(a, a, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, &a_saved)); + + r = *a; + libj2_j2u_and_j2u_to_j2u(a, a, a); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + + if (a->high == 0U) { + r = (struct libj2_j2u){111, 222}; + libj2_ju_and_j2u_to_j2u(a->low, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_ju_and_j2u_to_j2u(a->low, &r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } + + if (b->high == 0U) { + r = *a; + libj2_j2u_and_ju(&r, b->low); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_and_ju_to_j2u(a, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_and_ju_to_j2u(&r, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } +} + +int +main(void) +{ + unsigned truthtable[] = {0, 0, 0, 1}; + unsigned i, j; + uintmax_t a_bit, b_bit, r_bit; + struct libj2_j2u a, b, r, a_saved; + + srand((unsigned)time(NULL)); + + for (j = 0; j < 128; j++) { + a.high = a.low = 0; + b.high = b.low = 0; + r.high = r.low = 0; + for (i = 0; i < LIBJ2_J2U_BIT; i++) { + a_bit = (uintmax_t)(rand() < rand()); + b_bit = (uintmax_t)(rand() < rand()); + r_bit = truthtable[a_bit * 2U + b_bit]; + if (i < LIBJ2_JU_BIT) { + a.low |= a_bit << i; + b.low |= b_bit << i; + r.low |= r_bit << i; + } else { + a.high |= a_bit << (i - LIBJ2_JU_BIT); + b.high |= b_bit << (i - LIBJ2_JU_BIT); + r.high |= r_bit << (i - LIBJ2_JU_BIT); + } + } + + check(&a, &b, &r); + + a_saved = a; + a.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[(b.high >> i) & 1U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + a = a_saved; + + b.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 2U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + + r.high = 0U; + r.low = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 3U]; + r.high |= r_bit << i; + r_bit = truthtable[((a.low >> i) & 1U) * 3U]; + r.low |= r_bit << i; + } + check(&a, &a, &r); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_and_j2u_to_j2u.c b/libj2_j2u_and_j2u_to_j2u.c new file mode 100644 index 0000000..80b33c5 --- /dev/null +++ b/libj2_j2u_and_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_and_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_and_j2u.c */ + +#endif diff --git a/libj2_j2u_and_ju.c b/libj2_j2u_and_ju.c new file mode 100644 index 0000000..9d947f5 --- /dev/null +++ b/libj2_j2u_and_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_and_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_and_j2u.c */ + +#endif diff --git a/libj2_j2u_and_ju_to_j2u.c b/libj2_j2u_and_ju_to_j2u.c new file mode 100644 index 0000000..862fbaa --- /dev/null +++ b/libj2_j2u_and_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_and_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_and_j2u.c */ + +#endif diff --git a/libj2_j2u_cmp_j2u.c b/libj2_j2u_cmp_j2u.c new file mode 100644 index 0000000..a5072d8 --- /dev/null +++ b/libj2_j2u_cmp_j2u.c @@ -0,0 +1,200 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_cmp_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static int +cmp(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low) +{ + struct libj2_j2u a, b, c; + int ret; + + a.high = a_high; + a.low = a_low; + b.high = b_high; + b.low = b_low; + + ret = libj2_j2u_cmp_j2u(&a, &b); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(b.high == b_high); + EXPECT(b.low == b_low); + + EXPECT(libj2_j2u_cmp_j2u(&b, &a) == (ret ? -ret : 0)); + + EXPECT(libj2_j2u_lt_j2u(&a, &b) == (ret < 0)); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(b.high == b_high); + EXPECT(b.low == b_low); + + EXPECT(libj2_j2u_le_j2u(&a, &b) == (ret <= 0)); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(b.high == b_high); + EXPECT(b.low == b_low); + + EXPECT(libj2_j2u_gt_j2u(&a, &b) == (ret > 0)); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(b.high == b_high); + EXPECT(b.low == b_low); + + EXPECT(libj2_j2u_ge_j2u(&a, &b) == (ret >= 0)); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(b.high == b_high); + EXPECT(b.low == b_low); + + EXPECT(libj2_j2u_eq_j2u(&a, &b) == (ret == 0)); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(b.high == b_high); + EXPECT(b.low == b_low); + + EXPECT(libj2_j2u_ne_j2u(&a, &b) == (ret != 0)); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(b.high == b_high); + EXPECT(b.low == b_low); + + EXPECT(libj2_j2u_lt_j2u(&b, &a) == (ret > 0)); + EXPECT(libj2_j2u_le_j2u(&b, &a) == (ret >= 0)); + EXPECT(libj2_j2u_gt_j2u(&b, &a) == (ret < 0)); + EXPECT(libj2_j2u_ge_j2u(&b, &a) == (ret <= 0)); + EXPECT(libj2_j2u_eq_j2u(&b, &a) == (ret == 0)); + EXPECT(libj2_j2u_ne_j2u(&b, &a) == (ret != 0)); + + c = (struct libj2_j2u){111, 222}; + libj2_j2u_max_j2u_to_j2u(&a, &b, &c); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(b.high == b_high); + EXPECT(b.low == b_low); + if (ret >= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1); + if (ret <= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1); + + c = (struct libj2_j2u){111, 222}; + libj2_j2u_max_j2u_to_j2u(&b, &a, &c); + if (ret >= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1); + if (ret <= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1); + + c = a; + libj2_j2u_max_j2u(&c, &b); + EXPECT(b.high == b_high); + EXPECT(b.low == b_low); + if (ret >= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1); + if (ret <= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1); + + c = b; + libj2_j2u_max_j2u(&c, &a); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + if (ret >= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1); + if (ret <= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1); + + c = (struct libj2_j2u){111, 222}; + libj2_j2u_min_j2u_to_j2u(&a, &b, &c); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(b.high == b_high); + EXPECT(b.low == b_low); + if (ret <= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1); + if (ret >= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1); + + c = (struct libj2_j2u){111, 222}; + libj2_j2u_min_j2u_to_j2u(&b, &a, &c); + if (ret <= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1); + if (ret >= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1); + + c = a; + libj2_j2u_min_j2u(&c, &b); + EXPECT(b.high == b_high); + EXPECT(b.low == b_low); + if (ret <= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1); + if (ret >= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1); + + c = b; + libj2_j2u_min_j2u(&c, &a); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + if (ret <= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1); + if (ret >= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &b) == 1); + + return ret; +} + +int +main(void) +{ + const uintmax_t max = UINTMAX_MAX; + + EXPECT(cmp(0, 0, 0, 0) == 0); + EXPECT(cmp(0, 0, 0, 1) == -1); + EXPECT(cmp(0, 0, 1, 0) == -1); + EXPECT(cmp(0, 0, 1, 1) == -1); + EXPECT(cmp(0, 0, 0, max) == -1); + EXPECT(cmp(0, 0, max, 0) == -1); + EXPECT(cmp(0, 0, max, max) == -1); + EXPECT(cmp(0, 0, max, max - 1) == -1); + + EXPECT(cmp(0, 1, 0, 1) == 0); + EXPECT(cmp(0, 1, 1, 0) == -1); + EXPECT(cmp(0, 1, 1, 1) == -1); + EXPECT(cmp(0, 1, 0, max) == -1); + EXPECT(cmp(0, 1, max, 0) == -1); + EXPECT(cmp(0, 1, max, max) == -1); + EXPECT(cmp(0, 1, max, max - 1) == -1); + + EXPECT(cmp(1, 0, 1, 0) == 0); + EXPECT(cmp(1, 0, 1, 1) == -1); + EXPECT(cmp(1, 0, 0, max) == +1); + EXPECT(cmp(1, 0, max, 0) == -1); + EXPECT(cmp(1, 0, max, max) == -1); + EXPECT(cmp(1, 0, max, max - 1) == -1); + + EXPECT(cmp(1, 1, 1, 1) == 0); + EXPECT(cmp(1, 1, 0, max) == +1); + EXPECT(cmp(1, 1, max, 0) == -1); + EXPECT(cmp(1, 1, max, max) == -1); + EXPECT(cmp(1, 1, max, max - 1) == -1); + + EXPECT(cmp(0, max, 0, max) == 0); + EXPECT(cmp(0, max, max, 0) == -1); + EXPECT(cmp(0, max, max, max) == -1); + EXPECT(cmp(0, max, max, max - 1) == -1); + + EXPECT(cmp(max, 0, max, 0) == 0); + EXPECT(cmp(max, 0, max, max) == -1); + EXPECT(cmp(max, 0, max, max - 1) == -1); + + EXPECT(cmp(max, max, max, max) == 0); + EXPECT(cmp(max, max, max, max - 1) == +1); + + EXPECT(cmp(max, max - 1, max, max - 1) == 0); + + return 0; +} + +#endif diff --git a/libj2_j2u_cmp_ju.c b/libj2_j2u_cmp_ju.c new file mode 100644 index 0000000..ba45409 --- /dev/null +++ b/libj2_j2u_cmp_ju.c @@ -0,0 +1,145 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_cmp_ju(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +static int +cmp(uintmax_t a_high, uintmax_t a_low, uintmax_t b) +{ + struct libj2_j2u a, c; + int ret; + + a.high = a_high; + a.low = a_low; + + ret = libj2_j2u_cmp_ju(&a, b); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + + EXPECT(libj2_ju_cmp_j2u(b, &a) == (ret ? -ret : 0)); + + EXPECT(libj2_j2u_lt_ju(&a, b) == (ret < 0)); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + + EXPECT(libj2_j2u_le_ju(&a, b) == (ret <= 0)); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + + EXPECT(libj2_j2u_gt_ju(&a, b) == (ret > 0)); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + + EXPECT(libj2_j2u_ge_ju(&a, b) == (ret >= 0)); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + + EXPECT(libj2_j2u_eq_ju(&a, b) == (ret == 0)); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + + EXPECT(libj2_j2u_ne_ju(&a, b) == (ret != 0)); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + + EXPECT(libj2_ju_lt_j2u(b, &a) == (ret > 0)); + EXPECT(libj2_ju_le_j2u(b, &a) == (ret >= 0)); + EXPECT(libj2_ju_gt_j2u(b, &a) == (ret < 0)); + EXPECT(libj2_ju_ge_j2u(b, &a) == (ret <= 0)); + EXPECT(libj2_ju_eq_j2u(b, &a) == (ret == 0)); + EXPECT(libj2_ju_ne_j2u(b, &a) == (ret != 0)); + + c = (struct libj2_j2u){111, 222}; + libj2_j2u_max_ju_to_j2u(&a, b, &c); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + if (ret >= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1); + if (ret <= 0) + EXPECT(libj2_j2u_eq_ju(&c, b) == 1); + + c = a; + libj2_j2u_max_ju(&c, b); + if (ret >= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1); + if (ret <= 0) + EXPECT(libj2_j2u_eq_ju(&c, b) == 1); + + c = (struct libj2_j2u){111, 222}; + libj2_j2u_min_ju_to_j2u(&a, b, &c); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + if (ret <= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1); + if (ret >= 0) + EXPECT(libj2_j2u_eq_ju(&c, b) == 1); + + c = a; + libj2_j2u_min_ju(&c, b); + if (ret <= 0) + EXPECT(libj2_j2u_eq_j2u(&c, &a) == 1); + if (ret >= 0) + EXPECT(libj2_j2u_eq_ju(&c, b) == 1); + + return ret; +} + +int +main(void) +{ + const uintmax_t max = UINTMAX_MAX; + + EXPECT(cmp(0, 0, 0) == 0); + EXPECT(cmp(0, 1, 0) == +1); + EXPECT(cmp(1, 0, 0) == +1); + EXPECT(cmp(1, 1, 0) == +1); + EXPECT(cmp(0, max, 0) == +1); + EXPECT(cmp(max, 0, 0) == +1); + EXPECT(cmp(max, max, 0) == +1); + EXPECT(cmp(max, max - 1, 0) == +1); + + EXPECT(cmp(0, 0, 1) == -1); + EXPECT(cmp(0, 1, 1) == 0); + EXPECT(cmp(1, 0, 1) == +1); + EXPECT(cmp(1, 1, 1) == +1); + EXPECT(cmp(0, max, 1) == +1); + EXPECT(cmp(max, 0, 1) == +1); + EXPECT(cmp(max, max, 1) == +1); + EXPECT(cmp(max, max - 1, 1) == +1); + + EXPECT(cmp(0, 0, 2) == -1); + EXPECT(cmp(0, 1, 2) == -1); + EXPECT(cmp(1, 0, 2) == +1); + EXPECT(cmp(1, 1, 2) == +1); + EXPECT(cmp(0, max, 2) == +1); + EXPECT(cmp(max, 0, 2) == +1); + EXPECT(cmp(max, max, 2) == +1); + EXPECT(cmp(max, max - 1, 2) == +1); + + EXPECT(cmp(0, 0, max) == -1); + EXPECT(cmp(0, 1, max) == -1); + EXPECT(cmp(1, 0, max) == +1); + EXPECT(cmp(1, 1, max) == +1); + EXPECT(cmp(0, max, max) == 0); + EXPECT(cmp(max, 0, max) == +1); + EXPECT(cmp(max, max, max) == +1); + EXPECT(cmp(max, max - 1, max) == +1); + + EXPECT(cmp(0, 0, max - 1) == -1); + EXPECT(cmp(0, 1, max - 1) == -1); + EXPECT(cmp(1, 0, max - 1) == +1); + EXPECT(cmp(1, 1, max - 1) == +1); + EXPECT(cmp(0, max, max - 1) == +1); + EXPECT(cmp(max, 0, max - 1) == +1); + EXPECT(cmp(max, max, max - 1) == +1); + EXPECT(cmp(max, max - 1, max - 1) == +1); + + return 0; +} + +#endif diff --git a/libj2_j2u_div_j2u.c b/libj2_j2u_div_j2u.c new file mode 100644 index 0000000..fdd84bd --- /dev/null +++ b/libj2_j2u_div_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_div_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_div_j2u_return.c b/libj2_j2u_div_j2u_return.c new file mode 100644 index 0000000..9519796 --- /dev/null +++ b/libj2_j2u_div_j2u_return.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline uintmax_t libj2_j2u_div_j2u_return(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_div_j2u_to_j2u.c b/libj2_j2u_div_j2u_to_j2u.c new file mode 100644 index 0000000..dee0640 --- /dev/null +++ b/libj2_j2u_div_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_div_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_div_ju.c b/libj2_j2u_div_ju.c new file mode 100644 index 0000000..732efad --- /dev/null +++ b/libj2_j2u_div_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_div_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_div_ju_return.c b/libj2_j2u_div_ju_return.c new file mode 100644 index 0000000..bcaac5c --- /dev/null +++ b/libj2_j2u_div_ju_return.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline uintmax_t libj2_j2u_div_ju_return(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_div_ju_to_j2u.c b/libj2_j2u_div_ju_to_j2u.c new file mode 100644 index 0000000..65dabfb --- /dev/null +++ b/libj2_j2u_div_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_div_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_divmod_j2u.c b/libj2_j2u_divmod_j2u.c new file mode 100644 index 0000000..70dbb2a --- /dev/null +++ b/libj2_j2u_divmod_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline uintmax_t libj2_j2u_divmod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_divmod_j2u_to_j2u.c b/libj2_j2u_divmod_j2u_to_j2u.c new file mode 100644 index 0000000..3c5e756 --- /dev/null +++ b/libj2_j2u_divmod_j2u_to_j2u.c @@ -0,0 +1,389 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_divmod_j2u_to_j2u(struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res_q); +/* TODO Add man page */ + + +#else + +static uintmax_t +random_ju(void) +{ + size_t n = LIBJ2_JU_BIT; + uintmax_t r = 0; + while (n--) + if (rand() < rand()) + r |= (uintmax_t)1 << n; + return r; +} + + +static void +validate_result(const struct libj2_j2u *a, const struct libj2_j2u *b, + const struct libj2_j2u *q, const struct libj2_j2u *r) +{ + struct libj2_j2u v; + libj2_j2u_mul_j2u_to_j2u(q, b, &v); + libj2_j2u_add_j2u(&v, r); + EXPECT(libj2_j2u_eq_j2u(&v, a)); + + if (!a->high && !b->high) { + EXPECT(!q->high); + EXPECT(!r->high); + EXPECT(q->low == a->low / b->low); + EXPECT(r->low == a->low % b->low); + } +} + + +static void +check_manual(const struct libj2_j2u *a, const struct libj2_j2u *b, + const struct libj2_j2u *expected_q, const struct libj2_j2u *expected_r) +{ + struct libj2_j2u a_saved = *a, b_saved = *b, q, r, eq, er; + + EXPECT(!libj2_j2u_is_zero(b)); + + r = (struct libj2_j2u){111, 222}; + q = (struct libj2_j2u){333, 444}; + libj2_j2u_divmod_j2u_to_j2u_j2u(a, b, &q, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + if (expected_q) { + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + } else { + eq = q; + expected_q = &eq; + } + if (expected_r) { + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + } else { + er = r; + expected_r = &er; + } + + validate_result(a, b, expected_q, expected_r); + + r = (struct libj2_j2u){111, 222}; + q = *a; + libj2_j2u_divmod_j2u_to_j2u_j2u(&q, b, &q, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + q = (struct libj2_j2u){333, 444}; + libj2_j2u_divmod_j2u_to_j2u_j2u(&r, b, &q, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = (struct libj2_j2u){111, 222}; + q = *b; + libj2_j2u_divmod_j2u_to_j2u_j2u(a, &q, &q, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *b; + q = (struct libj2_j2u){333, 444}; + libj2_j2u_divmod_j2u_to_j2u_j2u(a, &r, &q, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *b; + q = *a; + libj2_j2u_divmod_j2u_to_j2u_j2u(&q, &r, &q, &r); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + q = *b; + libj2_j2u_divmod_j2u_to_j2u_j2u(&r, &q, &q, &r); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + q = (struct libj2_j2u){333, 444}; + libj2_j2u_div_j2u_to_j2u(a, b, &q); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + + q = *a; + libj2_j2u_div_j2u_to_j2u(&q, b, &q); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + + q = *b; + libj2_j2u_div_j2u_to_j2u(a, &q, &q); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_mod_j2u_to_j2u(a, b, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + libj2_j2u_mod_j2u_to_j2u(&r, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *b; + libj2_j2u_mod_j2u_to_j2u(a, &r, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + q = (struct libj2_j2u){333, 444}; + libj2_j2u_divmod_j2u_to_j2u(&r, b, &q); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + q = *b; + libj2_j2u_divmod_j2u_to_j2u(&r, &q, &q); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + q = *a; + libj2_j2u_div_j2u(&q, b); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + + r = *a; + libj2_j2u_mod_j2u(&r, b); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *b; + q = (struct libj2_j2u){333, 444}; + libj2_j2u_rdivmod_j2u_to_j2u(&r, a, &q); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *b; + q = *a; + libj2_j2u_rdivmod_j2u_to_j2u(&r, &q, &q); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + q = *b; + libj2_j2u_rdiv_j2u(&q, a); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + + r = *b; + libj2_j2u_rmod_j2u(&r, a); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + EXPECT(libj2_j2u_divmod_j2u(&r, b) == expected_q->low); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + EXPECT(libj2_j2u_div_j2u_return(a, b) == expected_q->low); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + + if (!b->high) { + r = (struct libj2_j2u){111, 222}; + q = (struct libj2_j2u){333, 444}; + libj2_j2u_divmod_ju_to_j2u_j2u(a, b->low, &q, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = (struct libj2_j2u){111, 222}; + q = *a; + libj2_j2u_divmod_ju_to_j2u_j2u(&q, b->low, &q, &r); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + q = (struct libj2_j2u){333, 444}; + libj2_j2u_divmod_ju_to_j2u_j2u(&r, b->low, &q, &r); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + q = (struct libj2_j2u){333, 444}; + libj2_j2u_div_ju_to_j2u(a, b->low, &q); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + + q = *a; + libj2_j2u_div_ju_to_j2u(&q, b->low, &q); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_mod_ju_to_j2u(a, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + libj2_j2u_mod_ju_to_j2u(&r, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + q = (struct libj2_j2u){333, 444}; + libj2_j2u_divmod_ju_to_j2u(&r, b->low, &q); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + q = *a; + libj2_j2u_div_ju(&q, b->low); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + + r = *a; + libj2_j2u_mod_ju(&r, b->low); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *b; + EXPECT(libj2_j2u_rdivmod_j2u(&r, a) == expected_q->low); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + EXPECT(libj2_j2u_divmod_ju(&r, b->low) == expected_q->low); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + EXPECT(libj2_j2u_div_ju_return(a, b->low) == expected_q->low); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + } + + if (a == b) { + r = (struct libj2_j2u){111, 222}; + q = *a; + libj2_j2u_divmod_j2u_to_j2u_j2u(&q, &q, &q, &r); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + q = (struct libj2_j2u){333, 444}; + libj2_j2u_divmod_j2u_to_j2u_j2u(&r, &r, &q, &r); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + q = *a; + libj2_j2u_div_j2u_to_j2u(&q, &q, &q); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + + r = *a; + libj2_j2u_mod_j2u_to_j2u(&r, &r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + q = (struct libj2_j2u){333, 444}; + libj2_j2u_divmod_j2u_to_j2u(&r, &r, &q); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + q = *a; + libj2_j2u_div_j2u(&q, &q); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + + r = *a; + libj2_j2u_mod_j2u(&r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + q = (struct libj2_j2u){333, 444}; + libj2_j2u_rdivmod_j2u_to_j2u(&r, &r, &q); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + q = *a; + libj2_j2u_rdiv_j2u(&q, &q); + EXPECT(libj2_j2u_eq_j2u(&q, expected_q)); + + r = *a; + libj2_j2u_rmod_j2u(&r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + + r = *a; + EXPECT(libj2_j2u_divmod_j2u(&r, &r) == expected_q->low); + EXPECT(libj2_j2u_eq_j2u(&r, expected_r)); + } +} + + +static void +check(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + struct libj2_j2u u, v; + if (!a) { + u.high = random_ju(); + u.low = random_ju(); + a = &u; + } + if (!b) { + do { + v.high = random_ju(); + v.low = random_ju(); + } while (!v.high && !v.low); + b = &u; + } + check_manual(a, b, NULL, NULL); +} + + +int +main(void) +{ + struct libj2_j2u a = {0, 0}, b = {0, 0}, q = {0, 0}, r = {0, 0}; + struct libj2_j2u zero = {0, 0}, one = {0, 0}, two = {0, 0}; + unsigned i; + + srand((unsigned)time(NULL)); + + one.low = 1; + two.low = 2; + + check_manual(&one, &one, &one, &zero); + check_manual(&two, &one, &two, &zero); + check_manual(&one, &two, &zero, &one); + check_manual(&zero, &one, &zero, &zero); + + a.low = 35; + b.low = 4; + q.low = 8; + r.low = 3; + check_manual(&a, &b, &q, &r); + + a.low = UINTMAX_C(0x94385c048097d350); + b.low = UINTMAX_C(0x9212734e33d9df1e); + r.low = a.low % b.low; + check(&a, &b); + check_manual(&a, &b, &one, &r); + + for (i = 0; i < 2048; i++) { + a.high = b.high = 0; + a.low = random_ju(); + b.low = random_ju(); + check(NULL, NULL); + check(NULL, &a); + check(&a, NULL); + check(&a, &b); + a.high = b.low; + check(&a, &a); + if (!libj2_j2u_is_zero(&a)) + check_manual(&zero, &a, &zero, &zero); + check_manual(&a, &one, &a, &zero); + b.high = a.high >> 1; + b.low = a.low >> 1; + b.low |= (a.high & 1U) << (LIBJ2_JU_BIT - 1U); + check_manual(&a, &two, &b, (a.low & 1U) ? &one : &zero); + } + + return 0; +} + + +#endif diff --git a/libj2_j2u_divmod_j2u_to_j2u_j2u.c b/libj2_j2u_divmod_j2u_to_j2u_j2u.c new file mode 100644 index 0000000..3e9d0b0 --- /dev/null +++ b/libj2_j2u_divmod_j2u_to_j2u_j2u.c @@ -0,0 +1,14 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_divmod_j2u_to_j2u_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, + struct libj2_j2u *res_q, struct libj2_j2u *res_r); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_divmod_ju.c b/libj2_j2u_divmod_ju.c new file mode 100644 index 0000000..70a5d64 --- /dev/null +++ b/libj2_j2u_divmod_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline uintmax_t libj2_j2u_divmod_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_divmod_ju_to_j2u.c b/libj2_j2u_divmod_ju_to_j2u.c new file mode 100644 index 0000000..bfe0146 --- /dev/null +++ b/libj2_j2u_divmod_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_divmod_ju_to_j2u(struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res_q); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_divmod_ju_to_j2u_j2u.c b/libj2_j2u_divmod_ju_to_j2u_j2u.c new file mode 100644 index 0000000..9828d30 --- /dev/null +++ b/libj2_j2u_divmod_ju_to_j2u_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_divmod_ju_to_j2u_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res_q, struct libj2_j2u *res_r); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_eq_j2u.c b/libj2_j2u_eq_j2u.c new file mode 100644 index 0000000..847f942 --- /dev/null +++ b/libj2_j2u_eq_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_eq_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */ + +#endif diff --git a/libj2_j2u_eq_ju.c b/libj2_j2u_eq_ju.c new file mode 100644 index 0000000..9012baa --- /dev/null +++ b/libj2_j2u_eq_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_eq_ju(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_j2u_ge_j2u.c b/libj2_j2u_ge_j2u.c new file mode 100644 index 0000000..031b7dd --- /dev/null +++ b/libj2_j2u_ge_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_ge_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */ + +#endif diff --git a/libj2_j2u_ge_ju.c b/libj2_j2u_ge_ju.c new file mode 100644 index 0000000..a348fa6 --- /dev/null +++ b/libj2_j2u_ge_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_ge_ju(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_j2u_gt_j2u.c b/libj2_j2u_gt_j2u.c new file mode 100644 index 0000000..bd4da14 --- /dev/null +++ b/libj2_j2u_gt_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_gt_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */ + +#endif diff --git a/libj2_j2u_gt_ju.c b/libj2_j2u_gt_ju.c new file mode 100644 index 0000000..e7947d0 --- /dev/null +++ b/libj2_j2u_gt_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_gt_ju(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_j2u_if_j2u.c b/libj2_j2u_if_j2u.c new file mode 100644 index 0000000..c035683 --- /dev/null +++ b/libj2_j2u_if_j2u.c @@ -0,0 +1,140 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_if_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static void +check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected) +{ + struct libj2_j2u a_saved = *a, b_saved = *b, r; + + r = *a; + libj2_j2u_if_j2u(&r, b); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_if_j2u(&r, &r); + EXPECT(libj2_j2u_is_max(&r)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_if_j2u_to_j2u(a, b, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_if_j2u_to_j2u(&r, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_j2u_if_j2u_to_j2u(a, &r, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_if_j2u_to_j2u(a, a, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_is_max(&r)); + + r = *a; + libj2_j2u_if_j2u_to_j2u(&r, &r, &r); + EXPECT(libj2_j2u_is_max(&r)); + + if (a->high == 0U) { + r = (struct libj2_j2u){111, 222}; + libj2_ju_if_j2u_to_j2u(a->low, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_ju_if_j2u_to_j2u(a->low, &r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } + + if (b->high == 0U) { + r = *a; + libj2_j2u_if_ju(&r, b->low); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_if_ju_to_j2u(a, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_if_ju_to_j2u(&r, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } +} + +int +main(void) +{ + unsigned truthtable[] = {1, 0, 1, 1}; + unsigned i, j; + uintmax_t a_bit, b_bit, r_bit; + struct libj2_j2u a, b, r, a_saved; + + srand((unsigned)time(NULL)); + + for (j = 0; j < 128; j++) { + a.high = a.low = 0; + b.high = b.low = 0; + r.high = r.low = 0; + for (i = 0; i < LIBJ2_J2U_BIT; i++) { + a_bit = (uintmax_t)(rand() < rand()); + b_bit = (uintmax_t)(rand() < rand()); + r_bit = truthtable[a_bit * 2U + b_bit]; + if (i < LIBJ2_JU_BIT) { + a.low |= a_bit << i; + b.low |= b_bit << i; + r.low |= r_bit << i; + } else { + a.high |= a_bit << (i - LIBJ2_JU_BIT); + b.high |= b_bit << (i - LIBJ2_JU_BIT); + r.high |= r_bit << (i - LIBJ2_JU_BIT); + } + } + + check(&a, &b, &r); + + a_saved = a; + a.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[(b.high >> i) & 1U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + a = a_saved; + + b.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 2U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + + r.high = 0U; + r.low = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 3U]; + r.high |= r_bit << i; + r_bit = truthtable[((a.low >> i) & 1U) * 3U]; + r.low |= r_bit << i; + } + check(&a, &a, &r); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_if_j2u_to_j2u.c b/libj2_j2u_if_j2u_to_j2u.c new file mode 100644 index 0000000..d9cbe47 --- /dev/null +++ b/libj2_j2u_if_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_if_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_if_j2u.c */ + +#endif diff --git a/libj2_j2u_if_ju.c b/libj2_j2u_if_ju.c new file mode 100644 index 0000000..088c176 --- /dev/null +++ b/libj2_j2u_if_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_if_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_if_j2u.c */ + +#endif diff --git a/libj2_j2u_if_ju_to_j2u.c b/libj2_j2u_if_ju_to_j2u.c new file mode 100644 index 0000000..a74c441 --- /dev/null +++ b/libj2_j2u_if_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_if_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_if_j2u.c */ + +#endif diff --git a/libj2_j2u_imply_j2u.c b/libj2_j2u_imply_j2u.c new file mode 100644 index 0000000..83accf9 --- /dev/null +++ b/libj2_j2u_imply_j2u.c @@ -0,0 +1,140 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_imply_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static void +check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected) +{ + struct libj2_j2u a_saved = *a, b_saved = *b, r; + + r = *a; + libj2_j2u_imply_j2u(&r, b); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_imply_j2u(&r, &r); + EXPECT(libj2_j2u_is_max(&r)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_imply_j2u_to_j2u(a, b, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_imply_j2u_to_j2u(&r, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_j2u_imply_j2u_to_j2u(a, &r, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_imply_j2u_to_j2u(a, a, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_is_max(&r)); + + r = *a; + libj2_j2u_imply_j2u_to_j2u(&r, &r, &r); + EXPECT(libj2_j2u_is_max(&r)); + + if (a->high == 0U) { + r = (struct libj2_j2u){111, 222}; + libj2_ju_imply_j2u_to_j2u(a->low, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_ju_imply_j2u_to_j2u(a->low, &r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } + + if (b->high == 0U) { + r = *a; + libj2_j2u_imply_ju(&r, b->low); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_imply_ju_to_j2u(a, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_imply_ju_to_j2u(&r, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } +} + +int +main(void) +{ + unsigned truthtable[] = {1, 1, 0, 1}; + unsigned i, j; + uintmax_t a_bit, b_bit, r_bit; + struct libj2_j2u a, b, r, a_saved; + + srand((unsigned)time(NULL)); + + for (j = 0; j < 128; j++) { + a.high = a.low = 0; + b.high = b.low = 0; + r.high = r.low = 0; + for (i = 0; i < LIBJ2_J2U_BIT; i++) { + a_bit = (uintmax_t)(rand() < rand()); + b_bit = (uintmax_t)(rand() < rand()); + r_bit = truthtable[a_bit * 2U + b_bit]; + if (i < LIBJ2_JU_BIT) { + a.low |= a_bit << i; + b.low |= b_bit << i; + r.low |= r_bit << i; + } else { + a.high |= a_bit << (i - LIBJ2_JU_BIT); + b.high |= b_bit << (i - LIBJ2_JU_BIT); + r.high |= r_bit << (i - LIBJ2_JU_BIT); + } + } + + check(&a, &b, &r); + + a_saved = a; + a.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[(b.high >> i) & 1U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + a = a_saved; + + b.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 2U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + + r.high = 0U; + r.low = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 3U]; + r.high |= r_bit << i; + r_bit = truthtable[((a.low >> i) & 1U) * 3U]; + r.low |= r_bit << i; + } + check(&a, &a, &r); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_imply_j2u_to_j2u.c b/libj2_j2u_imply_j2u_to_j2u.c new file mode 100644 index 0000000..4ff3041 --- /dev/null +++ b/libj2_j2u_imply_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_imply_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_imply_j2u.c */ + +#endif diff --git a/libj2_j2u_imply_ju.c b/libj2_j2u_imply_ju.c new file mode 100644 index 0000000..735c31a --- /dev/null +++ b/libj2_j2u_imply_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_imply_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_imply_j2u.c */ + +#endif diff --git a/libj2_j2u_imply_ju_to_j2u.c b/libj2_j2u_imply_ju_to_j2u.c new file mode 100644 index 0000000..cbb6309 --- /dev/null +++ b/libj2_j2u_imply_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_imply_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_imply_j2u.c */ + +#endif diff --git a/libj2_j2u_is_max.c b/libj2_j2u_is_max.c new file mode 100644 index 0000000..45df414 --- /dev/null +++ b/libj2_j2u_is_max.c @@ -0,0 +1,197 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_is_max(const struct libj2_j2u *a); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u value; + uintmax_t a, b; + int i, j; + + for (i = 0; i < CHAR_BIT * (int)sizeof(uintmax_t); i++) { + for (j = 0; j < CHAR_BIT * (int)sizeof(uintmax_t); j++) { + value.high = a = (uintmax_t)(i + 1); + value.low = b = (uintmax_t)(j + 1); + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)1 << i; + value.low = b = (uintmax_t)(j + 1); + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)(i + 1); + value.low = b = (uintmax_t)1 << j; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)1 << i; + value.low = b = (uintmax_t)1 << j; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b = ~((uintmax_t)(j + 1)); + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b = ~((uintmax_t)(j + 1)); + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b = ~((uintmax_t)1 << j); + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b = ~((uintmax_t)1 << j); + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + } + + value.high = 0; + value.low = a = (uintmax_t)(i + 1); + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)(i + 1); + value.low = 0; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = (uintmax_t)1 << i; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)1 << i; + value.low = 0; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = ~((uintmax_t)(i + 1)); + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = 0; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = ~((uintmax_t)1 << i); + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)1 << i); + value.low = 0; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + b = ~(uintmax_t)0; + + value.high = b; + value.low = a = (uintmax_t)(i + 1); + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)(i + 1); + value.low = b; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = (uintmax_t)1 << i; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)1 << i; + value.low = b; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = ~((uintmax_t)(i + 1)); + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = ~((uintmax_t)1 << i); + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + } + + value.high = 0; + value.low = 0; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == 0); + + a = ~(uintmax_t)0; + + value.high = 0; + value.low = a; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a; + value.low = 0; + EXPECT(!libj2_j2u_is_max(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = a; + value.low = a; + EXPECT(libj2_j2u_is_max(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == a); + + return 0; +} + +#endif diff --git a/libj2_j2u_is_min.c b/libj2_j2u_is_min.c new file mode 100644 index 0000000..a2a7565 --- /dev/null +++ b/libj2_j2u_is_min.c @@ -0,0 +1,197 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_is_min(const struct libj2_j2u *a); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u value; + uintmax_t a, b; + int i, j; + + for (i = 0; i < CHAR_BIT * (int)sizeof(uintmax_t); i++) { + for (j = 0; j < CHAR_BIT * (int)sizeof(uintmax_t); j++) { + value.high = a = (uintmax_t)(i + 1); + value.low = b = (uintmax_t)(j + 1); + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)1 << i; + value.low = b = (uintmax_t)(j + 1); + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)(i + 1); + value.low = b = (uintmax_t)1 << j; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)1 << i; + value.low = b = (uintmax_t)1 << j; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b = ~((uintmax_t)(j + 1)); + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b = ~((uintmax_t)(j + 1)); + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b = ~((uintmax_t)1 << j); + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b = ~((uintmax_t)1 << j); + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + } + + value.high = 0; + value.low = a = (uintmax_t)(i + 1); + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)(i + 1); + value.low = 0; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = (uintmax_t)1 << i; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)1 << i; + value.low = 0; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = ~((uintmax_t)(i + 1)); + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = 0; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = ~((uintmax_t)1 << i); + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)1 << i); + value.low = 0; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + b = ~(uintmax_t)0; + + value.high = b; + value.low = a = (uintmax_t)(i + 1); + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)(i + 1); + value.low = b; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = (uintmax_t)1 << i; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)1 << i; + value.low = b; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = ~((uintmax_t)(i + 1)); + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = ~((uintmax_t)1 << i); + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + } + + value.high = 0; + value.low = 0; + EXPECT(libj2_j2u_is_min(&value) == 1); + EXPECT(value.high == 0); + EXPECT(value.low == 0); + + a = ~(uintmax_t)0; + + value.high = 0; + value.low = a; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a; + value.low = 0; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = a; + value.low = a; + EXPECT(!libj2_j2u_is_min(&value)); + EXPECT(value.high == a); + EXPECT(value.low == a); + + return 0; +} + +#endif diff --git a/libj2_j2u_is_positive.c b/libj2_j2u_is_positive.c new file mode 100644 index 0000000..21a9dd7 --- /dev/null +++ b/libj2_j2u_is_positive.c @@ -0,0 +1,197 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_is_positive(const struct libj2_j2u *a); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u value; + uintmax_t a, b; + int i, j; + + for (i = 0; i < CHAR_BIT * (int)sizeof(uintmax_t); i++) { + for (j = 0; j < CHAR_BIT * (int)sizeof(uintmax_t); j++) { + value.high = a = (uintmax_t)(i + 1); + value.low = b = (uintmax_t)(j + 1); + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)1 << i; + value.low = b = (uintmax_t)(j + 1); + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)(i + 1); + value.low = b = (uintmax_t)1 << j; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)1 << i; + value.low = b = (uintmax_t)1 << j; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b = ~((uintmax_t)(j + 1)); + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b = ~((uintmax_t)(j + 1)); + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b = ~((uintmax_t)1 << j); + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b = ~((uintmax_t)1 << j); + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == b); + } + + value.high = 0; + value.low = a = (uintmax_t)(i + 1); + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)(i + 1); + value.low = 0; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = (uintmax_t)1 << i; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)1 << i; + value.low = 0; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = ~((uintmax_t)(i + 1)); + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = 0; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = ~((uintmax_t)1 << i); + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)1 << i); + value.low = 0; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + b = ~(uintmax_t)0; + + value.high = b; + value.low = a = (uintmax_t)(i + 1); + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)(i + 1); + value.low = b; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = (uintmax_t)1 << i; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)1 << i; + value.low = b; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = ~((uintmax_t)(i + 1)); + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = ~((uintmax_t)1 << i); + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == b); + } + + value.high = 0; + value.low = 0; + EXPECT(!libj2_j2u_is_positive(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == 0); + + a = ~(uintmax_t)0; + + value.high = 0; + value.low = a; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a; + value.low = 0; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = a; + value.low = a; + EXPECT(libj2_j2u_is_positive(&value) == 1); + EXPECT(value.high == a); + EXPECT(value.low == a); + + return 0; +} + +#endif diff --git a/libj2_j2u_is_zero.c b/libj2_j2u_is_zero.c new file mode 100644 index 0000000..7058bbe --- /dev/null +++ b/libj2_j2u_is_zero.c @@ -0,0 +1,197 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_is_zero(const struct libj2_j2u *a); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u value; + uintmax_t a, b; + int i, j; + + for (i = 0; i < CHAR_BIT * (int)sizeof(uintmax_t); i++) { + for (j = 0; j < CHAR_BIT * (int)sizeof(uintmax_t); j++) { + value.high = a = (uintmax_t)(i + 1); + value.low = b = (uintmax_t)(j + 1); + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)1 << i; + value.low = b = (uintmax_t)(j + 1); + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)(i + 1); + value.low = b = (uintmax_t)1 << j; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)1 << i; + value.low = b = (uintmax_t)1 << j; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b = ~((uintmax_t)(j + 1)); + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b = ~((uintmax_t)(j + 1)); + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b = ~((uintmax_t)1 << j); + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b = ~((uintmax_t)1 << j); + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + } + + value.high = 0; + value.low = a = (uintmax_t)(i + 1); + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)(i + 1); + value.low = 0; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = (uintmax_t)1 << i; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)1 << i; + value.low = 0; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = ~((uintmax_t)(i + 1)); + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = 0; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = ~((uintmax_t)1 << i); + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)1 << i); + value.low = 0; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + b = ~(uintmax_t)0; + + value.high = b; + value.low = a = (uintmax_t)(i + 1); + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)(i + 1); + value.low = b; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = (uintmax_t)1 << i; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)1 << i; + value.low = b; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = ~((uintmax_t)(i + 1)); + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = ~((uintmax_t)1 << i); + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == b); + } + + value.high = 0; + value.low = 0; + EXPECT(libj2_j2u_is_zero(&value) == 1); + EXPECT(value.high == 0); + EXPECT(value.low == 0); + + a = ~(uintmax_t)0; + + value.high = 0; + value.low = a; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a; + value.low = 0; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = a; + value.low = a; + EXPECT(!libj2_j2u_is_zero(&value)); + EXPECT(value.high == a); + EXPECT(value.low == a); + + return 0; +} + +#endif diff --git a/libj2_j2u_le_j2u.c b/libj2_j2u_le_j2u.c new file mode 100644 index 0000000..9403271 --- /dev/null +++ b/libj2_j2u_le_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_le_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */ + +#endif diff --git a/libj2_j2u_le_ju.c b/libj2_j2u_le_ju.c new file mode 100644 index 0000000..a55bfff --- /dev/null +++ b/libj2_j2u_le_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_le_ju(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_j2u_lrot.c b/libj2_j2u_lrot.c new file mode 100644 index 0000000..0ad033b --- /dev/null +++ b/libj2_j2u_lrot.c @@ -0,0 +1,81 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_lrot(struct libj2_j2u *a, unsigned b); +/* TODO Add man page */ + + +#else + +static void +set(struct libj2_j2u *a, const char *pattern, unsigned shift) +{ + unsigned i, j = (LIBJ2_J2U_BIT - (shift % LIBJ2_J2U_BIT)) % LIBJ2_J2U_BIT; + + a->high = 0; + a->low = 0; + + for (i = 0; i < LIBJ2_JU_BIT; i++, j++) + if (pattern[j % LIBJ2_J2U_BIT] == '1') + a->low |= (uintmax_t)1 << i; + + for (i = 0; i < LIBJ2_JU_BIT; i++, j++) + if (pattern[j % LIBJ2_J2U_BIT] == '1') + a->high |= (uintmax_t)1 << i; + +} + + +int +main(void) +{ + struct libj2_j2u a, r, a_saved, expected; + char pattern[LIBJ2_J2U_BIT + 1U]; + unsigned i, j, k; + + srand((unsigned)time(NULL)); + + for (i = 0; i < 128U; i++) { + for (j = 0; j < LIBJ2_J2U_BIT; j++) + pattern[j] = '0' + (rand() < rand()); + pattern[LIBJ2_J2U_BIT] = '\0'; + set(&a, pattern, 0); + a_saved = a; + for (j = 0; j <= 2U * LIBJ2_J2U_BIT; j++) { + set(&expected, pattern, j); + + r = a; + libj2_j2u_lrot(&r, j); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_lrot_to_j2u(&a, j, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + r = a; + libj2_j2u_lrot_to_j2u(&r, j, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + k = 2U * LIBJ2_J2U_BIT - j; + + r = a; + libj2_j2u_rrot(&r, k); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_rrot_to_j2u(&a, k, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + r = a; + libj2_j2u_rrot_to_j2u(&r, k, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + } + } + + return 0; +} + +#endif diff --git a/libj2_j2u_lrot_to_j2u.c b/libj2_j2u_lrot_to_j2u.c new file mode 100644 index 0000000..66f7a1d --- /dev/null +++ b/libj2_j2u_lrot_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_lrot_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_lrot.c */ + +#endif diff --git a/libj2_j2u_lsh.c b/libj2_j2u_lsh.c new file mode 100644 index 0000000..85ca72b --- /dev/null +++ b/libj2_j2u_lsh.c @@ -0,0 +1,172 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_lsh(struct libj2_j2u *a, unsigned b); +/* TODO Add man page */ + + +#else + +static const char *patterns[] = { + "0", + "1111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111", + "1010101010101001010100100010101010101011000101101011101001000110", + "1110100100100010000010111111011101101001000010001000011110101010", + "11111111111100001001011", + "0010011011001", + "110010001011110100101001010011010111101", + NULL +}; + + +PURE static size_t +count_ones(const char *bits) +{ + size_t n = strlen(bits); + if (n > LIBJ2_J2U_BIT) + bits = &bits[n - LIBJ2_J2U_BIT]; + n = 0; + while (*bits) + if (*bits++ == '1') + n += 1U; + return n; +} + + +static int +set(struct libj2_j2u *a, const char *bits, size_t trailing_zeroes) +{ + size_t i, n; + char *all_bits, *p; + + n = LIBJ2_J2U_BIT + strlen(bits) + trailing_zeroes; + EXPECT((all_bits = malloc(n + 1U))); + memset(all_bits, '0', LIBJ2_J2U_BIT); + p = stpcpy(&all_bits[LIBJ2_J2U_BIT], bits); + memset(p, '0', trailing_zeroes); + p = &p[trailing_zeroes]; + + n = 0; + + a->low = 0; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + if (*--p == '1') { + a->low |= (uintmax_t)1 << i; + n += 1U; + } + } + + a->high = 0; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + if (*--p == '1') { + a->high |= (uintmax_t)1 << i; + n += 1U; + } + } + + free(all_bits); + return n < count_ones(bits); +} + + +static void +self_check(void) +{ + struct libj2_j2u a = {111, 222}; + EXPECT(set(&a, "11", 8) == 0); + EXPECT(a.high == 0); + EXPECT(a.low == (3U << 8)); + EXPECT(set(&a, "1101", LIBJ2_JU_BIT) == 0); + EXPECT(a.high == 13U); + EXPECT(a.low == 0); + EXPECT(set(&a, "1", LIBJ2_JU_BIT - 1) == 0); + EXPECT(a.high == 0); + EXPECT(a.low == (UINTMAX_MAX ^ (UINTMAX_MAX >> 1))); + EXPECT(set(&a, "111", LIBJ2_JU_BIT - 2) == 0); + EXPECT(a.high == 1); + EXPECT(a.low == (UINTMAX_MAX ^ (UINTMAX_MAX >> 2))); + EXPECT(set(&a, "1", LIBJ2_J2U_BIT) == 1); + EXPECT(a.high == 0); + EXPECT(a.low == 0); +} + + +static void +check(const char *pattern) +{ + struct libj2_j2u a, a_saved, r, expected; + unsigned i; + int overflows; + + set(&a, pattern, 0); + a_saved = a; + for (i = 0; i < LIBJ2_J2U_BIT + 8U; i++) { + overflows = set(&expected, pattern, i); + + r = a; + libj2_j2u_lsh(&r, i); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = a; + EXPECT(libj2_j2u_lsh_overflow(&r, i) == overflows); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_lsh_to_j2u(&a, i, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + r = (struct libj2_j2u){111, 222}; + EXPECT(libj2_j2u_lsh_to_j2u_overflow(&a, i, &r) == overflows); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + r = a; + libj2_j2u_lsh_to_j2u(&r, i, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = a; + EXPECT(libj2_j2u_lsh_to_j2u_overflow(&r, i, &r) == overflows); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + } +} + + +int +main(void) +{ + size_t i, j; + char pattern[LIBJ2_J2U_BIT + 1U]; + + self_check(); + srand((unsigned)time(NULL)); + + for (i = 0; patterns[i]; i++) + check(patterns[i]); + + for (i = 0; i < 64; i++) { + for (j = 0; j < LIBJ2_J2U_BIT; j++) + pattern[j] = '0' + (rand() < rand()); + pattern[LIBJ2_J2U_BIT] = '\0'; + check(pattern); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_lsh_overflow.c b/libj2_j2u_lsh_overflow.c new file mode 100644 index 0000000..aee6155 --- /dev/null +++ b/libj2_j2u_lsh_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_lsh_overflow(struct libj2_j2u *a, unsigned b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_lsh.c */ + +#endif diff --git a/libj2_j2u_lsh_to_j2u.c b/libj2_j2u_lsh_to_j2u.c new file mode 100644 index 0000000..31b32c7 --- /dev/null +++ b/libj2_j2u_lsh_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_lsh_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_lsh.c */ + +#endif diff --git a/libj2_j2u_lsh_to_j2u_overflow.c b/libj2_j2u_lsh_to_j2u_overflow.c new file mode 100644 index 0000000..63aaa3f --- /dev/null +++ b/libj2_j2u_lsh_to_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_lsh_to_j2u_overflow(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_lsh.c */ + +#endif diff --git a/libj2_j2u_lt_j2u.c b/libj2_j2u_lt_j2u.c new file mode 100644 index 0000000..3dddb5e --- /dev/null +++ b/libj2_j2u_lt_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_lt_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */ + +#endif diff --git a/libj2_j2u_lt_ju.c b/libj2_j2u_lt_ju.c new file mode 100644 index 0000000..e467f58 --- /dev/null +++ b/libj2_j2u_lt_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_lt_ju(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_j2u_max.c b/libj2_j2u_max.c new file mode 100644 index 0000000..a6b7317 --- /dev/null +++ b/libj2_j2u_max.c @@ -0,0 +1,27 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_max(struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u value = {1, 2}; + + libj2_j2u_max(&value); + EXPECT(~value.high == 0); + EXPECT(~value.low == 0); + + libj2_j2u_max(&value); + EXPECT(~value.high == 0); + EXPECT(~value.low == 0); + + return 0; +} + +#endif diff --git a/libj2_j2u_max_j2u.c b/libj2_j2u_max_j2u.c new file mode 100644 index 0000000..3120428 --- /dev/null +++ b/libj2_j2u_max_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_max_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */ + +#endif diff --git a/libj2_j2u_max_j2u_to_j2u.c b/libj2_j2u_max_j2u_to_j2u.c new file mode 100644 index 0000000..ab780fa --- /dev/null +++ b/libj2_j2u_max_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_max_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */ + +#endif diff --git a/libj2_j2u_max_ju.c b/libj2_j2u_max_ju.c new file mode 100644 index 0000000..dfb10b8 --- /dev/null +++ b/libj2_j2u_max_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_max_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_j2u_max_ju_to_j2u.c b/libj2_j2u_max_ju_to_j2u.c new file mode 100644 index 0000000..4739cf3 --- /dev/null +++ b/libj2_j2u_max_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_max_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_j2u_min.c b/libj2_j2u_min.c new file mode 100644 index 0000000..4ede699 --- /dev/null +++ b/libj2_j2u_min.c @@ -0,0 +1,27 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_min(struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u value = {1, 2}; + + libj2_j2u_min(&value); + EXPECT(value.high == 0); + EXPECT(value.low == 0); + + libj2_j2u_min(&value); + EXPECT(value.high == 0); + EXPECT(value.low == 0); + + return 0; +} + +#endif diff --git a/libj2_j2u_min_j2u.c b/libj2_j2u_min_j2u.c new file mode 100644 index 0000000..1aa9f98 --- /dev/null +++ b/libj2_j2u_min_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_min_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */ + +#endif diff --git a/libj2_j2u_min_j2u_to_j2u.c b/libj2_j2u_min_j2u_to_j2u.c new file mode 100644 index 0000000..a47b80f --- /dev/null +++ b/libj2_j2u_min_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_min_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */ + +#endif diff --git a/libj2_j2u_min_ju.c b/libj2_j2u_min_ju.c new file mode 100644 index 0000000..a3dfcdf --- /dev/null +++ b/libj2_j2u_min_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_min_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_j2u_min_ju_to_j2u.c b/libj2_j2u_min_ju_to_j2u.c new file mode 100644 index 0000000..8fe83c5 --- /dev/null +++ b/libj2_j2u_min_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_min_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_j2u_mod_j2u.c b/libj2_j2u_mod_j2u.c new file mode 100644 index 0000000..511b026 --- /dev/null +++ b/libj2_j2u_mod_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_mod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_mod_j2u_to_j2u.c b/libj2_j2u_mod_j2u_to_j2u.c new file mode 100644 index 0000000..cf28e65 --- /dev/null +++ b/libj2_j2u_mod_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_mod_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_mod_ju.c b/libj2_j2u_mod_ju.c new file mode 100644 index 0000000..ec8016b --- /dev/null +++ b/libj2_j2u_mod_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_mod_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_mod_ju_to_j2u.c b/libj2_j2u_mod_ju_to_j2u.c new file mode 100644 index 0000000..284ef6a --- /dev/null +++ b/libj2_j2u_mod_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_mod_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_mul_j2u.c b/libj2_j2u_mul_j2u.c new file mode 100644 index 0000000..aa1f178 --- /dev/null +++ b/libj2_j2u_mul_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_mul_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_j2u_destructive.c */ + +#endif diff --git a/libj2_j2u_mul_j2u_destructive.c b/libj2_j2u_mul_j2u_destructive.c new file mode 100644 index 0000000..cfa36a2 --- /dev/null +++ b/libj2_j2u_mul_j2u_destructive.c @@ -0,0 +1,267 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_mul_j2u_destructive(struct libj2_j2u *restrict a /*result */, struct libj2_j2u *restrict b /*destructed */); +/* TODO Add man page */ + + +#else + +static uintmax_t +random_small_ju(size_t bits) +{ + uintmax_t r = 0; + while (bits--) + if (rand() < rand()) + r |= (uintmax_t)1 << bits; + return r; +} + +static uintmax_t +random_hju(void) +{ + return random_small_ju(LIBJ2_JU_BIT / 2U); +} + +static uintmax_t +random_ju(void) +{ + return random_small_ju(LIBJ2_JU_BIT); +} + +static void +random_j2u(struct libj2_j2u *a) +{ + a->high = random_ju(); + a->low = random_ju(); +} + + +static int +refmul(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *expected) +{ + struct libj2_j2u c; + unsigned i; + int overflow = 0; + + libj2_j2u_zero(expected); + for (i = 0; i < LIBJ2_J2U_BIT; i++) { + if (libj2_j2u_test_bit(b, i)) { + overflow |= libj2_j2u_lsh_to_j2u_overflow(a, i, &c); + libj2_j2u_add_j2u(expected, &c); + } + } + + return overflow; +} + + +static void +mul_(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *expected, int expect_overflow) +{ + struct libj2_j2u t, x, a_saved = *a, b_saved = *b; + + *expected = *a; + libj2_j2u_mul_j2u(expected, b); + + t = (struct libj2_j2u){111, 222}; + libj2_j2u_mul_j2u_to_j2u(a, b, &t); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + + t = *a; + EXPECT(libj2_j2u_mul_j2u_overflow(&t, b) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + + t = (struct libj2_j2u){111, 222}; + EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow(a, b, &t) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + + t = *a; + x = *b; + libj2_j2u_mul_j2u_destructive(&t, &x); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + + t = *a; + x = *b; + EXPECT(libj2_j2u_mul_j2u_overflow_destructive(&t, &x) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + + if (a == b) { + t = *a; + libj2_j2u_mul_j2u(&t, &t); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + + t = *a; + libj2_j2u_mul_j2u_to_j2u(&t, &t, &t); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + + t = *a; + EXPECT(libj2_j2u_mul_j2u_overflow(&t, &t) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + + t = *a; + EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow(&t, &t, &t) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + }} + + +static void +mul(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *expected, int expect_overflow) +{ + struct libj2_j2u t; + + if (a == b) { + t = *a; + mul_(a, &t, expected, expect_overflow); + mul_(a, a, expected, expect_overflow); + } else { + mul_(a, b, expected, expect_overflow); + mul_(b, a, expected, expect_overflow); + } +} + + +int +main(void) +{ + const struct libj2_j2u zero = {0, 0}; + const struct libj2_j2u one = {.high = 0, .low = 1}; + const struct libj2_j2u four = {.high = 0, .low = 4}; + const struct libj2_j2u ju_max = {.high = 0, .low = UINTMAX_MAX}; + const struct libj2_j2u j2u_max = {.high = UINTMAX_MAX, .low = UINTMAX_MAX}; + struct libj2_j2u a, b, r, expected; + uintmax_t u, v; + unsigned i; + int expect_overflow; + + srand((unsigned)time(NULL)); + + r = (struct libj2_j2u){111, 222}; + mul(&zero, &zero, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + mul(&zero, &one, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + mul(&zero, &ju_max, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + mul(&one, &zero, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + mul(&ju_max, &zero, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + + for (i = 0; i < 32; i++) { + r = (struct libj2_j2u){111, 222}; + v = random_ju(); + libj2_ju_to_j2u(v, &a); + mul(&zero, &a, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + v = random_ju(); + libj2_ju_to_j2u(v, &a); + mul(&a, &zero, &r, 0); + + EXPECT(libj2_j2u_is_zero(&r)); + r = (struct libj2_j2u){111, 222}; + random_j2u(&a); + mul(&zero, &a, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + random_j2u(&a); + mul(&a, &zero, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + } + + r = (struct libj2_j2u){111, 222}; + mul(&one, &one, &r, 0); + EXPECT(r.high == 0); + EXPECT(r.low == 1); + + r = (struct libj2_j2u){111, 222}; + mul(&four, &four, &r, 0); + EXPECT(r.high == 0); + EXPECT(r.low == 16); + + for (i = 0; i < 32; i++) { + r = (struct libj2_j2u){111, 222}; + v = random_ju(); + libj2_ju_to_j2u(v, &a); + mul(&one, &a, &r, 0); + EXPECT(r.high == 0); + EXPECT(r.low == v); + + r = (struct libj2_j2u){111, 222}; + v = random_ju(); + libj2_ju_to_j2u(v, &a); + mul(&a, &one, &r, 0); + EXPECT(r.high == 0); + EXPECT(r.low == v); + } + + for (i = 0; i < 32; i++) { + u = random_hju(); + v = random_hju(); + + libj2_ju_to_j2u(u, &a); + libj2_ju_to_j2u(v, &b); + + r = (struct libj2_j2u){111, 222}; + mul(&a, &b, &r, 0); + EXPECT(r.high == 0); + EXPECT(r.low == u * v); + + r = (struct libj2_j2u){111, 222}; + mul(&b, &a, &r, 0); + EXPECT(r.high == 0); + EXPECT(r.low == u * v); + } + + r = (struct libj2_j2u){111, 222}; + mul(&ju_max, &ju_max, &r, 0); + EXPECT(r.high == UINTMAX_MAX - 1U); + EXPECT(r.low == 1); + + r = (struct libj2_j2u){111, 222}; + mul(&j2u_max, &ju_max, &r, 1); + EXPECT(r.high == UINTMAX_MAX); + EXPECT(r.low == 1); + + /* self-check */ + r = (struct libj2_j2u){111, 222}; + EXPECT(refmul(&j2u_max, &ju_max, &r) == 1); + EXPECT(r.high == UINTMAX_MAX); + EXPECT(r.low == 1); + r = (struct libj2_j2u){111, 222}; + EXPECT(refmul(&j2u_max, &j2u_max, &r) == 1); + EXPECT(r.high == 0); + EXPECT(r.low == 1); + + for (i = 0; i < 256; i++) { + random_j2u(&a); + random_j2u(&b); + + expect_overflow = refmul(&a, &b, &expected); + + r = (struct libj2_j2u){111, 222}; + mul(&a, &b, &r, expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_mul_j2u_overflow.c b/libj2_j2u_mul_j2u_overflow.c new file mode 100644 index 0000000..30c665d --- /dev/null +++ b/libj2_j2u_mul_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_mul_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_j2u_destructive.c */ + +#endif diff --git a/libj2_j2u_mul_j2u_overflow_destructive.c b/libj2_j2u_mul_j2u_overflow_destructive.c new file mode 100644 index 0000000..4f346c5 --- /dev/null +++ b/libj2_j2u_mul_j2u_overflow_destructive.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_mul_j2u_overflow_destructive(struct libj2_j2u *restrict a /*result */, struct libj2_j2u *restrict b /*destructed */); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_j2u_destructive.c */ + +#endif diff --git a/libj2_j2u_mul_j2u_to_j2u.c b/libj2_j2u_mul_j2u_to_j2u.c new file mode 100644 index 0000000..b2fb25a --- /dev/null +++ b/libj2_j2u_mul_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_mul_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_j2u_destructive.c */ + +#endif diff --git a/libj2_j2u_mul_j2u_to_j2u_overflow.c b/libj2_j2u_mul_j2u_to_j2u_overflow.c new file mode 100644 index 0000000..5867c4f --- /dev/null +++ b/libj2_j2u_mul_j2u_to_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_mul_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_j2u_destructive.c */ + +#endif diff --git a/libj2_j2u_mul_ju.c b/libj2_j2u_mul_ju.c new file mode 100644 index 0000000..17fc453 --- /dev/null +++ b/libj2_j2u_mul_ju.c @@ -0,0 +1,197 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_mul_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +static uintmax_t +random_small_ju(size_t bits) +{ + uintmax_t r = 0; + while (bits--) + if (rand() < rand()) + r |= (uintmax_t)1 << bits; + return r; +} + +static uintmax_t +random_hju(void) +{ + return random_small_ju(LIBJ2_JU_BIT / 2U); +} + +static uintmax_t +random_ju(void) +{ + return random_small_ju(LIBJ2_JU_BIT); +} + + +static int +refmul(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *expected) +{ + struct libj2_j2u c; + unsigned i; + int overflow = 0; + + libj2_j2u_zero(expected); + for (i = 0; i < LIBJ2_J2U_BIT; i++, b >>= 1) { + if (b & 1U) { + overflow |= libj2_j2u_lsh_to_j2u_overflow(a, i, &c); + libj2_j2u_add_j2u(expected, &c); + } + } + + return overflow; +} + + +static void +mul(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *expected, int expect_overflow) +{ + struct libj2_j2u t, a_saved = *a; + + *expected = *a; + libj2_j2u_mul_ju(expected, b); + + t = (struct libj2_j2u){111, 222}; + libj2_j2u_mul_ju_to_j2u(a, b, &t); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + + t = (struct libj2_j2u){111, 222}; + libj2_ju_mul_j2u_to_j2u(b, a, &t); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + + t = *a; + EXPECT(libj2_j2u_mul_ju_overflow(&t, b) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + + t = (struct libj2_j2u){111, 222}; + EXPECT(libj2_j2u_mul_ju_to_j2u_overflow(a, b, &t) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + + t = (struct libj2_j2u){111, 222}; + EXPECT(libj2_ju_mul_j2u_to_j2u_overflow(b, a, &t) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); +} + + +int +main(void) +{ + struct libj2_j2u r, expected; + uintmax_t u, v, w; + unsigned i; + int expect_overflow; + + srand((unsigned)time(NULL)); + + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){.high = 0, .low = 0}, 0, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){.high = 0, .low = 0}, 1, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){.high = 0, .low = 0}, UINTMAX_MAX, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){.high = 0, .low = 1}, 0, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){.high = 0, .low = UINTMAX_MAX}, 0, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + + for (i = 0; i < 32; i++) { + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){.high = 0, .low = 0}, random_ju(), &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){.high = 0, .low = random_ju()}, 0, &r, 0); + EXPECT(libj2_j2u_is_zero(&r)); + } + + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){.high = 0, .low = 1}, 1, &r, 0); + EXPECT(r.high == 0); + EXPECT(r.low == 1); + + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){.high = 0, .low = 4}, 4, &r, 0); + EXPECT(r.high == 0); + EXPECT(r.low == 16); + + for (i = 0; i < 32; i++) { + r = (struct libj2_j2u){111, 222}; + v = random_ju(); + mul(&(struct libj2_j2u){.high = 0, .low = 1}, v, &r, 0); + EXPECT(r.high == 0); + EXPECT(r.low == v); + + r = (struct libj2_j2u){111, 222}; + v = random_ju(); + mul(&(struct libj2_j2u){.high = 0, .low = v}, 1, &r, 0); + EXPECT(r.high == 0); + EXPECT(r.low == v); + } + + for (i = 0; i < 32; i++) { + u = random_hju(); + v = random_hju(); + + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){.high = 0, .low = u}, v, &r, 0); + EXPECT(r.high == 0); + EXPECT(r.low == u * v); + + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){.high = 0, .low = v}, u, &r, 0); + EXPECT(r.high == 0); + EXPECT(r.low == u * v); + } + + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){.high = 0, .low = UINTMAX_MAX}, UINTMAX_MAX, &r, 0); + EXPECT(r.high == UINTMAX_MAX - 1U); + EXPECT(r.low == 1); + + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){.high = UINTMAX_MAX, .low = UINTMAX_MAX}, UINTMAX_MAX, &r, 1); + EXPECT(r.high == UINTMAX_MAX); + EXPECT(r.low == 1); + + /* self-check */ + r = (struct libj2_j2u){111, 222}; + EXPECT(refmul(&(struct libj2_j2u){.high = UINTMAX_MAX, .low = UINTMAX_MAX}, UINTMAX_MAX, &r) == 1); + EXPECT(r.high == UINTMAX_MAX); + EXPECT(r.low == 1); + + for (i = 0; i < 256; i++) { + u = random_ju(); + v = random_ju(); + w = random_ju(); + + expect_overflow = refmul(&(struct libj2_j2u){u, v}, w, &expected); + + r = (struct libj2_j2u){111, 222}; + mul(&(struct libj2_j2u){u, v}, w, &r, expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_mul_ju_overflow.c b/libj2_j2u_mul_ju_overflow.c new file mode 100644 index 0000000..bd7900f --- /dev/null +++ b/libj2_j2u_mul_ju_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_mul_ju_overflow(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */ + +#endif diff --git a/libj2_j2u_mul_ju_to_j2u.c b/libj2_j2u_mul_ju_to_j2u.c new file mode 100644 index 0000000..7a79b79 --- /dev/null +++ b/libj2_j2u_mul_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_mul_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */ + +#endif diff --git a/libj2_j2u_mul_ju_to_j2u_overflow.c b/libj2_j2u_mul_ju_to_j2u_overflow.c new file mode 100644 index 0000000..c88450b --- /dev/null +++ b/libj2_j2u_mul_ju_to_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_mul_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */ + +#endif diff --git a/libj2_j2u_nand_j2u.c b/libj2_j2u_nand_j2u.c new file mode 100644 index 0000000..6c575fe --- /dev/null +++ b/libj2_j2u_nand_j2u.c @@ -0,0 +1,143 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nand_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static void +check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected) +{ + struct libj2_j2u a_saved = *a, b_saved = *b, r; + + r = *a; + libj2_j2u_nand_j2u(&r, b); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_nand_j2u(&r, &r); + libj2_not_j2u(&r); + EXPECT(libj2_j2u_eq_j2u(&r, &a_saved)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_nand_j2u_to_j2u(a, b, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_nand_j2u_to_j2u(&r, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_j2u_nand_j2u_to_j2u(a, &r, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_nand_j2u_to_j2u(a, a, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + libj2_not_j2u(&r); + EXPECT(libj2_j2u_eq_j2u(&r, &a_saved)); + + r = *a; + libj2_j2u_nand_j2u_to_j2u(&r, &r, &r); + libj2_not_j2u(&r); + EXPECT(libj2_j2u_eq_j2u(&r, &a_saved)); + + if (a->high == 0U) { + r = (struct libj2_j2u){111, 222}; + libj2_ju_nand_j2u_to_j2u(a->low, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_ju_nand_j2u_to_j2u(a->low, &r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } + + if (b->high == 0U) { + r = *a; + libj2_j2u_nand_ju(&r, b->low); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_nand_ju_to_j2u(a, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_nand_ju_to_j2u(&r, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } +} + +int +main(void) +{ + unsigned truthtable[] = {1, 1, 1, 0}; + unsigned i, j; + uintmax_t a_bit, b_bit, r_bit; + struct libj2_j2u a, b, r, a_saved; + + srand((unsigned)time(NULL)); + + for (j = 0; j < 128; j++) { + a.high = a.low = 0; + b.high = b.low = 0; + r.high = r.low = 0; + for (i = 0; i < LIBJ2_J2U_BIT; i++) { + a_bit = (uintmax_t)(rand() < rand()); + b_bit = (uintmax_t)(rand() < rand()); + r_bit = truthtable[a_bit * 2U + b_bit]; + if (i < LIBJ2_JU_BIT) { + a.low |= a_bit << i; + b.low |= b_bit << i; + r.low |= r_bit << i; + } else { + a.high |= a_bit << (i - LIBJ2_JU_BIT); + b.high |= b_bit << (i - LIBJ2_JU_BIT); + r.high |= r_bit << (i - LIBJ2_JU_BIT); + } + } + + check(&a, &b, &r); + + a_saved = a; + a.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[(b.high >> i) & 1U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + a = a_saved; + + b.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 2U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + + r.high = 0U; + r.low = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 3U]; + r.high |= r_bit << i; + r_bit = truthtable[((a.low >> i) & 1U) * 3U]; + r.low |= r_bit << i; + } + check(&a, &a, &r); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_nand_j2u_to_j2u.c b/libj2_j2u_nand_j2u_to_j2u.c new file mode 100644 index 0000000..8cad27e --- /dev/null +++ b/libj2_j2u_nand_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nand_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nand_j2u.c */ + +#endif diff --git a/libj2_j2u_nand_ju.c b/libj2_j2u_nand_ju.c new file mode 100644 index 0000000..0237342 --- /dev/null +++ b/libj2_j2u_nand_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nand_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nand_j2u.c */ + +#endif diff --git a/libj2_j2u_nand_ju_to_j2u.c b/libj2_j2u_nand_ju_to_j2u.c new file mode 100644 index 0000000..b3d458a --- /dev/null +++ b/libj2_j2u_nand_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nand_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nand_j2u.c */ + +#endif diff --git a/libj2_j2u_ne_j2u.c b/libj2_j2u_ne_j2u.c new file mode 100644 index 0000000..539d481 --- /dev/null +++ b/libj2_j2u_ne_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_ne_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_j2u.c */ + +#endif diff --git a/libj2_j2u_ne_ju.c b/libj2_j2u_ne_ju.c new file mode 100644 index 0000000..128f3f6 --- /dev/null +++ b/libj2_j2u_ne_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_ne_ju(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_j2u_nif_j2u.c b/libj2_j2u_nif_j2u.c new file mode 100644 index 0000000..fbb45d4 --- /dev/null +++ b/libj2_j2u_nif_j2u.c @@ -0,0 +1,140 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nif_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static void +check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected) +{ + struct libj2_j2u a_saved = *a, b_saved = *b, r; + + r = *a; + libj2_j2u_nif_j2u(&r, b); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_nif_j2u(&r, &r); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_nif_j2u_to_j2u(a, b, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_nif_j2u_to_j2u(&r, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_j2u_nif_j2u_to_j2u(a, &r, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_nif_j2u_to_j2u(a, a, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_is_zero(&r)); + + r = *a; + libj2_j2u_nif_j2u_to_j2u(&r, &r, &r); + EXPECT(libj2_j2u_is_zero(&r)); + + if (a->high == 0U) { + r = (struct libj2_j2u){111, 222}; + libj2_ju_nif_j2u_to_j2u(a->low, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_ju_nif_j2u_to_j2u(a->low, &r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } + + if (b->high == 0U) { + r = *a; + libj2_j2u_nif_ju(&r, b->low); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_nif_ju_to_j2u(a, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_nif_ju_to_j2u(&r, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } +} + +int +main(void) +{ + unsigned truthtable[] = {0, 1, 0, 0}; + unsigned i, j; + uintmax_t a_bit, b_bit, r_bit; + struct libj2_j2u a, b, r, a_saved; + + srand((unsigned)time(NULL)); + + for (j = 0; j < 128; j++) { + a.high = a.low = 0; + b.high = b.low = 0; + r.high = r.low = 0; + for (i = 0; i < LIBJ2_J2U_BIT; i++) { + a_bit = (uintmax_t)(rand() < rand()); + b_bit = (uintmax_t)(rand() < rand()); + r_bit = truthtable[a_bit * 2U + b_bit]; + if (i < LIBJ2_JU_BIT) { + a.low |= a_bit << i; + b.low |= b_bit << i; + r.low |= r_bit << i; + } else { + a.high |= a_bit << (i - LIBJ2_JU_BIT); + b.high |= b_bit << (i - LIBJ2_JU_BIT); + r.high |= r_bit << (i - LIBJ2_JU_BIT); + } + } + + check(&a, &b, &r); + + a_saved = a; + a.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[(b.high >> i) & 1U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + a = a_saved; + + b.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 2U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + + r.high = 0U; + r.low = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 3U]; + r.high |= r_bit << i; + r_bit = truthtable[((a.low >> i) & 1U) * 3U]; + r.low |= r_bit << i; + } + check(&a, &a, &r); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_nif_j2u_to_j2u.c b/libj2_j2u_nif_j2u_to_j2u.c new file mode 100644 index 0000000..e1cd670 --- /dev/null +++ b/libj2_j2u_nif_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nif_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nif_j2u.c */ + +#endif diff --git a/libj2_j2u_nif_ju.c b/libj2_j2u_nif_ju.c new file mode 100644 index 0000000..caa6222 --- /dev/null +++ b/libj2_j2u_nif_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nif_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nif_j2u.c */ + +#endif diff --git a/libj2_j2u_nif_ju_to_j2u.c b/libj2_j2u_nif_ju_to_j2u.c new file mode 100644 index 0000000..f95f4a0 --- /dev/null +++ b/libj2_j2u_nif_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nif_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nif_j2u.c */ + +#endif diff --git a/libj2_j2u_nimply_j2u.c b/libj2_j2u_nimply_j2u.c new file mode 100644 index 0000000..c81a049 --- /dev/null +++ b/libj2_j2u_nimply_j2u.c @@ -0,0 +1,140 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nimply_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static void +check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected) +{ + struct libj2_j2u a_saved = *a, b_saved = *b, r; + + r = *a; + libj2_j2u_nimply_j2u(&r, b); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_nimply_j2u(&r, &r); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_nimply_j2u_to_j2u(a, b, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_nimply_j2u_to_j2u(&r, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_j2u_nimply_j2u_to_j2u(a, &r, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_nimply_j2u_to_j2u(a, a, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_is_zero(&r)); + + r = *a; + libj2_j2u_nimply_j2u_to_j2u(&r, &r, &r); + EXPECT(libj2_j2u_is_zero(&r)); + + if (a->high == 0U) { + r = (struct libj2_j2u){111, 222}; + libj2_ju_nimply_j2u_to_j2u(a->low, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_ju_nimply_j2u_to_j2u(a->low, &r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } + + if (b->high == 0U) { + r = *a; + libj2_j2u_nimply_ju(&r, b->low); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_nimply_ju_to_j2u(a, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_nimply_ju_to_j2u(&r, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } +} + +int +main(void) +{ + unsigned truthtable[] = {0, 0, 1, 0}; + unsigned i, j; + uintmax_t a_bit, b_bit, r_bit; + struct libj2_j2u a, b, r, a_saved; + + srand((unsigned)time(NULL)); + + for (j = 0; j < 128; j++) { + a.high = a.low = 0; + b.high = b.low = 0; + r.high = r.low = 0; + for (i = 0; i < LIBJ2_J2U_BIT; i++) { + a_bit = (uintmax_t)(rand() < rand()); + b_bit = (uintmax_t)(rand() < rand()); + r_bit = truthtable[a_bit * 2U + b_bit]; + if (i < LIBJ2_JU_BIT) { + a.low |= a_bit << i; + b.low |= b_bit << i; + r.low |= r_bit << i; + } else { + a.high |= a_bit << (i - LIBJ2_JU_BIT); + b.high |= b_bit << (i - LIBJ2_JU_BIT); + r.high |= r_bit << (i - LIBJ2_JU_BIT); + } + } + + check(&a, &b, &r); + + a_saved = a; + a.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[(b.high >> i) & 1U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + a = a_saved; + + b.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 2U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + + r.high = 0U; + r.low = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 3U]; + r.high |= r_bit << i; + r_bit = truthtable[((a.low >> i) & 1U) * 3U]; + r.low |= r_bit << i; + } + check(&a, &a, &r); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_nimply_j2u_to_j2u.c b/libj2_j2u_nimply_j2u_to_j2u.c new file mode 100644 index 0000000..654be2e --- /dev/null +++ b/libj2_j2u_nimply_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nimply_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nimply_j2u.c */ + +#endif diff --git a/libj2_j2u_nimply_ju.c b/libj2_j2u_nimply_ju.c new file mode 100644 index 0000000..8d87725 --- /dev/null +++ b/libj2_j2u_nimply_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nimply_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nimply_j2u.c */ + +#endif diff --git a/libj2_j2u_nimply_ju_to_j2u.c b/libj2_j2u_nimply_ju_to_j2u.c new file mode 100644 index 0000000..e46d803 --- /dev/null +++ b/libj2_j2u_nimply_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nimply_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nimply_j2u.c */ + +#endif diff --git a/libj2_j2u_nor_j2u.c b/libj2_j2u_nor_j2u.c new file mode 100644 index 0000000..902997f --- /dev/null +++ b/libj2_j2u_nor_j2u.c @@ -0,0 +1,143 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nor_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static void +check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected) +{ + struct libj2_j2u a_saved = *a, b_saved = *b, r; + + r = *a; + libj2_j2u_nor_j2u(&r, b); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_nor_j2u(&r, &r); + libj2_not_j2u(&r); + EXPECT(libj2_j2u_eq_j2u(&r, &a_saved)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_nor_j2u_to_j2u(a, b, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_nor_j2u_to_j2u(&r, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_j2u_nor_j2u_to_j2u(a, &r, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_nor_j2u_to_j2u(a, a, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + libj2_not_j2u(&r); + EXPECT(libj2_j2u_eq_j2u(&r, &a_saved)); + + r = *a; + libj2_j2u_nor_j2u_to_j2u(&r, &r, &r); + libj2_not_j2u(&r); + EXPECT(libj2_j2u_eq_j2u(&r, &a_saved)); + + if (a->high == 0U) { + r = (struct libj2_j2u){111, 222}; + libj2_ju_nor_j2u_to_j2u(a->low, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_ju_nor_j2u_to_j2u(a->low, &r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } + + if (b->high == 0U) { + r = *a; + libj2_j2u_nor_ju(&r, b->low); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_nor_ju_to_j2u(a, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_nor_ju_to_j2u(&r, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } +} + +int +main(void) +{ + unsigned truthtable[] = {1, 0, 0, 0}; + unsigned i, j; + uintmax_t a_bit, b_bit, r_bit; + struct libj2_j2u a, b, r, a_saved; + + srand((unsigned)time(NULL)); + + for (j = 0; j < 128; j++) { + a.high = a.low = 0; + b.high = b.low = 0; + r.high = r.low = 0; + for (i = 0; i < LIBJ2_J2U_BIT; i++) { + a_bit = (uintmax_t)(rand() < rand()); + b_bit = (uintmax_t)(rand() < rand()); + r_bit = truthtable[a_bit * 2U + b_bit]; + if (i < LIBJ2_JU_BIT) { + a.low |= a_bit << i; + b.low |= b_bit << i; + r.low |= r_bit << i; + } else { + a.high |= a_bit << (i - LIBJ2_JU_BIT); + b.high |= b_bit << (i - LIBJ2_JU_BIT); + r.high |= r_bit << (i - LIBJ2_JU_BIT); + } + } + + check(&a, &b, &r); + + a_saved = a; + a.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[(b.high >> i) & 1U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + a = a_saved; + + b.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 2U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + + r.high = 0U; + r.low = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 3U]; + r.high |= r_bit << i; + r_bit = truthtable[((a.low >> i) & 1U) * 3U]; + r.low |= r_bit << i; + } + check(&a, &a, &r); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_nor_j2u_to_j2u.c b/libj2_j2u_nor_j2u_to_j2u.c new file mode 100644 index 0000000..38c30c7 --- /dev/null +++ b/libj2_j2u_nor_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nor_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nor_j2u.c */ + +#endif diff --git a/libj2_j2u_nor_ju.c b/libj2_j2u_nor_ju.c new file mode 100644 index 0000000..145ec9e --- /dev/null +++ b/libj2_j2u_nor_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nor_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nor_j2u.c */ + +#endif diff --git a/libj2_j2u_nor_ju_to_j2u.c b/libj2_j2u_nor_ju_to_j2u.c new file mode 100644 index 0000000..89f797d --- /dev/null +++ b/libj2_j2u_nor_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_nor_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nor_j2u.c */ + +#endif diff --git a/libj2_j2u_or_j2u.c b/libj2_j2u_or_j2u.c new file mode 100644 index 0000000..9593807 --- /dev/null +++ b/libj2_j2u_or_j2u.c @@ -0,0 +1,140 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_or_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static void +check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected) +{ + struct libj2_j2u a_saved = *a, b_saved = *b, r; + + r = *a; + libj2_j2u_or_j2u(&r, b); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_or_j2u(&r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &a_saved)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_or_j2u_to_j2u(a, b, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_or_j2u_to_j2u(&r, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_j2u_or_j2u_to_j2u(a, &r, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_or_j2u_to_j2u(a, a, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, a)); + + r = *a; + libj2_j2u_or_j2u_to_j2u(a, a, a); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + + if (a->high == 0U) { + r = (struct libj2_j2u){111, 222}; + libj2_ju_or_j2u_to_j2u(a->low, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_ju_or_j2u_to_j2u(a->low, &r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } + + if (b->high == 0U) { + r = *a; + libj2_j2u_or_ju(&r, b->low); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_or_ju_to_j2u(a, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_or_ju_to_j2u(&r, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } +} + +int +main(void) +{ + unsigned truthtable[] = {0, 1, 1, 1}; + unsigned i, j; + uintmax_t a_bit, b_bit, r_bit; + struct libj2_j2u a, b, r, a_saved; + + srand((unsigned)time(NULL)); + + for (j = 0; j < 128; j++) { + a.high = a.low = 0; + b.high = b.low = 0; + r.high = r.low = 0; + for (i = 0; i < LIBJ2_J2U_BIT; i++) { + a_bit = (uintmax_t)(rand() < rand()); + b_bit = (uintmax_t)(rand() < rand()); + r_bit = truthtable[a_bit * 2U + b_bit]; + if (i < LIBJ2_JU_BIT) { + a.low |= a_bit << i; + b.low |= b_bit << i; + r.low |= r_bit << i; + } else { + a.high |= a_bit << (i - LIBJ2_JU_BIT); + b.high |= b_bit << (i - LIBJ2_JU_BIT); + r.high |= r_bit << (i - LIBJ2_JU_BIT); + } + } + + check(&a, &b, &r); + + a_saved = a; + a.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[(b.high >> i) & 1U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + a = a_saved; + + b.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 2U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + + r.high = 0U; + r.low = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 3U]; + r.high |= r_bit << i; + r_bit = truthtable[((a.low >> i) & 1U) * 3U]; + r.low |= r_bit << i; + } + check(&a, &a, &r); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_or_j2u_to_j2u.c b/libj2_j2u_or_j2u_to_j2u.c new file mode 100644 index 0000000..ab4b29b --- /dev/null +++ b/libj2_j2u_or_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_or_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_or_j2u.c */ + +#endif diff --git a/libj2_j2u_or_ju.c b/libj2_j2u_or_ju.c new file mode 100644 index 0000000..81ad912 --- /dev/null +++ b/libj2_j2u_or_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_or_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_or_j2u.c */ + +#endif diff --git a/libj2_j2u_or_ju_to_j2u.c b/libj2_j2u_or_ju_to_j2u.c new file mode 100644 index 0000000..2707726 --- /dev/null +++ b/libj2_j2u_or_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_or_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_or_j2u.c */ + +#endif diff --git a/libj2_j2u_rdiv_j2u.c b/libj2_j2u_rdiv_j2u.c new file mode 100644 index 0000000..fd4a4fb --- /dev/null +++ b/libj2_j2u_rdiv_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_rdiv_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_rdivmod_j2u.c b/libj2_j2u_rdivmod_j2u.c new file mode 100644 index 0000000..c856570 --- /dev/null +++ b/libj2_j2u_rdivmod_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline uintmax_t libj2_j2u_rdivmod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_rdivmod_j2u_to_j2u.c b/libj2_j2u_rdivmod_j2u_to_j2u.c new file mode 100644 index 0000000..fc04b1a --- /dev/null +++ b/libj2_j2u_rdivmod_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_rdivmod_j2u_to_j2u(struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res_q); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_rmod_j2u.c b/libj2_j2u_rmod_j2u.c new file mode 100644 index 0000000..013e2af --- /dev/null +++ b/libj2_j2u_rmod_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_rmod_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_divmod_j2u_to_j2u.c */ + +#endif diff --git a/libj2_j2u_rrot.c b/libj2_j2u_rrot.c new file mode 100644 index 0000000..4fb3a70 --- /dev/null +++ b/libj2_j2u_rrot.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_rrot(struct libj2_j2u *a, unsigned b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_lrot.c */ + +#endif diff --git a/libj2_j2u_rrot_to_j2u.c b/libj2_j2u_rrot_to_j2u.c new file mode 100644 index 0000000..a73d220 --- /dev/null +++ b/libj2_j2u_rrot_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_rrot_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_lrot.c */ + +#endif diff --git a/libj2_j2u_rsh.c b/libj2_j2u_rsh.c new file mode 100644 index 0000000..2a5ed50 --- /dev/null +++ b/libj2_j2u_rsh.c @@ -0,0 +1,129 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_rsh(struct libj2_j2u *a, unsigned b); +/* TODO Add man page */ + + +#else + +static const char *patterns[] = { + "0", + "1111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111", + "1010101010101001010100100010101010101011000101101011101001000110", + "1110100100100010000010111111011101101001000010001000011110101010", + "11111111111100001001011", + "0010011011001", + "110010001011110100101001010011010111101", + NULL +}; + + +static int +set(struct libj2_j2u *a, const char *bits, size_t leading_zeroes) +{ + size_t i, n; + int underflow = 0; + + a->high = 0; + a->low = 0; + + n = strlen(bits); + if (n > LIBJ2_J2U_BIT) { + bits = &bits[n - LIBJ2_J2U_BIT]; + n = LIBJ2_J2U_BIT; + } + + while (n && leading_zeroes--) + underflow |= bits[--n] == '1'; + + for (i = 0; n && i < LIBJ2_JU_BIT; i++) + if (bits[--n] == '1') + a->low |= (uintmax_t)1 << i; + + for (i = 0; n && i < LIBJ2_JU_BIT; i++) + if (bits[--n] == '1') + a->high |= (uintmax_t)1 << i; + + return underflow; +} + + +static void +check(const char *pattern) +{ + struct libj2_j2u a, a_saved, r, expected; + unsigned i; + int underflows; + + set(&a, pattern, 0); + a_saved = a; + for (i = 0; i < LIBJ2_J2U_BIT + 8U; i++) { + underflows = set(&expected, pattern, i); + + r = a; + libj2_j2u_rsh(&r, i); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = a; + EXPECT(libj2_j2u_rsh_underflow(&r, i) == underflows); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_rsh_to_j2u(&a, i, &r); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = (struct libj2_j2u){111, 222}; + EXPECT(libj2_j2u_rsh_to_j2u_underflow(&a, i, &r) == underflows); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = a; + libj2_j2u_rsh_to_j2u(&r, i, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = a; + EXPECT(libj2_j2u_rsh_to_j2u_underflow(&r, i, &r) == underflows); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + } +} + + +int +main(void) +{ + size_t i, j; + char pattern[LIBJ2_J2U_BIT + 1U]; + + srand((unsigned)time(NULL)); + + for (i = 0; patterns[i]; i++) + check(patterns[i]); + + for (i = 0; i < 64; i++) { + for (j = 0; j < LIBJ2_J2U_BIT; j++) + pattern[j] = '0' + (rand() < rand()); + pattern[LIBJ2_J2U_BIT] = '\0'; + check(pattern); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_rsh_to_j2u.c b/libj2_j2u_rsh_to_j2u.c new file mode 100644 index 0000000..f5b63bd --- /dev/null +++ b/libj2_j2u_rsh_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_rsh_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_rsh.c */ + +#endif diff --git a/libj2_j2u_rsh_to_j2u_underflow.c b/libj2_j2u_rsh_to_j2u_underflow.c new file mode 100644 index 0000000..c38a006 --- /dev/null +++ b/libj2_j2u_rsh_to_j2u_underflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_rsh_to_j2u_underflow(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_rsh.c */ + +#endif diff --git a/libj2_j2u_rsh_underflow.c b/libj2_j2u_rsh_underflow.c new file mode 100644 index 0000000..6cc9615 --- /dev/null +++ b/libj2_j2u_rsh_underflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_rsh_underflow(struct libj2_j2u *a, unsigned b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_rsh.c */ + +#endif diff --git a/libj2_j2u_rsub_j2u.c b/libj2_j2u_rsub_j2u.c new file mode 100644 index 0000000..edae0e7 --- /dev/null +++ b/libj2_j2u_rsub_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_rsub_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */ + +#endif diff --git a/libj2_j2u_rsub_j2u_overflow.c b/libj2_j2u_rsub_j2u_overflow.c new file mode 100644 index 0000000..e730930 --- /dev/null +++ b/libj2_j2u_rsub_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_rsub_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */ + +#endif diff --git a/libj2_j2u_rsub_ju.c b/libj2_j2u_rsub_ju.c new file mode 100644 index 0000000..cd3a80f --- /dev/null +++ b/libj2_j2u_rsub_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_rsub_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */ + +#endif diff --git a/libj2_j2u_rsub_ju_overflow.c b/libj2_j2u_rsub_ju_overflow.c new file mode 100644 index 0000000..398479f --- /dev/null +++ b/libj2_j2u_rsub_ju_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_rsub_ju_overflow(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */ + +#endif diff --git a/libj2_j2u_sub_j2u.c b/libj2_j2u_sub_j2u.c new file mode 100644 index 0000000..6727c71 --- /dev/null +++ b/libj2_j2u_sub_j2u.c @@ -0,0 +1,213 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_sub_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static uintmax_t +random_ju(void) +{ + size_t n = LIBJ2_JU_BIT; + uintmax_t r = 0; + while (n--) + if (rand() < rand()) + r |= (uintmax_t)1 << n; + return r; +} + + +static void +check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low, + uintmax_t r_high, uintmax_t r_low, int r_overflow) +{ + struct libj2_j2u a, b, r, a_saved, b_saved, expected; + + a_saved = (struct libj2_j2u){.high = a_high, .low = a_low}; + b_saved = (struct libj2_j2u){.high = b_high, .low = b_low}; + expected = (struct libj2_j2u){.high = r_high, .low = r_low}; + + a = a_saved; + b = b_saved; + libj2_j2u_sub_j2u(&a, &b); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + b = b_saved; + libj2_j2u_sub_j2u_to_j2u(&a, &b, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + a = a_saved; + b = b_saved; + libj2_j2u_sub_j2u_to_j2u(&a, &b, &a); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + a = a_saved; + b = b_saved; + libj2_j2u_sub_j2u_to_j2u(&a, &b, &b); + EXPECT(libj2_j2u_eq_j2u(&b, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + b = b_saved; + EXPECT(libj2_j2u_sub_j2u_overflow(&a, &b) == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + b = b_saved; + EXPECT(libj2_j2u_sub_j2u_to_j2u_overflow(&a, &b, &r) == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + a = a_saved; + b = b_saved; + EXPECT(libj2_j2u_sub_j2u_to_j2u_overflow(&a, &b, &a) == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + + a = a_saved; + b = b_saved; + EXPECT(libj2_j2u_sub_j2u_to_j2u_overflow(&a, &b, &b) == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&b, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + a = a_saved; + b = b_saved; + libj2_j2u_rsub_j2u(&b, &a); + EXPECT(libj2_j2u_eq_j2u(&b, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + b = b_saved; + EXPECT(libj2_j2u_rsub_j2u_overflow(&b, &a) == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&b, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); +} + + +static void +check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low) +{ + struct libj2_j2u a, b, r; + int overflow; + + a.high = a_high; + a.low = a_low; + b.high = b_high; + b.low = b_low; + + overflow = libj2_j2u_lt_j2u(&a, &b); + libj2_minus_j2u(&b); + libj2_j2u_add_j2u_to_j2u_overflow(&a, &b, &r); + check_(a_high, a_low, b_high, b_low, r.high, r.low, overflow); +} + + +static void +check_manual(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low, + uintmax_t r_high, uintmax_t r_low, int r_overflow) +{ + check_(a_high, a_low, b_high, b_low, r_high, r_low, r_overflow); + check(a_high, a_low, b_high, b_low); +} + + +static void +check_double(uintmax_t high, uintmax_t low) +{ + struct libj2_j2u a, a_saved, r; + + a_saved = (struct libj2_j2u){.high = high, .low = low}; + + a = a_saved; + libj2_j2u_sub_j2u(&a, &a); + EXPECT(libj2_j2u_is_zero(&a)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + libj2_j2u_sub_j2u_to_j2u(&a, &a, &r); + EXPECT(libj2_j2u_is_zero(&r)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + a = a_saved; + libj2_j2u_sub_j2u_to_j2u(&a, &a, &a); + EXPECT(libj2_j2u_is_zero(&a)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + EXPECT(libj2_j2u_sub_j2u_overflow(&a, &a) == 0); + EXPECT(libj2_j2u_is_zero(&a)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + EXPECT(libj2_j2u_sub_j2u_to_j2u_overflow(&a, &a, &r) == 0); + EXPECT(libj2_j2u_is_zero(&r)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + a = a_saved; + EXPECT(libj2_j2u_sub_j2u_to_j2u_overflow(&a, &a, &a) == 0); + EXPECT(libj2_j2u_is_zero(&a)); + + a = a_saved; + libj2_j2u_rsub_j2u(&a, &a); + EXPECT(libj2_j2u_is_zero(&a)); + + r = (struct libj2_j2u){111, 222}; + a = a_saved; + EXPECT(libj2_j2u_rsub_j2u_overflow(&a, &a) == 0); + EXPECT(libj2_j2u_is_zero(&a)); +} + + +int +main(void) +{ + unsigned i; + + srand((unsigned)time(NULL)); + + check_manual(0, 0, 0, 0, 0, 0, 0); + check_manual(0, 1, 0, 1, 0, 0, 0); + check_manual(0, 1, 0, 0, 0, 1, 0); + check_manual(1, 0, 0, 1, 0, UINTMAX_MAX, 0); + check_manual(1, 1, 0, 2, 0, UINTMAX_MAX, 0); + check_manual(1, 1, 0, 1, 1, 0, 0); + check_manual(2, 0, 0, 1, 1, UINTMAX_MAX, 0); + check_manual(2, 0, 1, 1, 0, UINTMAX_MAX, 0); + check_manual(0, 0, 0, 1, UINTMAX_MAX, UINTMAX_MAX, 1); + check_manual(0, UINTMAX_MAX, 0, 1, 0, UINTMAX_MAX - 1U, 0); + check_manual(0, UINTMAX_MAX, 0, UINTMAX_MAX, 0, 0, 0); + check_manual(UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX, 0, 0, 0); + + for (i = 0; i < 256; i++) + check(random_ju(), random_ju(), random_ju(), random_ju()); + + check_double(0, 0); + check_double(0, UINTMAX_MAX); + check_double(UINTMAX_MAX, 0); + check_double(UINTMAX_MAX, UINTMAX_MAX); + for (i = 0; i < 256; i++) { + check_double(0, random_ju()); + check_double(random_ju(), 0); + check_double(random_ju(), UINTMAX_MAX); + check_double(random_ju(), random_ju()); + check_double(UINTMAX_MAX, random_ju()); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_sub_j2u_overflow.c b/libj2_j2u_sub_j2u_overflow.c new file mode 100644 index 0000000..c4e3052 --- /dev/null +++ b/libj2_j2u_sub_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_sub_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */ + +#endif diff --git a/libj2_j2u_sub_j2u_to_j2u.c b/libj2_j2u_sub_j2u_to_j2u.c new file mode 100644 index 0000000..4f3e0c3 --- /dev/null +++ b/libj2_j2u_sub_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_sub_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */ + +#endif diff --git a/libj2_j2u_sub_j2u_to_j2u_overflow.c b/libj2_j2u_sub_j2u_to_j2u_overflow.c new file mode 100644 index 0000000..ca518a9 --- /dev/null +++ b/libj2_j2u_sub_j2u_to_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_sub_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */ + +#endif diff --git a/libj2_j2u_sub_ju.c b/libj2_j2u_sub_ju.c new file mode 100644 index 0000000..b2a3f47 --- /dev/null +++ b/libj2_j2u_sub_ju.c @@ -0,0 +1,142 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_sub_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +static uintmax_t +random_ju(void) +{ + size_t n = LIBJ2_JU_BIT; + uintmax_t r = 0; + while (n--) + if (rand() < rand()) + r |= (uintmax_t)1 << n; + return r; +} + + +static void +check(uintmax_t a_high, uintmax_t a_low, uintmax_t b) +{ + struct libj2_j2u a, r, expected; + int expected_overflow, expected_roverflow; + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + expected_overflow = libj2_j2u_lt_ju(&a, b); + expected_roverflow = libj2_ju_lt_j2u(b, &a); + libj2_ju_to_j2u(b, &expected); + libj2_minus_j2u(&expected); + libj2_j2u_add_j2u_overflow(&expected, &a); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + libj2_j2u_sub_ju(&a, b); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_j2u_sub_ju_overflow(&a, b) == expected_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + libj2_j2u_sub_ju_to_j2u(&a, b, &r); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + libj2_j2u_sub_ju_to_j2u(&a, b, &a); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_j2u_sub_ju_to_j2u_overflow(&a, b, &r) == expected_overflow); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_j2u_sub_ju_to_j2u_overflow(&a, b, &a) == expected_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + libj2_ju_sub_j2u_to_j2u(b, &a, &r); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + libj2_minus_j2u(&r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + libj2_ju_sub_j2u_to_j2u(b, &a, &a); + libj2_minus_j2u(&a); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + libj2_j2u_rsub_ju(&a, b); + libj2_minus_j2u(&a); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_j2u_rsub_ju_overflow(&a, b) == expected_roverflow); + libj2_minus_j2u(&a); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + + r = (struct libj2_j2u){111, 222}; + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_ju_sub_j2u_to_j2u_overflow(b, &a, &r) == expected_roverflow); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + libj2_minus_j2u(&r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_ju_sub_j2u_to_j2u_overflow(b, &a, &a) == expected_roverflow); + libj2_minus_j2u(&a); + EXPECT(libj2_j2u_eq_j2u(&a, &expected)); +} + + +int +main(void) +{ + unsigned i; + + srand((unsigned)time(NULL)); + + check(0, 0, 0); + check(0, 0, UINTMAX_MAX); + check(UINTMAX_MAX, 0, 0); + check(UINTMAX_MAX, 0, UINTMAX_MAX); + for (i = 0; i < 256; i++) { + check(0, 0, random_ju()); + check(random_ju(), 0, 0); + check(random_ju(), 0, random_ju()); + check(random_ju(), 0, UINTMAX_MAX); + check(UINTMAX_MAX, 0, random_ju()); + } + + check(0, UINTMAX_MAX, 0); + check(0, UINTMAX_MAX, UINTMAX_MAX); + check(UINTMAX_MAX, UINTMAX_MAX, 0); + check(UINTMAX_MAX, UINTMAX_MAX, UINTMAX_MAX); + for (i = 0; i < 256; i++) { + check(0, UINTMAX_MAX, random_ju()); + check(random_ju(), UINTMAX_MAX, 0); + check(random_ju(), UINTMAX_MAX, 1); + check(random_ju(), UINTMAX_MAX, random_ju()); + check(random_ju(), UINTMAX_MAX, UINTMAX_MAX); + check(UINTMAX_MAX, UINTMAX_MAX, random_ju()); + } + + for (i = 0; i < 256; i++) + check(random_ju(), random_ju(), random_ju()); + + return 0; +} + +#endif diff --git a/libj2_j2u_sub_ju_overflow.c b/libj2_j2u_sub_ju_overflow.c new file mode 100644 index 0000000..4b675be --- /dev/null +++ b/libj2_j2u_sub_ju_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_sub_ju_overflow(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */ + +#endif diff --git a/libj2_j2u_sub_ju_to_j2u.c b/libj2_j2u_sub_ju_to_j2u.c new file mode 100644 index 0000000..78ddc3a --- /dev/null +++ b/libj2_j2u_sub_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_sub_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */ + +#endif diff --git a/libj2_j2u_sub_ju_to_j2u_overflow.c b/libj2_j2u_sub_ju_to_j2u_overflow.c new file mode 100644 index 0000000..4f983ab --- /dev/null +++ b/libj2_j2u_sub_ju_to_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_sub_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */ + +#endif diff --git a/libj2_j2u_test_bit.c b/libj2_j2u_test_bit.c new file mode 100644 index 0000000..2d4661b --- /dev/null +++ b/libj2_j2u_test_bit.c @@ -0,0 +1,39 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_test_bit(const struct libj2_j2u *a, unsigned b); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u a; + unsigned i, j, k; + + for (k = 1; k <= 10; k++) { + for (j = 0; j < k; j++) { + a.high = 0; + a.low = 0; + for (i = 0; i < LIBJ2_J2U_BIT; i++) { + if (i % k != j) + continue; + if (i < LIBJ2_JU_BIT) + a.low |= (uintmax_t)1 << i; + else + a.high |= (uintmax_t)1 << (i - LIBJ2_JU_BIT); + } + for (i = 0; i < LIBJ2_J2U_BIT; i++) + EXPECT(libj2_j2u_test_bit(&a, i) == (i % k == j)); + for (i = LIBJ2_J2U_BIT; i < 2U * LIBJ2_J2U_BIT; i++) + EXPECT(libj2_j2u_test_bit(&a, i) == 0); + } + } + + return 0; +} + +#endif diff --git a/libj2_j2u_test_high_ju.c b/libj2_j2u_test_high_ju.c new file mode 100644 index 0000000..0d03b40 --- /dev/null +++ b/libj2_j2u_test_high_ju.c @@ -0,0 +1,35 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_test_high_ju(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u a; + uintmax_t h, i, j; + + for (h = 0; h < 10; h++) { + a.low = h; + for (i = 0; i < 128; i++) { + for (j = 0; j < 128; j++) { + a.high = i; + if (i & j) + EXPECT(libj2_j2u_test_high_ju(&a, j) == 1); + else + EXPECT(libj2_j2u_test_high_ju(&a, j) == 0); + EXPECT(a.low == h); + EXPECT(a.high == i); + } + } + } + + return 0; +} + +#endif diff --git a/libj2_j2u_test_j2u.c b/libj2_j2u_test_j2u.c new file mode 100644 index 0000000..682da56 --- /dev/null +++ b/libj2_j2u_test_j2u.c @@ -0,0 +1,90 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_test_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static void +set_pattern(struct libj2_j2u *a, unsigned off, unsigned mod) +{ + unsigned i; + a->high = 0; + a->low = 0; + for (i = 0; i < LIBJ2_J2U_BIT; i++) { + if (i % mod != off) + continue; + if (i < LIBJ2_JU_BIT) + a->low |= (uintmax_t)1 << i; + else + a->high |= (uintmax_t)1 << (i - LIBJ2_JU_BIT); + } +} + +CONST static int +expected(unsigned a_off, unsigned a_mod, unsigned b_off, unsigned b_mod) +{ + unsigned a, b; + if (a_off >= a_mod || b_off >= b_mod) + return 0; + if (a_mod == b_mod) + return a_off == b_off; + a = a_off; + b = b_off; + while (a < LIBJ2_J2U_BIT && b < LIBJ2_J2U_BIT) { + if (a == b) + return 1; + if (a < b) + a += a_mod; + else + b += b_mod; + } + return 0; +} + +int +main(void) +{ + struct libj2_j2u a, b, a_saved, b_saved; + unsigned i, j, u, v, ii, jj; + unsigned mods[] = {1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 33, 64, 12, LIBJ2_J2U_BIT, + LIBJ2_J2U_BIT - 1U, LIBJ2_J2U_BIT - 2U, LIBJ2_J2U_BIT - 3U}; + + EXPECT(expected(0, 4, 0, 5) == 1); + EXPECT(expected(0, 4, 1, 4) == 0); + EXPECT(expected(0, 4, 0, 4) == 1); + EXPECT(expected(0, 2, 0, 3) == 1); + + for (ii = 0; ii < sizeof(mods) / sizeof(*mods); ii++) { + i = mods[ii]; + for (u = 0; u <= i; u++) { + set_pattern(&a, u, i); + a_saved = a; + EXPECT(libj2_j2u_test_j2u(&a, &a) == (u < i)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + b.high = ~a.high; + b.low = ~a.low; + b_saved = b; + EXPECT(libj2_j2u_test_j2u(&a, &b) == 0); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + for (jj = 0; jj < sizeof(mods) / sizeof(*mods); jj++) { + j = mods[jj]; + for (v = 0; v <= j; v++) { + set_pattern(&b, v, j); + b_saved = b; + EXPECT(libj2_j2u_test_j2u(&a, &b) == expected(u, i, v, j)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + } + } + } + } + + return 0; +} + +#endif diff --git a/libj2_j2u_test_ju.c b/libj2_j2u_test_ju.c new file mode 100644 index 0000000..5752bf2 --- /dev/null +++ b/libj2_j2u_test_ju.c @@ -0,0 +1,35 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_test_ju(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u a; + uintmax_t h, i, j; + + for (h = 0; h < 10; h++) { + a.high = h; + for (i = 0; i < 128; i++) { + for (j = 0; j < 128; j++) { + a.low = i; + if (i & j) + EXPECT(libj2_j2u_test_ju(&a, j) == 1); + else + EXPECT(libj2_j2u_test_ju(&a, j) == 0); + EXPECT(a.high == h); + EXPECT(a.low == i); + } + } + } + + return 0; +} + +#endif diff --git a/libj2_j2u_xnor_j2u.c b/libj2_j2u_xnor_j2u.c new file mode 100644 index 0000000..98f5298 --- /dev/null +++ b/libj2_j2u_xnor_j2u.c @@ -0,0 +1,140 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_xnor_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static void +check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected) +{ + struct libj2_j2u a_saved = *a, b_saved = *b, r; + + r = *a; + libj2_j2u_xnor_j2u(&r, b); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_xnor_j2u(&r, &r); + EXPECT(libj2_j2u_is_max(&r)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_xnor_j2u_to_j2u(a, b, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_xnor_j2u_to_j2u(&r, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_j2u_xnor_j2u_to_j2u(a, &r, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_xnor_j2u_to_j2u(a, a, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_is_max(&r)); + + r = *a; + libj2_j2u_xnor_j2u_to_j2u(&r, &r, &r); + EXPECT(libj2_j2u_is_max(&r)); + + if (a->high == 0U) { + r = (struct libj2_j2u){111, 222}; + libj2_ju_xnor_j2u_to_j2u(a->low, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_ju_xnor_j2u_to_j2u(a->low, &r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } + + if (b->high == 0U) { + r = *a; + libj2_j2u_xnor_ju(&r, b->low); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_xnor_ju_to_j2u(a, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_xnor_ju_to_j2u(&r, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } +} + +int +main(void) +{ + unsigned truthtable[] = {1, 0, 0, 1}; + unsigned i, j; + uintmax_t a_bit, b_bit, r_bit; + struct libj2_j2u a, b, r, a_saved; + + srand((unsigned)time(NULL)); + + for (j = 0; j < 128; j++) { + a.high = a.low = 0; + b.high = b.low = 0; + r.high = r.low = 0; + for (i = 0; i < LIBJ2_J2U_BIT; i++) { + a_bit = (uintmax_t)(rand() < rand()); + b_bit = (uintmax_t)(rand() < rand()); + r_bit = truthtable[a_bit * 2U + b_bit]; + if (i < LIBJ2_JU_BIT) { + a.low |= a_bit << i; + b.low |= b_bit << i; + r.low |= r_bit << i; + } else { + a.high |= a_bit << (i - LIBJ2_JU_BIT); + b.high |= b_bit << (i - LIBJ2_JU_BIT); + r.high |= r_bit << (i - LIBJ2_JU_BIT); + } + } + + check(&a, &b, &r); + + a_saved = a; + a.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[(b.high >> i) & 1U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + a = a_saved; + + b.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 2U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + + r.high = 0U; + r.low = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 3U]; + r.high |= r_bit << i; + r_bit = truthtable[((a.low >> i) & 1U) * 3U]; + r.low |= r_bit << i; + } + check(&a, &a, &r); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_xnor_j2u_to_j2u.c b/libj2_j2u_xnor_j2u_to_j2u.c new file mode 100644 index 0000000..111532f --- /dev/null +++ b/libj2_j2u_xnor_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_xnor_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_xnor_j2u.c */ + +#endif diff --git a/libj2_j2u_xnor_ju.c b/libj2_j2u_xnor_ju.c new file mode 100644 index 0000000..0d3f871 --- /dev/null +++ b/libj2_j2u_xnor_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_xnor_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_xnor_j2u.c */ + +#endif diff --git a/libj2_j2u_xnor_ju_to_j2u.c b/libj2_j2u_xnor_ju_to_j2u.c new file mode 100644 index 0000000..ca1bfe6 --- /dev/null +++ b/libj2_j2u_xnor_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_xnor_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_xnor_j2u.c */ + +#endif diff --git a/libj2_j2u_xor_j2u.c b/libj2_j2u_xor_j2u.c new file mode 100644 index 0000000..c6ee6d1 --- /dev/null +++ b/libj2_j2u_xor_j2u.c @@ -0,0 +1,140 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_xor_j2u(struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +static void +check(struct libj2_j2u *a, struct libj2_j2u *b, const struct libj2_j2u *expected) +{ + struct libj2_j2u a_saved = *a, b_saved = *b, r; + + r = *a; + libj2_j2u_xor_j2u(&r, b); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_xor_j2u(&r, &r); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_xor_j2u_to_j2u(a, b, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_xor_j2u_to_j2u(&r, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_j2u_xor_j2u_to_j2u(a, &r, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_xor_j2u_to_j2u(a, a, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_is_zero(&r)); + + r = *a; + libj2_j2u_xor_j2u_to_j2u(&r, &r, &r); + EXPECT(libj2_j2u_is_zero(&r)); + + if (a->high == 0U) { + r = (struct libj2_j2u){111, 222}; + libj2_ju_xor_j2u_to_j2u(a->low, b, &r); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *b; + libj2_ju_xor_j2u_to_j2u(a->low, &r, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } + + if (b->high == 0U) { + r = *a; + libj2_j2u_xor_ju(&r, b->low); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = (struct libj2_j2u){111, 222}; + libj2_j2u_xor_ju_to_j2u(a, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + + r = *a; + libj2_j2u_xor_ju_to_j2u(&r, b->low, &r); + EXPECT(libj2_j2u_eq_j2u(&r, expected)); + } +} + +int +main(void) +{ + unsigned truthtable[] = {0, 1, 1, 0}; + unsigned i, j; + uintmax_t a_bit, b_bit, r_bit; + struct libj2_j2u a, b, r, a_saved; + + srand((unsigned)time(NULL)); + + for (j = 0; j < 128; j++) { + a.high = a.low = 0; + b.high = b.low = 0; + r.high = r.low = 0; + for (i = 0; i < LIBJ2_J2U_BIT; i++) { + a_bit = (uintmax_t)(rand() < rand()); + b_bit = (uintmax_t)(rand() < rand()); + r_bit = truthtable[a_bit * 2U + b_bit]; + if (i < LIBJ2_JU_BIT) { + a.low |= a_bit << i; + b.low |= b_bit << i; + r.low |= r_bit << i; + } else { + a.high |= a_bit << (i - LIBJ2_JU_BIT); + b.high |= b_bit << (i - LIBJ2_JU_BIT); + r.high |= r_bit << (i - LIBJ2_JU_BIT); + } + } + + check(&a, &b, &r); + + a_saved = a; + a.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[(b.high >> i) & 1U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + a = a_saved; + + b.high = 0U; + r.high = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 2U]; + r.high |= r_bit << i; + } + check(&a, &b, &r); + + r.high = 0U; + r.low = 0U; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + r_bit = truthtable[((a.high >> i) & 1U) * 3U]; + r.high |= r_bit << i; + r_bit = truthtable[((a.low >> i) & 1U) * 3U]; + r.low |= r_bit << i; + } + check(&a, &a, &r); + } + + return 0; +} + +#endif diff --git a/libj2_j2u_xor_j2u_to_j2u.c b/libj2_j2u_xor_j2u_to_j2u.c new file mode 100644 index 0000000..bfd0d8c --- /dev/null +++ b/libj2_j2u_xor_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_xor_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_xor_j2u.c */ + +#endif diff --git a/libj2_j2u_xor_ju.c b/libj2_j2u_xor_ju.c new file mode 100644 index 0000000..a4db682 --- /dev/null +++ b/libj2_j2u_xor_ju.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_xor_ju(struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_xor_j2u.c */ + +#endif diff --git a/libj2_j2u_xor_ju_to_j2u.c b/libj2_j2u_xor_ju_to_j2u.c new file mode 100644 index 0000000..6503634 --- /dev/null +++ b/libj2_j2u_xor_ju_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_xor_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_xor_j2u.c */ + +#endif diff --git a/libj2_j2u_zero.c b/libj2_j2u_zero.c new file mode 100644 index 0000000..ae8f904 --- /dev/null +++ b/libj2_j2u_zero.c @@ -0,0 +1,27 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_j2u_zero(struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u value = {1, 2}; + + libj2_j2u_zero(&value); + EXPECT(value.high == 0); + EXPECT(value.low == 0); + + libj2_j2u_zero(&value); + EXPECT(value.high == 0); + EXPECT(value.low == 0); + + return 0; +} + +#endif diff --git a/libj2_ju_add_j2u_to_j2u.c b/libj2_ju_add_j2u_to_j2u.c new file mode 100644 index 0000000..60fff73 --- /dev/null +++ b/libj2_ju_add_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_add_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_ju.c */ + +#endif diff --git a/libj2_ju_add_j2u_to_j2u_overflow.c b/libj2_ju_add_j2u_to_j2u_overflow.c new file mode 100644 index 0000000..d02dfee --- /dev/null +++ b/libj2_ju_add_j2u_to_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_add_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_ju.c */ + +#endif diff --git a/libj2_ju_add_ju_to_j2u.c b/libj2_ju_add_ju_to_j2u.c new file mode 100644 index 0000000..7622b84 --- /dev/null +++ b/libj2_ju_add_ju_to_j2u.c @@ -0,0 +1,95 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_add_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +static uintmax_t +random_ju(void) +{ + size_t n = LIBJ2_JU_BIT; + uintmax_t r = 0; + while (n--) + if (rand() < rand()) + r |= (uintmax_t)1 << n; + return r; +} + + +static void +self_check(uintmax_t a, uintmax_t b, uintmax_t r_high, uintmax_t r_low) +{ + uintmax_t carry = 0; + unsigned i; + + for (i = 0; i < LIBJ2_JU_BIT; i++) { + carry += (a >> i) & 1U; + carry += (b >> i) & 1U; + EXPECT((carry & 1U) == ((r_low >> i) & 1U)); + carry >>= 1; + } + + EXPECT(r_high == carry); +} + + +static void +check(uintmax_t a, uintmax_t b) +{ + struct libj2_j2u r; + uintmax_t expected_high = (uintmax_t)(a > UINTMAX_MAX - b); + uintmax_t expected_low = a + b; + + self_check(a, b, expected_high, expected_low); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_add_ju_to_j2u(a, b, &r); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); +} + + +static void +check_manual(uintmax_t a, uintmax_t b, uintmax_t expected_high, uintmax_t expected_low) +{ + struct libj2_j2u r; + + r = (struct libj2_j2u){111, 222}; + libj2_ju_add_ju_to_j2u(a, b, &r); + EXPECT(r.high == expected_high); + EXPECT(r.low == expected_low); + check(a, b); +} + + +int +main(void) +{ + unsigned i; + + srand((unsigned)time(NULL)); + + check_manual(0, 0, 0, 0); + check_manual(0, UINTMAX_MAX, 0, UINTMAX_MAX); + check_manual(UINTMAX_MAX, 0, 0, UINTMAX_MAX); + check_manual(UINTMAX_MAX, 1, 1, 0); + check_manual(1, UINTMAX_MAX, 1, 0); + check_manual(UINTMAX_MAX, UINTMAX_MAX, 1, UINTMAX_MAX - 1U); + + for (i = 0; i < 256; i++) { + check(0, random_ju()); + check(random_ju(), 0); + check(random_ju(), 1); + check(random_ju(), random_ju()); + check(random_ju(), UINTMAX_MAX); + check(UINTMAX_MAX, random_ju()); + } + + return 0; +} + +#endif diff --git a/libj2_ju_and_j2u_to_j2u.c b/libj2_ju_and_j2u_to_j2u.c new file mode 100644 index 0000000..623d558 --- /dev/null +++ b/libj2_ju_and_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_and_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_and_j2u.c */ + +#endif diff --git a/libj2_ju_cmp_j2u.c b/libj2_ju_cmp_j2u.c new file mode 100644 index 0000000..e97d9be --- /dev/null +++ b/libj2_ju_cmp_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_cmp_j2u(uintmax_t a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_ju_eq_j2u.c b/libj2_ju_eq_j2u.c new file mode 100644 index 0000000..c13e1b0 --- /dev/null +++ b/libj2_ju_eq_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_eq_j2u(uintmax_t a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_ju_ge_j2u.c b/libj2_ju_ge_j2u.c new file mode 100644 index 0000000..0787166 --- /dev/null +++ b/libj2_ju_ge_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_ge_j2u(uintmax_t a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_ju_gt_j2u.c b/libj2_ju_gt_j2u.c new file mode 100644 index 0000000..a7a4a2d --- /dev/null +++ b/libj2_ju_gt_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_gt_j2u(uintmax_t a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_ju_if_j2u_to_j2u.c b/libj2_ju_if_j2u_to_j2u.c new file mode 100644 index 0000000..1f035bf --- /dev/null +++ b/libj2_ju_if_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_if_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_if_j2u.c */ + +#endif diff --git a/libj2_ju_imply_j2u_to_j2u.c b/libj2_ju_imply_j2u_to_j2u.c new file mode 100644 index 0000000..f710250 --- /dev/null +++ b/libj2_ju_imply_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_imply_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_imply_j2u.c */ + +#endif diff --git a/libj2_ju_le_j2u.c b/libj2_ju_le_j2u.c new file mode 100644 index 0000000..0e428c2 --- /dev/null +++ b/libj2_ju_le_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_le_j2u(uintmax_t a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_ju_lrot_to_j2u.c b/libj2_ju_lrot_to_j2u.c new file mode 100644 index 0000000..25df836 --- /dev/null +++ b/libj2_ju_lrot_to_j2u.c @@ -0,0 +1,64 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_lrot_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +static void +set(struct libj2_j2u *a, const char *pattern, unsigned shift) +{ + unsigned i, j = (LIBJ2_J2U_BIT - (shift % LIBJ2_J2U_BIT)) % LIBJ2_J2U_BIT; + + a->high = 0; + a->low = 0; + + for (i = 0; i < LIBJ2_JU_BIT; i++, j++) + if (pattern[j % LIBJ2_J2U_BIT] == '1') + a->low |= (uintmax_t)1 << i; + + for (i = 0; i < LIBJ2_JU_BIT; i++, j++) + if (pattern[j % LIBJ2_J2U_BIT] == '1') + a->high |= (uintmax_t)1 << i; + +} + + +int +main(void) +{ + struct libj2_j2u a, r, expected; + char pattern[LIBJ2_J2U_BIT + 1U]; + unsigned i, j, k; + + srand((unsigned)time(NULL)); + + for (i = 0; i < 128U; i++) { + for (j = 0; j < LIBJ2_JU_BIT; j++) + pattern[j] = '0' + (rand() < rand()); + memset(&pattern[LIBJ2_JU_BIT], '0', LIBJ2_JU_BIT); + pattern[LIBJ2_J2U_BIT] = '\0'; + set(&a, pattern, 0); + EXPECT(a.high == 0); + for (j = 0; j <= 2U * LIBJ2_J2U_BIT; j++) { + set(&expected, pattern, j); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_lrot_to_j2u(a.low, j, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + k = 2U * LIBJ2_J2U_BIT - j; + + r = (struct libj2_j2u){111, 222}; + libj2_ju_rrot_to_j2u(a.low, k, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + } + } + + return 0; +} + +#endif diff --git a/libj2_ju_lsh_to_j2u.c b/libj2_ju_lsh_to_j2u.c new file mode 100644 index 0000000..82aa61f --- /dev/null +++ b/libj2_ju_lsh_to_j2u.c @@ -0,0 +1,171 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_lsh_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +static const char *patterns[] = { + "0", + "1111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111", + "1010101010101001010100100010101010101011000101101011101001000110", + "1110100100100010000010111111011101101001000010001000011110101010", + "11111111111100001001011", + "0010011011001", + "110010001011110100101001010011010111101", + NULL +}; + + +PURE static size_t +count_ones(const char *bits) +{ + size_t n = strlen(bits); + if (n > LIBJ2_J2U_BIT) + bits = &bits[n - LIBJ2_J2U_BIT]; + n = 0; + while (*bits) + if (*bits++ == '1') + n += 1U; + return n; +} + + +static int +set_j2u(struct libj2_j2u *a, const char *bits, size_t trailing_zeroes) +{ + size_t i, n; + char *all_bits, *p; + + n = LIBJ2_J2U_BIT + strlen(bits) + trailing_zeroes; + EXPECT((all_bits = malloc(n + 1U))); + memset(all_bits, '0', LIBJ2_J2U_BIT); + p = stpcpy(&all_bits[LIBJ2_J2U_BIT], bits); + memset(p, '0', trailing_zeroes); + p = &p[trailing_zeroes]; + + n = 0; + + a->low = 0; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + if (*--p == '1') { + a->low |= (uintmax_t)1 << i; + n += 1U; + } + } + + a->high = 0; + for (i = 0; i < LIBJ2_JU_BIT; i++) { + if (*--p == '1') { + a->high |= (uintmax_t)1 << i; + n += 1U; + } + } + + free(all_bits); + return n < count_ones(bits); +} + + +static int +set(struct libj2_j2u *a, const char *bits, size_t trailing_zeroes) +{ + size_t n = strlen(bits); + if (n > LIBJ2_JU_BIT) + bits = &bits[n - LIBJ2_JU_BIT]; + return set_j2u(a, bits, trailing_zeroes); +} + + +static void +self_check(void) +{ + struct libj2_j2u a = {111, 222}; + char pattern[LIBJ2_J2U_BIT + 1U]; + EXPECT(set(&a, "11", 8) == 0); + EXPECT(a.high == 0); + EXPECT(a.low == (3U << 8)); + EXPECT(set(&a, "1101", LIBJ2_JU_BIT) == 0); + EXPECT(a.high == 13U); + EXPECT(a.low == 0); + EXPECT(set(&a, "1", LIBJ2_JU_BIT - 1) == 0); + EXPECT(a.high == 0); + EXPECT(a.low == (UINTMAX_MAX ^ (UINTMAX_MAX >> 1))); + EXPECT(set(&a, "111", LIBJ2_JU_BIT - 2) == 0); + EXPECT(a.high == 1); + EXPECT(a.low == (UINTMAX_MAX ^ (UINTMAX_MAX >> 2))); + EXPECT(set(&a, "1", LIBJ2_J2U_BIT) == 1); + EXPECT(a.high == 0); + EXPECT(a.low == 0); + memset(pattern, '1', LIBJ2_J2U_BIT); + pattern[LIBJ2_J2U_BIT] = '\0'; + a = (struct libj2_j2u){111, 222}; + EXPECT(set(&a, pattern, 0) == 0); + EXPECT(a.high == 0); + EXPECT(a.low == UINTMAX_MAX); +} + + +static void +check(const char *pattern) +{ + struct libj2_j2u a, r, expected; + unsigned i; + int overflows; + + set(&a, pattern, 0); + EXPECT(a.high == 0); + for (i = 0; i < LIBJ2_J2U_BIT + 8U; i++) { + overflows = set(&expected, pattern, i); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_lsh_to_j2u(a.low, i, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = (struct libj2_j2u){111, 222}; + EXPECT(libj2_ju_lsh_to_j2u_overflow(a.low, i, &r) == overflows); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + } +} + + +int +main(void) +{ + size_t i, j; + char pattern[LIBJ2_JU_BIT + 1U]; + + self_check(); + srand((unsigned)time(NULL)); + + for (i = 0; patterns[i]; i++) + check(patterns[i]); + + for (i = 0; i < 64; i++) { + for (j = 0; j < LIBJ2_JU_BIT; j++) + pattern[j] = '0' + (rand() < rand()); + pattern[LIBJ2_JU_BIT] = '\0'; + check(pattern); + } + + return 0; +} + +#endif diff --git a/libj2_ju_lsh_to_j2u_overflow.c b/libj2_ju_lsh_to_j2u_overflow.c new file mode 100644 index 0000000..c67f0cf --- /dev/null +++ b/libj2_ju_lsh_to_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_lsh_to_j2u_overflow(uintmax_t a, unsigned b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_ju_lsh_to_j2u.c */ + +#endif diff --git a/libj2_ju_lt_j2u.c b/libj2_ju_lt_j2u.c new file mode 100644 index 0000000..b9d88e2 --- /dev/null +++ b/libj2_ju_lt_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_lt_j2u(uintmax_t a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_ju_mul_j2u_to_j2u.c b/libj2_ju_mul_j2u_to_j2u.c new file mode 100644 index 0000000..03c8a74 --- /dev/null +++ b/libj2_ju_mul_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_mul_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */ + +#endif diff --git a/libj2_ju_mul_j2u_to_j2u_overflow.c b/libj2_ju_mul_j2u_to_j2u_overflow.c new file mode 100644 index 0000000..876ec5b --- /dev/null +++ b/libj2_ju_mul_j2u_to_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_mul_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */ + +#endif diff --git a/libj2_ju_mul_ju_to_j2u.c b/libj2_ju_mul_ju_to_j2u.c new file mode 100644 index 0000000..11daad4 --- /dev/null +++ b/libj2_ju_mul_ju_to_j2u.c @@ -0,0 +1,149 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_mul_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +static uintmax_t +random_small_ju(size_t bits) +{ + uintmax_t r = 0; + while (bits--) + if (rand() < rand()) + r |= (uintmax_t)1 << bits; + return r; +} + +static uintmax_t +random_hju(void) +{ + return random_small_ju(LIBJ2_JU_BIT / 2U); +} + +static uintmax_t +random_ju(void) +{ + return random_small_ju(LIBJ2_JU_BIT); +} + + +static void +mul(uintmax_t a, uintmax_t b, struct libj2_j2u *expected) +{ + struct libj2_j2u c; + unsigned i; + + libj2_j2u_zero(expected); + for (i = 0; i < LIBJ2_JU_BIT; i++, b >>= 1) { + if (b & 1U) { + libj2_ju_lsh_to_j2u(a, i, &c); + libj2_j2u_add_j2u(expected, &c); + } + } +} + + +int +main(void) +{ + struct libj2_j2u r, expected; + uintmax_t u, v; + unsigned i; + + srand((unsigned)time(NULL)); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_mul_ju_to_j2u(0, 0, &r); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_mul_ju_to_j2u(0, 1, &r); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_mul_ju_to_j2u(0, UINTMAX_MAX, &r); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_mul_ju_to_j2u(1, 0, &r); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_mul_ju_to_j2u(UINTMAX_MAX, 0, &r); + EXPECT(libj2_j2u_is_zero(&r)); + + for (i = 0; i < 32; i++) { + r = (struct libj2_j2u){111, 222}; + libj2_ju_mul_ju_to_j2u(0, random_ju(), &r); + EXPECT(libj2_j2u_is_zero(&r)); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_mul_ju_to_j2u(random_ju(), 0, &r); + EXPECT(libj2_j2u_is_zero(&r)); + } + + r = (struct libj2_j2u){111, 222}; + libj2_ju_mul_ju_to_j2u(1, 1, &r); + EXPECT(r.high == 0); + EXPECT(r.low == 1); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_mul_ju_to_j2u(4, 4, &r); + EXPECT(r.high == 0); + EXPECT(r.low == 16); + + for (i = 0; i < 32; i++) { + r = (struct libj2_j2u){111, 222}; + v = random_ju(); + libj2_ju_mul_ju_to_j2u(1, v, &r); + EXPECT(r.high == 0); + EXPECT(r.low == v); + + r = (struct libj2_j2u){111, 222}; + v = random_ju(); + libj2_ju_mul_ju_to_j2u(v, 1, &r); + EXPECT(r.high == 0); + EXPECT(r.low == v); + } + + for (i = 0; i < 32; i++) { + u = random_hju(); + v = random_hju(); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_mul_ju_to_j2u(u, v, &r); + EXPECT(r.high == 0); + EXPECT(r.low == u * v); + + libj2_ju_mul_ju_to_j2u(v, u, &r); + EXPECT(r.high == 0); + EXPECT(r.low == u * v); + } + + r = (struct libj2_j2u){111, 222}; + libj2_ju_mul_ju_to_j2u(UINTMAX_MAX, UINTMAX_MAX, &r); + EXPECT(r.high == UINTMAX_MAX - 1U); + EXPECT(r.low == 1); + + for (i = 0; i < 256; i++) { + u = random_ju(); + v = random_ju(); + + mul(u, v, &expected); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_mul_ju_to_j2u(u, v, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + libj2_ju_mul_ju_to_j2u(v, u, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + } + + return 0; +} + +#endif diff --git a/libj2_ju_nand_j2u_to_j2u.c b/libj2_ju_nand_j2u_to_j2u.c new file mode 100644 index 0000000..d26055a --- /dev/null +++ b/libj2_ju_nand_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_nand_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nand_j2u.c */ + +#endif diff --git a/libj2_ju_ne_j2u.c b/libj2_ju_ne_j2u.c new file mode 100644 index 0000000..556d553 --- /dev/null +++ b/libj2_ju_ne_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_ne_j2u(uintmax_t a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_cmp_ju.c */ + +#endif diff --git a/libj2_ju_nif_j2u_to_j2u.c b/libj2_ju_nif_j2u_to_j2u.c new file mode 100644 index 0000000..eb9a17d --- /dev/null +++ b/libj2_ju_nif_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_nif_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nif_j2u.c */ + +#endif diff --git a/libj2_ju_nimply_j2u_to_j2u.c b/libj2_ju_nimply_j2u_to_j2u.c new file mode 100644 index 0000000..42bc22f --- /dev/null +++ b/libj2_ju_nimply_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_nimply_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nimply_j2u.c */ + +#endif diff --git a/libj2_ju_nor_j2u_to_j2u.c b/libj2_ju_nor_j2u_to_j2u.c new file mode 100644 index 0000000..01aec4c --- /dev/null +++ b/libj2_ju_nor_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_nor_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_nor_j2u.c */ + +#endif diff --git a/libj2_ju_or_j2u_to_j2u.c b/libj2_ju_or_j2u_to_j2u.c new file mode 100644 index 0000000..85e9c70 --- /dev/null +++ b/libj2_ju_or_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_or_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_or_j2u.c */ + +#endif diff --git a/libj2_ju_rrot_to_j2u.c b/libj2_ju_rrot_to_j2u.c new file mode 100644 index 0000000..a1051ab --- /dev/null +++ b/libj2_ju_rrot_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_rrot_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_ju_lrot_to_j2u.c */ + +#endif diff --git a/libj2_ju_rsh_to_j2u.c b/libj2_ju_rsh_to_j2u.c new file mode 100644 index 0000000..7c5913f --- /dev/null +++ b/libj2_ju_rsh_to_j2u.c @@ -0,0 +1,121 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_rsh_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +static const char *patterns[] = { + "0", + "1111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111", + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111", + "1010101010101001010100100010101010101011000101101011101001000110", + "1110100100100010000010111111011101101001000010001000011110101010", + "11111111111100001001011", + "0010011011001", + "110010001011110100101001010011010111101", + NULL +}; + + +static int +set_j2u(struct libj2_j2u *a, const char *bits, size_t leading_zeroes) +{ + size_t i, n; + int underflow = 0; + + a->high = 0; + a->low = 0; + + n = strlen(bits); + if (n > LIBJ2_J2U_BIT) { + bits = &bits[n - LIBJ2_J2U_BIT]; + n = LIBJ2_J2U_BIT; + } + + while (n && leading_zeroes--) + underflow |= bits[--n] == '1'; + + for (i = 0; n && i < LIBJ2_JU_BIT; i++) + if (bits[--n] == '1') + a->low |= (uintmax_t)1 << i; + + for (i = 0; n && i < LIBJ2_JU_BIT; i++) + if (bits[--n] == '1') + a->high |= (uintmax_t)1 << i; + + return underflow; +} + + +static int +set(struct libj2_j2u *a, const char *bits, size_t leading_zeroes) +{ + size_t n = strlen(bits); + if (n > LIBJ2_JU_BIT) + bits = &bits[n - LIBJ2_JU_BIT]; + return set_j2u(a, bits, leading_zeroes); +} + + +static void +check(const char *pattern) +{ + struct libj2_j2u a, r, expected; + unsigned i; + int underflows; + + set(&a, pattern, 0); + EXPECT(a.high == 0); + for (i = 0; i < LIBJ2_J2U_BIT + 8U; i++) { + underflows = set(&expected, pattern, i); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_rsh_to_j2u(a.low, i, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = (struct libj2_j2u){111, 222}; + EXPECT(libj2_ju_rsh_to_j2u_underflow(a.low, i, &r) == underflows); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + } +} + + +int +main(void) +{ + size_t i, j; + char pattern[LIBJ2_J2U_BIT + 1U]; + + srand((unsigned)time(NULL)); + + for (i = 0; patterns[i]; i++) + check(patterns[i]); + + for (i = 0; i < 64; i++) { + for (j = 0; j < LIBJ2_J2U_BIT; j++) + pattern[j] = '0' + (rand() < rand()); + pattern[LIBJ2_J2U_BIT] = '\0'; + check(pattern); + } + + return 0; +} + +#endif diff --git a/libj2_ju_rsh_to_j2u_underflow.c b/libj2_ju_rsh_to_j2u_underflow.c new file mode 100644 index 0000000..89969da --- /dev/null +++ b/libj2_ju_rsh_to_j2u_underflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_rsh_to_j2u_underflow(uintmax_t a, unsigned b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_ju_rsh_to_j2u.c */ + +#endif diff --git a/libj2_ju_sub_j2u_to_j2u.c b/libj2_ju_sub_j2u_to_j2u.c new file mode 100644 index 0000000..6e85181 --- /dev/null +++ b/libj2_ju_sub_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_sub_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */ + +#endif diff --git a/libj2_ju_sub_j2u_to_j2u_overflow.c b/libj2_ju_sub_j2u_to_j2u_overflow.c new file mode 100644 index 0000000..5fef105 --- /dev/null +++ b/libj2_ju_sub_j2u_to_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_sub_j2u_to_j2u_overflow(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */ + +#endif diff --git a/libj2_ju_sub_ju_to_j2u.c b/libj2_ju_sub_ju_to_j2u.c new file mode 100644 index 0000000..b61e96a --- /dev/null +++ b/libj2_ju_sub_ju_to_j2u.c @@ -0,0 +1,64 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_sub_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +static uintmax_t +random_ju(void) +{ + size_t n = LIBJ2_JU_BIT; + uintmax_t r = 0; + while (n--) + if (rand() < rand()) + r |= (uintmax_t)1 << n; + return r; +} + + +static void +check(uintmax_t a, uintmax_t b) +{ + struct libj2_j2u r, expected; + int expected_overflow; + + libj2_ju_to_j2u(a, &expected); + expected_overflow = libj2_j2u_sub_ju_overflow(&expected, b); + + r = (struct libj2_j2u){111, 222}; + libj2_ju_sub_ju_to_j2u(a, b, &r); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + r = (struct libj2_j2u){111, 222}; + EXPECT(libj2_ju_sub_ju_to_j2u_overflow(a, b, &r) == expected_overflow); + EXPECT(libj2_j2u_eq_j2u(&r, &expected)); +} + + +int +main(void) +{ + unsigned i; + + srand((unsigned)time(NULL)); + + check(0, 0); + check(0, UINTMAX_MAX); + check(UINTMAX_MAX, 0); + check(UINTMAX_MAX, UINTMAX_MAX); + for (i = 0; i < 256; i++) { + check(0, random_ju()); + check(UINTMAX_MAX, random_ju()); + check(random_ju(), 0); + check(random_ju(), random_ju()); + check(random_ju(), UINTMAX_MAX); + } + + return 0; +} + +#endif diff --git a/libj2_ju_sub_ju_to_j2u_overflow.c b/libj2_ju_sub_ju_to_j2u_overflow.c new file mode 100644 index 0000000..cd3c67b --- /dev/null +++ b/libj2_ju_sub_ju_to_j2u_overflow.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_sub_ju_to_j2u_overflow(uintmax_t a, uintmax_t b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_ju_sub_ju_to_j2u.c */ + +#endif diff --git a/libj2_ju_to_j2u.c b/libj2_ju_to_j2u.c new file mode 100644 index 0000000..ce3ccb6 --- /dev/null +++ b/libj2_ju_to_j2u.c @@ -0,0 +1,29 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_to_j2u(uintmax_t a, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u value; + + value = (struct libj2_j2u){1, 2}; + libj2_ju_to_j2u(5, &value); + EXPECT(value.high == 0); + EXPECT(value.low == 5); + + value = (struct libj2_j2u){1, 2}; + libj2_ju_to_j2u(10, &value); + EXPECT(value.high == 0); + EXPECT(value.low == 10); + + return 0; +} + +#endif diff --git a/libj2_ju_xnor_j2u_to_j2u.c b/libj2_ju_xnor_j2u_to_j2u.c new file mode 100644 index 0000000..5611187 --- /dev/null +++ b/libj2_ju_xnor_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_xnor_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_xnor_j2u.c */ + +#endif diff --git a/libj2_ju_xor_j2u_to_j2u.c b/libj2_ju_xor_j2u_to_j2u.c new file mode 100644 index 0000000..62e6b40 --- /dev/null +++ b/libj2_ju_xor_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_ju_xor_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_xor_j2u.c */ + +#endif diff --git a/libj2_max_j2u.c b/libj2_max_j2u.c new file mode 100644 index 0000000..edef85c --- /dev/null +++ b/libj2_max_j2u.c @@ -0,0 +1,177 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_max_j2u(struct libj2_j2u *a, ... /*, NULL */); +/* TODO Add man page */ + + +#else + +static struct libj2_j2u v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13; + +static void +reset(void) +{ + const uintmax_t max = UINTMAX_MAX; + v1 = (struct libj2_j2u){0, 0}; + v2 = (struct libj2_j2u){0, 1}; + v3 = (struct libj2_j2u){0, 2}; + v4 = (struct libj2_j2u){0, max - 1}; + v5 = (struct libj2_j2u){1, 0}; + v6 = (struct libj2_j2u){1, 1}; + v7 = (struct libj2_j2u){max - 1, 0}; + v8 = (struct libj2_j2u){max - 1, 1}; + v9 = (struct libj2_j2u){max - 1, max}; + v10 = (struct libj2_j2u){max, 0}; + v11 = (struct libj2_j2u){max, 1}; + v12 = (struct libj2_j2u){max, max - 1}; + v13 = (struct libj2_j2u){max, max}; +} + +static void +expect_untouched(void) +{ + const uintmax_t max = UINTMAX_MAX; + EXPECT(libj2_j2u_eq_j2u(&v1, &(struct libj2_j2u){0, 0}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v2, &(struct libj2_j2u){0, 1}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v3, &(struct libj2_j2u){0, 2}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v4, &(struct libj2_j2u){0, max - 1}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v5, &(struct libj2_j2u){1, 0}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v6, &(struct libj2_j2u){1, 1}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v7, &(struct libj2_j2u){max - 1, 0}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v8, &(struct libj2_j2u){max - 1, 1}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v9, &(struct libj2_j2u){max - 1, max}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v10, &(struct libj2_j2u){max, 0}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v11, &(struct libj2_j2u){max, 1}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v12, &(struct libj2_j2u){max, max - 1}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v13, &(struct libj2_j2u){max, max}) == 1); +} + +#define HEAD(X, ...) X +#define TAIL(X, ...) __VA_ARGS__ + +#define CHECK(MAX, ...)\ + do {\ + reset();\ + \ + r = *(HEAD(__VA_ARGS__));\ + libj2_max_j2u(&r, TAIL(__VA_ARGS__));\ + expect_untouched();\ + EXPECT(libj2_j2u_eq_j2u(&(MAX), &r));\ + \ + p = libj2_max_j2u_return(__VA_ARGS__);\ + expect_untouched();\ + EXPECT(p != NULL);\ + EXPECT(libj2_j2u_eq_j2u(&(MAX), p));\ + \ + r = (struct libj2_j2u){111, 222};\ + libj2_max_j2u_to_j2u(__VA_ARGS__, &r);\ + expect_untouched();\ + EXPECT(libj2_j2u_eq_j2u(&(MAX), &r));\ + } while (0) + +int +main(void) +{ + struct libj2_j2u r; + const struct libj2_j2u *p; + + CHECK(v1, &v1, NULL); + CHECK(v2, &v2, NULL); + CHECK(v3, &v3, NULL); + + CHECK(v2, &v1, &v2, NULL); + CHECK(v2, &v2, &v1, NULL); + CHECK(v3, &v2, &v3, NULL); + CHECK(v3, &v3, &v2, NULL); + CHECK(v4, &v3, &v4, NULL); + CHECK(v4, &v4, &v3, NULL); + CHECK(v5, &v4, &v5, NULL); + CHECK(v5, &v5, &v4, NULL); + CHECK(v6, &v5, &v6, NULL); + CHECK(v6, &v6, &v5, NULL); + CHECK(v7, &v6, &v7, NULL); + CHECK(v7, &v7, &v6, NULL); + CHECK(v8, &v7, &v8, NULL); + CHECK(v8, &v8, &v7, NULL); + CHECK(v9, &v8, &v9, NULL); + CHECK(v9, &v9, &v8, NULL); + CHECK(v10, &v9, &v10, NULL); + CHECK(v10, &v10, &v9, NULL); + CHECK(v11, &v10, &v11, NULL); + CHECK(v11, &v11, &v10, NULL); + CHECK(v12, &v11, &v12, NULL); + CHECK(v12, &v12, &v11, NULL); + CHECK(v13, &v12, &v13, NULL); + CHECK(v13, &v13, &v12, NULL); + + CHECK(v6, &v1, &v2, &v3, &v4, &v5, &v6, NULL); + CHECK(v6, &v1, &v2, &v3, &v4, &v6, &v5, NULL); + CHECK(v6, &v1, &v2, &v3, &v6, &v4, &v5, NULL); + CHECK(v6, &v1, &v2, &v6, &v3, &v4, &v5, NULL); + CHECK(v6, &v1, &v6, &v2, &v3, &v4, &v5, NULL); + CHECK(v6, &v6, &v1, &v2, &v3, &v4, &v5, NULL); + + CHECK(v6, &v6, &v5, &v4, &v3, &v2, &v1, NULL); + CHECK(v6, &v5, &v6, &v4, &v3, &v2, &v1, NULL); + CHECK(v6, &v5, &v4, &v6, &v3, &v2, &v1, NULL); + CHECK(v6, &v5, &v4, &v3, &v6, &v2, &v1, NULL); + CHECK(v6, &v5, &v4, &v3, &v2, &v6, &v1, NULL); + CHECK(v6, &v5, &v4, &v3, &v2, &v1, &v6, NULL); + + CHECK(v13, &v1, &v6, &v9, &v11, &v12, &v4, &v8, &v2, &v3, &v10, &v7, &v5, &v13, NULL); + CHECK(v13, &v12, &v2, &v11, &v13, &v7, &v4, &v9, &v10, &v1, &v6, &v3, &v8, &v5, NULL); + CHECK(v13, &v5, &v13, &v6, &v12, &v8, &v10, &v3, &v9, &v7, &v2, &v11, &v1, &v4, NULL); + CHECK(v13, &v4, &v13, &v10, &v11, &v5, &v12, &v9, &v3, &v7, &v6, &v1, &v8, &v2, NULL); + CHECK(v13, &v5, &v7, &v6, &v3, &v2, &v1, &v11, &v12, &v8, &v4, &v9, &v13, &v10, NULL); + CHECK(v13, &v3, &v8, &v7, &v10, &v1, &v11, &v13, &v12, &v5, &v4, &v2, &v6, &v9, NULL); + CHECK(v13, &v11, &v2, &v8, &v3, &v5, &v12, &v4, &v13, &v1, &v10, &v7, &v6, &v9, NULL); + CHECK(v13, &v8, &v6, &v2, &v10, &v9, &v13, &v12, &v4, &v7, &v1, &v11, &v5, &v3, NULL); + CHECK(v13, &v4, &v8, &v7, &v12, &v13, &v1, &v6, &v11, &v2, &v3, &v10, &v9, &v5, NULL); + CHECK(v13, &v13, &v11, &v1, &v4, &v8, &v10, &v12, &v5, &v3, &v2, &v9, &v7, &v6, NULL); + CHECK(v13, &v13, &v3, &v12, &v8, &v10, &v11, &v7, &v2, &v4, &v1, &v9, &v6, &v5, NULL); + CHECK(v13, &v9, &v8, &v13, &v7, &v1, &v5, &v6, &v11, &v12, &v4, &v3, &v2, &v10, NULL); + CHECK(v13, &v9, &v8, &v10, &v6, &v3, &v1, &v12, &v2, &v5, &v11, &v4, &v7, &v13, NULL); + CHECK(v13, &v5, &v4, &v12, &v13, &v8, &v7, &v9, &v1, &v6, &v10, &v3, &v2, &v11, NULL); + CHECK(v13, &v5, &v4, &v11, &v9, &v8, &v7, &v10, &v6, &v2, &v3, &v1, &v13, &v12, NULL); + CHECK(v13, &v12, &v1, &v13, &v10, &v7, &v6, &v5, &v2, &v11, &v4, &v3, &v8, &v9, NULL); + CHECK(v13, &v2, &v1, &v8, &v7, &v13, &v5, &v9, &v10, &v6, &v3, &v11, &v12, &v4, NULL); + CHECK(v13, &v3, &v7, &v13, &v9, &v6, &v8, &v5, &v12, &v4, &v11, &v2, &v10, &v1, NULL); + CHECK(v13, &v12, &v3, &v6, &v5, &v2, &v9, &v4, &v11, &v8, &v10, &v13, &v1, &v7, NULL); + CHECK(v13, &v1, &v13, &v7, &v4, &v3, &v12, &v2, &v9, &v5, &v10, &v11, &v6, &v8, NULL); + CHECK(v13, &v7, &v3, &v8, &v1, &v2, &v4, &v13, &v5, &v6, &v10, &v9, &v11, &v12, NULL); + CHECK(v13, &v2, &v3, &v13, &v8, &v12, &v5, &v11, &v1, &v9, &v10, &v4, &v7, &v6, NULL); + CHECK(v13, &v10, &v6, &v7, &v5, &v11, &v9, &v1, &v3, &v13, &v4, &v2, &v8, &v12, NULL); + CHECK(v13, &v6, &v9, &v12, &v7, &v2, &v1, &v10, &v4, &v13, &v11, &v3, &v5, &v8, NULL); + CHECK(v13, &v5, &v1, &v9, &v6, &v4, &v8, &v7, &v11, &v13, &v3, &v2, &v12, &v10, NULL); + CHECK(v13, &v1, &v10, &v11, &v2, &v9, &v12, &v7, &v5, &v3, &v8, &v13, &v6, &v4, NULL); + CHECK(v13, &v3, &v10, &v2, &v4, &v8, &v9, &v11, &v7, &v5, &v1, &v13, &v6, &v12, NULL); + CHECK(v13, &v8, &v10, &v11, &v6, &v5, &v2, &v9, &v4, &v3, &v13, &v7, &v12, &v1, NULL); + CHECK(v13, &v4, &v12, &v11, &v7, &v3, &v13, &v10, &v2, &v5, &v9, &v1, &v6, &v8, NULL); + CHECK(v13, &v7, &v13, &v12, &v3, &v4, &v8, &v11, &v9, &v1, &v10, &v6, &v2, &v5, NULL); + CHECK(v13, &v5, &v4, &v2, &v1, &v8, &v7, &v13, &v10, &v11, &v3, &v9, &v6, &v12, NULL); + CHECK(v13, &v7, &v8, &v10, &v2, &v4, &v1, &v11, &v9, &v12, &v6, &v13, &v5, &v3, NULL); + CHECK(v13, &v3, &v7, &v2, &v13, &v5, &v10, &v12, &v6, &v8, &v1, &v11, &v9, &v4, NULL); + CHECK(v13, &v12, &v13, &v6, &v9, &v4, &v11, &v8, &v3, &v2, &v1, &v7, &v10, &v5, NULL); + CHECK(v13, &v2, &v9, &v10, &v13, &v1, &v3, &v5, &v8, &v7, &v6, &v11, &v4, &v12, NULL); + CHECK(v13, &v7, &v5, &v10, &v11, &v3, &v12, &v4, &v9, &v6, &v13, &v1, &v2, &v8, NULL); + CHECK(v13, &v1, &v3, &v4, &v8, &v2, &v13, &v11, &v7, &v10, &v5, &v6, &v12, &v9, NULL); + CHECK(v13, &v7, &v2, &v1, &v13, &v5, &v10, &v3, &v9, &v6, &v4, &v11, &v8, &v12, NULL); + CHECK(v13, &v6, &v5, &v3, &v11, &v8, &v9, &v1, &v12, &v7, &v13, &v4, &v10, &v2, NULL); + CHECK(v13, &v13, &v6, &v5, &v4, &v3, &v8, &v1, &v2, &v7, &v9, &v10, &v11, &v12, NULL); + CHECK(v13, &v13, &v12, &v4, &v3, &v11, &v6, &v1, &v7, &v10, &v2, &v5, &v9, &v8, NULL); + CHECK(v13, &v13, &v6, &v7, &v2, &v8, &v4, &v1, &v5, &v12, &v11, &v3, &v10, &v9, NULL); + CHECK(v13, &v13, &v5, &v12, &v11, &v10, &v9, &v2, &v6, &v4, &v8, &v3, &v1, &v7, NULL); + CHECK(v13, &v1, &v8, &v7, &v6, &v13, &v9, &v3, &v11, &v10, &v4, &v2, &v12, &v5, NULL); + CHECK(v13, &v8, &v9, &v3, &v7, &v1, &v11, &v2, &v13, &v4, &v6, &v12, &v10, &v5, NULL); + CHECK(v13, &v4, &v5, &v13, &v2, &v7, &v8, &v9, &v10, &v11, &v1, &v3, &v6, &v12, NULL); + CHECK(v13, &v7, &v4, &v11, &v9, &v6, &v12, &v3, &v5, &v10, &v8, &v1, &v2, &v13, NULL); + CHECK(v13, &v8, &v9, &v6, &v2, &v11, &v5, &v13, &v1, &v3, &v7, &v10, &v12, &v4, NULL); + CHECK(v13, &v10, &v4, &v5, &v6, &v3, &v7, &v13, &v8, &v12, &v2, &v9, &v1, &v11, NULL); + CHECK(v13, &v9, &v1, &v3, &v8, &v12, &v5, &v6, &v2, &v10, &v11, &v4, &v7, &v13, NULL); + + return 0; +} + +#endif diff --git a/libj2_max_j2u_return.c b/libj2_max_j2u_return.c new file mode 100644 index 0000000..8887178 --- /dev/null +++ b/libj2_max_j2u_return.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline const struct libj2_j2u *libj2_max_j2u_return(const struct libj2_j2u *a, ... /*, NULL */); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_max_j2u.c */ + +#endif diff --git a/libj2_max_j2u_to_j2u.c b/libj2_max_j2u_to_j2u.c new file mode 100644 index 0000000..2b82706 --- /dev/null +++ b/libj2_max_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_max_j2u_to_j2u(const struct libj2_j2u *a, ... /*, NULL, struct libj2_j2u *res */); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_max_j2u.c */ + +#endif diff --git a/libj2_min_j2u.c b/libj2_min_j2u.c new file mode 100644 index 0000000..729bbfd --- /dev/null +++ b/libj2_min_j2u.c @@ -0,0 +1,189 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_min_j2u(struct libj2_j2u *a, ... /*, NULL */); +/* TODO Add man page */ + + +#else + +static struct libj2_j2u v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13; + +static void +reset(void) +{ + const uintmax_t max = UINTMAX_MAX; + v1 = (struct libj2_j2u){0, 0}; + v2 = (struct libj2_j2u){0, 1}; + v3 = (struct libj2_j2u){0, 2}; + v4 = (struct libj2_j2u){0, max - 1}; + v5 = (struct libj2_j2u){1, 0}; + v6 = (struct libj2_j2u){1, 1}; + v7 = (struct libj2_j2u){max - 1, 0}; + v8 = (struct libj2_j2u){max - 1, 1}; + v9 = (struct libj2_j2u){max - 1, max}; + v10 = (struct libj2_j2u){max, 0}; + v11 = (struct libj2_j2u){max, 1}; + v12 = (struct libj2_j2u){max, max - 1}; + v13 = (struct libj2_j2u){max, max}; +} + +static void +expect_untouched(void) +{ + const uintmax_t max = UINTMAX_MAX; + EXPECT(libj2_j2u_eq_j2u(&v1, &(struct libj2_j2u){0, 0}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v2, &(struct libj2_j2u){0, 1}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v3, &(struct libj2_j2u){0, 2}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v4, &(struct libj2_j2u){0, max - 1}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v5, &(struct libj2_j2u){1, 0}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v6, &(struct libj2_j2u){1, 1}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v7, &(struct libj2_j2u){max - 1, 0}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v8, &(struct libj2_j2u){max - 1, 1}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v9, &(struct libj2_j2u){max - 1, max}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v10, &(struct libj2_j2u){max, 0}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v11, &(struct libj2_j2u){max, 1}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v12, &(struct libj2_j2u){max, max - 1}) == 1); + EXPECT(libj2_j2u_eq_j2u(&v13, &(struct libj2_j2u){max, max}) == 1); +} + +#define HEAD(X, ...) X +#define TAIL(X, ...) __VA_ARGS__ + +#define CHECK(MIN, ...)\ + do {\ + reset();\ + \ + r = *(HEAD(__VA_ARGS__));\ + libj2_min_j2u(&r, TAIL(__VA_ARGS__));\ + expect_untouched();\ + EXPECT(libj2_j2u_eq_j2u(&(MIN), &r));\ + \ + p = libj2_min_j2u_return(__VA_ARGS__);\ + expect_untouched();\ + EXPECT(p != NULL);\ + EXPECT(libj2_j2u_eq_j2u(&(MIN), p));\ + \ + r = (struct libj2_j2u){111, 222};\ + libj2_min_j2u_to_j2u(__VA_ARGS__, &r);\ + expect_untouched();\ + EXPECT(libj2_j2u_eq_j2u(&(MIN), &r));\ + } while (0) + +int +main(void) +{ + struct libj2_j2u r; + const struct libj2_j2u *p; + + CHECK(v1, &v1, NULL); + CHECK(v2, &v2, NULL); + CHECK(v3, &v3, NULL); + + CHECK(v1, &v1, &v2, NULL); + CHECK(v1, &v2, &v1, NULL); + CHECK(v2, &v2, &v3, NULL); + CHECK(v2, &v3, &v2, NULL); + CHECK(v3, &v3, &v4, NULL); + CHECK(v3, &v4, &v3, NULL); + CHECK(v4, &v4, &v5, NULL); + CHECK(v4, &v5, &v4, NULL); + CHECK(v5, &v5, &v6, NULL); + CHECK(v5, &v6, &v5, NULL); + CHECK(v6, &v6, &v7, NULL); + CHECK(v6, &v7, &v6, NULL); + CHECK(v7, &v7, &v8, NULL); + CHECK(v7, &v8, &v7, NULL); + CHECK(v8, &v8, &v9, NULL); + CHECK(v8, &v9, &v8, NULL); + CHECK(v9, &v9, &v10, NULL); + CHECK(v9, &v10, &v9, NULL); + CHECK(v10, &v10, &v11, NULL); + CHECK(v10, &v11, &v10, NULL); + CHECK(v11, &v11, &v12, NULL); + CHECK(v11, &v12, &v11, NULL); + CHECK(v12, &v12, &v13, NULL); + CHECK(v12, &v13, &v12, NULL); + + CHECK(v1, &v1, &v2, &v3, &v4, &v5, &v6, NULL); + CHECK(v1, &v2, &v1, &v3, &v4, &v5, &v6, NULL); + CHECK(v1, &v2, &v3, &v1, &v4, &v5, &v6, NULL); + CHECK(v1, &v2, &v3, &v4, &v1, &v5, &v6, NULL); + CHECK(v1, &v2, &v3, &v4, &v5, &v1, &v6, NULL); + CHECK(v1, &v2, &v3, &v4, &v5, &v6, &v1, NULL); + + CHECK(v1, &v6, &v5, &v4, &v3, &v2, &v1, NULL); + CHECK(v1, &v6, &v5, &v4, &v3, &v1, &v2, NULL); + CHECK(v1, &v6, &v5, &v4, &v1, &v3, &v2, NULL); + CHECK(v1, &v6, &v5, &v1, &v4, &v3, &v2, NULL); + CHECK(v1, &v6, &v1, &v5, &v4, &v3, &v2, NULL); + CHECK(v1, &v1, &v6, &v5, &v4, &v3, &v2, NULL); + + CHECK(v2, &v2, &v3, &v4, &v5, &v6, NULL); + CHECK(v2, &v3, &v2, &v4, &v5, &v6, NULL); + CHECK(v2, &v3, &v4, &v2, &v5, &v6, NULL); + CHECK(v2, &v3, &v4, &v5, &v2, &v6, NULL); + CHECK(v2, &v3, &v4, &v5, &v6, &v2, NULL); + + CHECK(v2, &v6, &v5, &v4, &v3, &v2, NULL); + CHECK(v2, &v6, &v5, &v4, &v2, &v3, NULL); + CHECK(v2, &v6, &v5, &v2, &v4, &v3, NULL); + CHECK(v2, &v6, &v2, &v5, &v4, &v3, NULL); + CHECK(v2, &v2, &v6, &v5, &v4, &v3, NULL); + + CHECK(v2, &v6, &v9, &v11, &v12, &v4, &v8, &v2, &v3, &v10, &v7, &v5, &v13, NULL); + CHECK(v2, &v12, &v2, &v11, &v13, &v7, &v4, &v9, &v10, &v6, &v3, &v8, &v5, NULL); + CHECK(v2, &v5, &v13, &v6, &v12, &v8, &v10, &v3, &v9, &v7, &v2, &v11, &v4, NULL); + CHECK(v2, &v4, &v13, &v10, &v11, &v5, &v12, &v9, &v3, &v7, &v6, &v8, &v2, NULL); + CHECK(v2, &v5, &v7, &v6, &v3, &v2, &v11, &v12, &v8, &v4, &v9, &v13, &v10, NULL); + CHECK(v2, &v3, &v8, &v7, &v10, &v11, &v13, &v12, &v5, &v4, &v2, &v6, &v9, NULL); + CHECK(v2, &v11, &v2, &v8, &v3, &v5, &v12, &v4, &v13, &v10, &v7, &v6, &v9, NULL); + CHECK(v2, &v8, &v6, &v2, &v10, &v9, &v13, &v12, &v4, &v7, &v11, &v5, &v3, NULL); + CHECK(v2, &v4, &v8, &v7, &v12, &v13, &v6, &v11, &v2, &v3, &v10, &v9, &v5, NULL); + CHECK(v2, &v13, &v11, &v4, &v8, &v10, &v12, &v5, &v3, &v2, &v9, &v7, &v6, NULL); + CHECK(v2, &v13, &v3, &v12, &v8, &v10, &v11, &v7, &v2, &v4, &v9, &v6, &v5, NULL); + CHECK(v2, &v9, &v8, &v13, &v7, &v5, &v6, &v11, &v12, &v4, &v3, &v2, &v10, NULL); + CHECK(v2, &v9, &v8, &v10, &v6, &v3, &v12, &v2, &v5, &v11, &v4, &v7, &v13, NULL); + CHECK(v2, &v5, &v4, &v12, &v13, &v8, &v7, &v9, &v6, &v10, &v3, &v2, &v11, NULL); + CHECK(v2, &v5, &v4, &v11, &v9, &v8, &v7, &v10, &v6, &v2, &v3, &v13, &v12, NULL); + CHECK(v2, &v12, &v13, &v10, &v7, &v6, &v5, &v2, &v11, &v4, &v3, &v8, &v9, NULL); + CHECK(v2, &v2, &v8, &v7, &v13, &v5, &v9, &v10, &v6, &v3, &v11, &v12, &v4, NULL); + CHECK(v2, &v3, &v7, &v13, &v9, &v6, &v8, &v5, &v12, &v4, &v11, &v2, &v10, NULL); + CHECK(v2, &v12, &v3, &v6, &v5, &v2, &v9, &v4, &v11, &v8, &v10, &v13, &v7, NULL); + CHECK(v2, &v13, &v7, &v4, &v3, &v12, &v2, &v9, &v5, &v10, &v11, &v6, &v8, NULL); + CHECK(v2, &v7, &v3, &v8, &v2, &v4, &v13, &v5, &v6, &v10, &v9, &v11, &v12, NULL); + CHECK(v2, &v2, &v3, &v13, &v8, &v12, &v5, &v11, &v9, &v10, &v4, &v7, &v6, NULL); + CHECK(v2, &v10, &v6, &v7, &v5, &v11, &v9, &v3, &v13, &v4, &v2, &v8, &v12, NULL); + CHECK(v2, &v6, &v9, &v12, &v7, &v2, &v10, &v4, &v13, &v11, &v3, &v5, &v8, NULL); + CHECK(v2, &v5, &v9, &v6, &v4, &v8, &v7, &v11, &v13, &v3, &v2, &v12, &v10, NULL); + CHECK(v2, &v10, &v11, &v2, &v9, &v12, &v7, &v5, &v3, &v8, &v13, &v6, &v4, NULL); + CHECK(v2, &v3, &v10, &v2, &v4, &v8, &v9, &v11, &v7, &v5, &v13, &v6, &v12, NULL); + CHECK(v2, &v8, &v10, &v11, &v6, &v5, &v2, &v9, &v4, &v3, &v13, &v7, &v12, NULL); + CHECK(v2, &v4, &v12, &v11, &v7, &v3, &v13, &v10, &v2, &v5, &v9, &v6, &v8, NULL); + CHECK(v2, &v7, &v13, &v12, &v3, &v4, &v8, &v11, &v9, &v10, &v6, &v2, &v5, NULL); + CHECK(v2, &v5, &v4, &v2, &v8, &v7, &v13, &v10, &v11, &v3, &v9, &v6, &v12, NULL); + CHECK(v2, &v7, &v8, &v10, &v2, &v4, &v11, &v9, &v12, &v6, &v13, &v5, &v3, NULL); + CHECK(v2, &v3, &v7, &v2, &v13, &v5, &v10, &v12, &v6, &v8, &v11, &v9, &v4, NULL); + CHECK(v2, &v12, &v13, &v6, &v9, &v4, &v11, &v8, &v3, &v2, &v7, &v10, &v5, NULL); + CHECK(v2, &v2, &v9, &v10, &v13, &v3, &v5, &v8, &v7, &v6, &v11, &v4, &v12, NULL); + CHECK(v2, &v7, &v5, &v10, &v11, &v3, &v12, &v4, &v9, &v6, &v13, &v2, &v8, NULL); + CHECK(v2, &v3, &v4, &v8, &v2, &v13, &v11, &v7, &v10, &v5, &v6, &v12, &v9, NULL); + CHECK(v2, &v7, &v2, &v13, &v5, &v10, &v3, &v9, &v6, &v4, &v11, &v8, &v12, NULL); + CHECK(v2, &v6, &v5, &v3, &v11, &v8, &v9, &v12, &v7, &v13, &v4, &v10, &v2, NULL); + CHECK(v2, &v13, &v6, &v5, &v4, &v3, &v8, &v2, &v7, &v9, &v10, &v11, &v12, NULL); + CHECK(v2, &v13, &v12, &v4, &v3, &v11, &v6, &v7, &v10, &v2, &v5, &v9, &v8, NULL); + CHECK(v2, &v13, &v6, &v7, &v2, &v8, &v4, &v5, &v12, &v11, &v3, &v10, &v9, NULL); + CHECK(v2, &v13, &v5, &v12, &v11, &v10, &v9, &v2, &v6, &v4, &v8, &v3, &v7, NULL); + CHECK(v2, &v8, &v7, &v6, &v13, &v9, &v3, &v11, &v10, &v4, &v2, &v12, &v5, NULL); + CHECK(v2, &v8, &v9, &v3, &v7, &v11, &v2, &v13, &v4, &v6, &v12, &v10, &v5, NULL); + CHECK(v2, &v4, &v5, &v13, &v2, &v7, &v8, &v9, &v10, &v11, &v3, &v6, &v12, NULL); + CHECK(v2, &v7, &v4, &v11, &v9, &v6, &v12, &v3, &v5, &v10, &v8, &v2, &v13, NULL); + CHECK(v2, &v8, &v9, &v6, &v2, &v11, &v5, &v13, &v3, &v7, &v10, &v12, &v4, NULL); + CHECK(v2, &v10, &v4, &v5, &v6, &v3, &v7, &v13, &v8, &v12, &v2, &v9, &v11, NULL); + CHECK(v2, &v9, &v3, &v8, &v12, &v5, &v6, &v2, &v10, &v11, &v4, &v7, &v13, NULL); + + return 0; +} + +#endif diff --git a/libj2_min_j2u_return.c b/libj2_min_j2u_return.c new file mode 100644 index 0000000..38bc3f3 --- /dev/null +++ b/libj2_min_j2u_return.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline const struct libj2_j2u *libj2_min_j2u_return(const struct libj2_j2u *a, ... /*, NULL */); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_min_j2u.c */ + +#endif diff --git a/libj2_min_j2u_to_j2u.c b/libj2_min_j2u_to_j2u.c new file mode 100644 index 0000000..3e0d187 --- /dev/null +++ b/libj2_min_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_min_j2u_to_j2u(const struct libj2_j2u *a, ... /*, NULL, struct libj2_j2u *res */); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_min_j2u.c */ + +#endif diff --git a/libj2_minus_j2u.c b/libj2_minus_j2u.c new file mode 100644 index 0000000..c0609f9 --- /dev/null +++ b/libj2_minus_j2u.c @@ -0,0 +1,79 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_minus_j2u(struct libj2_j2u *a); +/* TODO Add man page */ + + +#else + +static uintmax_t +random_ju(void) +{ + size_t n = LIBJ2_JU_BIT; + uintmax_t r = 0; + while (n--) + if (rand() < rand()) + r |= (uintmax_t)1 << n; + return r; +} + + +static void +minus_j2u(struct libj2_j2u *a) +{ + struct libj2_j2u r, a_saved = *a; + r = (struct libj2_j2u){111, 222}; + libj2_minus_j2u_to_j2u(a, &r); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + libj2_minus_j2u(a); + EXPECT(libj2_j2u_eq_j2u(a, &r)); +} + + +int +main(void) +{ + unsigned i; + struct libj2_j2u a, b; + uintmax_t v; + + libj2_j2u_zero(&a); + minus_j2u(&a); + EXPECT(libj2_j2u_is_zero(&a)); + + a = (struct libj2_j2u){.high = 0, .low = 1}; + minus_j2u(&a); + EXPECT(libj2_j2u_eq_j2u(&a, &(struct libj2_j2u){.high = UINTMAX_MAX, .low = UINTMAX_MAX})); + + a = (struct libj2_j2u){.high = UINTMAX_MAX, .low = UINTMAX_MAX}; + minus_j2u(&a); + EXPECT(libj2_j2u_eq_j2u(&a, &(struct libj2_j2u){.high = 0, .low = 1})); + + for (i = 0; i < 256; i++) { + a.high = 0; + a.low = v = random_ju(); + minus_j2u(&a); + EXPECT(a.high == UINTMAX_MAX); + EXPECT(a.low == 0U - v); + + a.high = UINTMAX_MAX; + a.low = v = random_ju(); + minus_j2u(&a); + EXPECT(a.high == 0); + EXPECT(a.low == 0U - v); + } + + for (i = 0; i < 256; i++) { + a.high = b.high = random_ju(); + a.low = b.low = random_ju(); + minus_j2u(&a); + libj2_j2u_add_j2u(&a, &b); + EXPECT(libj2_j2u_is_zero(&a)); + } + + return 0; +} + +#endif diff --git a/libj2_minus_j2u_to_j2u.c b/libj2_minus_j2u_to_j2u.c new file mode 100644 index 0000000..1198d4e --- /dev/null +++ b/libj2_minus_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_minus_j2u_to_j2u(const struct libj2_j2u *a, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_minus_j2u.c */ + +#endif diff --git a/libj2_not_j2u.c b/libj2_not_j2u.c new file mode 100644 index 0000000..2a59b50 --- /dev/null +++ b/libj2_not_j2u.c @@ -0,0 +1,34 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_not_j2u(struct libj2_j2u *a); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u a; + + a.high = 0; + a.low = 0; + libj2_not_j2u(&a); + EXPECT(a.high == UINTMAX_MAX); + EXPECT(a.low == UINTMAX_MAX); + libj2_not_j2u(&a); + EXPECT(a.high == 0); + EXPECT(a.low == 0); + + a.high = UINTMAX_C(0x45FF23); + a.low = UINTMAX_C(0x5245FBA4); + libj2_not_j2u(&a); + EXPECT(a.high == ~(uintmax_t)UINTMAX_C(0x45FF23)); + EXPECT(a.low == ~(uintmax_t)UINTMAX_C(0x5245FBA4)); + + return 0; +} + +#endif diff --git a/libj2_not_j2u_to_j2u.c b/libj2_not_j2u_to_j2u.c new file mode 100644 index 0000000..6a19c17 --- /dev/null +++ b/libj2_not_j2u_to_j2u.c @@ -0,0 +1,46 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_not_j2u_to_j2u(const struct libj2_j2u *a, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u a, r, a_saved; + + a.high = 0; + a.low = 0; + a_saved = a; + r = (struct libj2_j2u){111, 222}; + libj2_not_j2u_to_j2u(&a, &r); + EXPECT(r.high == UINTMAX_MAX); + EXPECT(r.low == UINTMAX_MAX); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + a.high = UINTMAX_MAX; + a.low = UINTMAX_MAX; + a_saved = a; + r = (struct libj2_j2u){111, 222}; + libj2_not_j2u_to_j2u(&a, &r); + EXPECT(r.high == 0); + EXPECT(r.low == 0); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + a.high = UINTMAX_C(0x45FF23); + a.low = UINTMAX_C(0x5245FBA4); + a_saved = a; + r = (struct libj2_j2u){111, 222}; + libj2_not_j2u_to_j2u(&a, &r); + EXPECT(r.high == ~(uintmax_t)UINTMAX_C(0x45FF23)); + EXPECT(r.low == ~(uintmax_t)UINTMAX_C(0x5245FBA4)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + return 0; +} + +#endif diff --git a/libj2_not_ju_to_j2u.c b/libj2_not_ju_to_j2u.c new file mode 100644 index 0000000..aee0715 --- /dev/null +++ b/libj2_not_ju_to_j2u.c @@ -0,0 +1,34 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_not_ju_to_j2u(uintmax_t a, struct libj2_j2u *res); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u r; + + r = (struct libj2_j2u){111, 222}; + libj2_not_ju_to_j2u(0, &r); + EXPECT(r.high == UINTMAX_MAX); + EXPECT(r.low == UINTMAX_MAX); + + r = (struct libj2_j2u){111, 222}; + libj2_not_ju_to_j2u(UINTMAX_MAX, &r); + EXPECT(r.high == UINTMAX_MAX); + EXPECT(r.low == 0); + + r = (struct libj2_j2u){111, 222}; + libj2_not_ju_to_j2u(UINTMAX_C(0x5245FBA4), &r); + EXPECT(r.high == UINTMAX_MAX); + EXPECT(r.low == ~(uintmax_t)UINTMAX_C(0x5245FBA4)); + + return 0; +} + +#endif diff --git a/libj2_sgn_j2u.c b/libj2_sgn_j2u.c new file mode 100644 index 0000000..d20aa6f --- /dev/null +++ b/libj2_sgn_j2u.c @@ -0,0 +1,197 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_sgn_j2u(const struct libj2_j2u *a); +/* TODO Add man page */ + + +#else + +int +main(void) +{ + struct libj2_j2u value; + uintmax_t a, b; + int i, j; + + for (i = 0; i < CHAR_BIT * (int)sizeof(uintmax_t); i++) { + for (j = 0; j < CHAR_BIT * (int)sizeof(uintmax_t); j++) { + value.high = a = (uintmax_t)(i + 1); + value.low = b = (uintmax_t)(j + 1); + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)1 << i; + value.low = b = (uintmax_t)(j + 1); + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)(i + 1); + value.low = b = (uintmax_t)1 << j; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = (uintmax_t)1 << i; + value.low = b = (uintmax_t)1 << j; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b = ~((uintmax_t)(j + 1)); + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b = ~((uintmax_t)(j + 1)); + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b = ~((uintmax_t)1 << j); + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b = ~((uintmax_t)1 << j); + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == b); + } + + value.high = 0; + value.low = a = (uintmax_t)(i + 1); + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)(i + 1); + value.low = 0; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = (uintmax_t)1 << i; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)1 << i; + value.low = 0; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = ~((uintmax_t)(i + 1)); + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = 0; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = 0; + value.low = a = ~((uintmax_t)1 << i); + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)1 << i); + value.low = 0; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + b = ~(uintmax_t)0; + + value.high = b; + value.low = a = (uintmax_t)(i + 1); + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)(i + 1); + value.low = b; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = (uintmax_t)1 << i; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = (uintmax_t)1 << i; + value.low = b; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = ~((uintmax_t)(i + 1)); + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)(i + 1)); + value.low = b; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == b); + + value.high = b; + value.low = a = ~((uintmax_t)1 << i); + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == b); + EXPECT(value.low == a); + + value.high = a = ~((uintmax_t)1 << i); + value.low = b; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == b); + } + + value.high = 0; + value.low = 0; + EXPECT(libj2_sgn_j2u(&value) == 0); + EXPECT(value.high == 0); + EXPECT(value.low == 0); + + a = ~(uintmax_t)0; + + value.high = 0; + value.low = a; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == 0); + EXPECT(value.low == a); + + value.high = a; + value.low = 0; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == 0); + + value.high = a; + value.low = a; + EXPECT(libj2_sgn_j2u(&value) == +1); + EXPECT(value.high == a); + EXPECT(value.low == a); + + return 0; +} + +#endif diff --git a/libj2_vmax_j2u.c b/libj2_vmax_j2u.c new file mode 100644 index 0000000..1296902 --- /dev/null +++ b/libj2_vmax_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_vmax_j2u(struct libj2_j2u *a, va_list args); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested via libj2_max_j2u */ + +#endif diff --git a/libj2_vmax_j2u_return.c b/libj2_vmax_j2u_return.c new file mode 100644 index 0000000..b512ccd --- /dev/null +++ b/libj2_vmax_j2u_return.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline const struct libj2_j2u *libj2_vmax_j2u_return(const struct libj2_j2u *a, va_list args); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested via libj2_max_j2u_return */ + +#endif diff --git a/libj2_vmax_j2u_to_j2u.c b/libj2_vmax_j2u_to_j2u.c new file mode 100644 index 0000000..9b421dc --- /dev/null +++ b/libj2_vmax_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_vmax_j2u_to_j2u(const struct libj2_j2u *a, va_list args); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested via libj2_vmax_j2u_to_j2u */ + +#endif diff --git a/libj2_vmin_j2u.c b/libj2_vmin_j2u.c new file mode 100644 index 0000000..c723719 --- /dev/null +++ b/libj2_vmin_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_vmin_j2u(struct libj2_j2u *a, va_list args); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested via libj2_min_j2u */ + +#endif diff --git a/libj2_vmin_j2u_return.c b/libj2_vmin_j2u_return.c new file mode 100644 index 0000000..e10fb23 --- /dev/null +++ b/libj2_vmin_j2u_return.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline const struct libj2_j2u *libj2_vmin_j2u_return(const struct libj2_j2u *a, va_list args); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested via libj2_min_j2u_return */ + +#endif diff --git a/libj2_vmin_j2u_to_j2u.c b/libj2_vmin_j2u_to_j2u.c new file mode 100644 index 0000000..021e5ee --- /dev/null +++ b/libj2_vmin_j2u_to_j2u.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void libj2_vmin_j2u_to_j2u(const struct libj2_j2u *a, va_list args); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested via libj2_vmin_j2u_to_j2u */ + +#endif diff --git a/mk/linux.mk b/mk/linux.mk new file mode 100644 index 0000000..ad58f69 --- /dev/null +++ b/mk/linux.mk @@ -0,0 +1,6 @@ +LIBEXT = so +LIBFLAGS = -shared -Wl,-soname,lib$(LIB_NAME).$(LIBEXT).$(LIB_MAJOR) +LIBMAJOREXT = $(LIBEXT).$(LIB_MAJOR) +LIBMINOREXT = $(LIBEXT).$(LIB_VERSION) + +FIX_INSTALL_NAME = : diff --git a/mk/macos.mk b/mk/macos.mk new file mode 100644 index 0000000..ca39133 --- /dev/null +++ b/mk/macos.mk @@ -0,0 +1,6 @@ +LIBEXT = dylib +LIBFLAGS = -dynamiclib -Wl,-compatibility_version,$(LIB_MAJOR) -Wl,-current_version,$(LIB_VERSION) +LIBMAJOREXT = $(LIB_MAJOR).$(LIBEXT) +LIBMINOREXT = $(LIB_VERSION).$(LIBEXT) + +FIX_INSTALL_NAME = install_name_tool -id "$(PREFIX)/lib/libj2.$(LIBMAJOREXT)" diff --git a/mk/windows.mk b/mk/windows.mk new file mode 100644 index 0000000..ed5ec8d --- /dev/null +++ b/mk/windows.mk @@ -0,0 +1,6 @@ +LIBEXT = dll +LIBFLAGS = -shared +LIBMAJOREXT = $(LIB_MAJOR).$(LIBEXT) +LIBMINOREXT = $(LIB_VERSION).$(LIBEXT) + +FIX_INSTALL_NAME = : |
