aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile24
-rw-r--r--libj2.h26
-rw-r--r--libj2/addition.h64
-rw-r--r--libj2/bit-shifting.h106
-rw-r--r--libj2/multiplication.h235
-rw-r--r--libj2/subtraction.h116
-rw-r--r--libj2_j2u_add_j2u.c12
-rw-r--r--libj2_j2u_add_j2u_overflow_p.c13
-rw-r--r--libj2_j2u_add_ju.c30
-rw-r--r--libj2_j2u_add_ju_overflow_p.c13
-rw-r--r--libj2_j2u_lsh.c4
-rw-r--r--libj2_j2u_lsh_overflow_p.c13
-rw-r--r--libj2_j2u_mul_j2u_destructive.c72
-rw-r--r--libj2_j2u_mul_j2u_overflow_p.c13
-rw-r--r--libj2_j2u_mul_j2u_overflow_p_quick.c13
-rw-r--r--libj2_j2u_mul_j2u_to_j2u_overflow_p.c14
-rw-r--r--libj2_j2u_mul_ju.c64
-rw-r--r--libj2_j2u_mul_ju_overflow_p.c13
-rw-r--r--libj2_j2u_mul_ju_overflow_p_quick.c13
-rw-r--r--libj2_j2u_mul_ju_to_j2u_overflow_p.c13
-rw-r--r--libj2_j2u_rsh.c4
-rw-r--r--libj2_j2u_rsh_underflow_p.c13
-rw-r--r--libj2_j2u_rsub_j2u_overflow_p.c13
-rw-r--r--libj2_j2u_rsub_ju_overflow_p.c13
-rw-r--r--libj2_j2u_sub_j2u.c24
-rw-r--r--libj2_j2u_sub_j2u_overflow_p.c13
-rw-r--r--libj2_j2u_sub_ju.c17
-rw-r--r--libj2_j2u_sub_ju_overflow_p.c13
-rw-r--r--libj2_ju_add_j2u_overflow_p.c13
-rw-r--r--libj2_ju_lsh_overflow_p.c13
-rw-r--r--libj2_ju_lsh_to_j2u.c2
-rw-r--r--libj2_ju_mul_j2u_overflow_p.c13
-rw-r--r--libj2_ju_mul_j2u_overflow_p_quick.c13
-rw-r--r--libj2_ju_mul_j2u_to_j2u_overflow_p.c13
-rw-r--r--libj2_ju_rsh_to_j2u.c2
-rw-r--r--libj2_ju_rsh_underflow_p.c13
-rw-r--r--libj2_ju_sub_j2u_overflow_p.c13
-rw-r--r--libj2_ju_sub_ju_overflow_p.c13
-rw-r--r--libj2_ju_sub_ju_to_j2u.c2
39 files changed, 1081 insertions, 10 deletions
diff --git a/Makefile b/Makefile
index bd51b5c..4890df6 100644
--- a/Makefile
+++ b/Makefile
@@ -249,7 +249,29 @@ OBJ =\
libj2_slc_j2u_to_j2u.o\
libj2_j2u_has_j2u.o\
libj2_j2u_has_ju.o\
- libj2_j2u_has_high_ju.o
+ libj2_j2u_has_high_ju.o\
+ libj2_j2u_lsh_overflow_p.o\
+ libj2_ju_lsh_overflow_p.o\
+ libj2_j2u_rsh_underflow_p.o\
+ libj2_ju_rsh_underflow_p.o\
+ libj2_j2u_add_ju_overflow_p.o\
+ libj2_ju_add_j2u_overflow_p.o\
+ libj2_j2u_add_j2u_overflow_p.o\
+ libj2_j2u_sub_ju_overflow_p.o\
+ libj2_ju_sub_j2u_overflow_p.o\
+ libj2_ju_sub_ju_overflow_p.o\
+ libj2_j2u_sub_j2u_overflow_p.o\
+ libj2_j2u_rsub_j2u_overflow_p.o\
+ libj2_j2u_rsub_ju_overflow_p.o\
+ libj2_j2u_mul_j2u_overflow_p_quick.o\
+ libj2_j2u_mul_ju_overflow_p_quick.o\
+ libj2_ju_mul_j2u_overflow_p_quick.o\
+ libj2_j2u_mul_j2u_overflow_p.o\
+ libj2_j2u_mul_ju_overflow_p.o\
+ libj2_ju_mul_j2u_overflow_p.o\
+ libj2_j2u_mul_j2u_to_j2u_overflow_p.o\
+ libj2_j2u_mul_ju_to_j2u_overflow_p.o\
+ libj2_ju_mul_j2u_to_j2u_overflow_p.o
SUBHDR =\
libj2/constants.h\
diff --git a/libj2.h b/libj2.h
index aa1747f..4130c97 100644
--- a/libj2.h
+++ b/libj2.h
@@ -52,6 +52,32 @@ struct libj2_j2u {
};
+/**
+ * Arithmetic overflow prediction result
+ *
+ * Use by some functions for which prediction
+ * is costly in edge cases, and thus stopped
+ * as soon as such an edge case is detected
+ */
+enum libj2_overflow {
+ /**
+ * Where will not be an overflow
+ */
+ LIBJ2_NO_OVERFLOW = 0,
+
+ /**
+ * Where will be an overflow
+ */
+ LIBJ2_OVERFLOW = 1,
+
+ /**
+ * Overflow prediction stopped
+ * (due to high cost)
+ */
+ LIBJ2_OVERFLOW_UNKNOWN
+};
+
+
#include "libj2/constants.h"
#include "libj2/signum.h"
#include "libj2/constructors.h"
diff --git a/libj2/addition.h b/libj2/addition.h
index d900622..d0a57bf 100644
--- a/libj2/addition.h
+++ b/libj2/addition.h
@@ -311,3 +311,67 @@ libj2_j2u_add_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_
#endif
}
}
+
+
+/**
+ * Predict whether `libj2_j2u_add_ju_to_j2u_overflow`
+ * or `libj2_j2u_add_ju_overflow` will return a
+ * result-overflow signal
+ *
+ * `libj2_j2u_add_ju_overflow_p(a, b)` implements
+ * `libj2_j2u_add_ju_to_j2u_overflow(a, b, &(struct libj2_j2u){})`
+ * in an efficient manner
+ *
+ * @param a The augend
+ * @param b The addend
+ * @return 1 if the addition would overflow, 0 otherwise
+ */
+inline int
+libj2_j2u_add_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b)
+{
+ return a->low > UINTMAX_MAX - b && a->high == UINTMAX_MAX;
+}
+
+
+/**
+ * Predict whether `libj2_ju_add_j2u_to_j2u_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_ju_add_j2u_overflow_p(a, b)` implements
+ * `libj2_ju_add_j2u_to_j2u_overflow(a, b, &(struct libj2_j2u){})`
+ * in an efficient manner
+ *
+ * @param a The augend
+ * @param b The addend
+ * @return 1 if the addition would overflow, 0 otherwise
+ */
+inline int
+libj2_ju_add_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b)
+{
+ return libj2_j2u_add_ju_overflow_p(b, a);
+}
+
+
+/**
+ * Predict whether `libj2_j2u_add_j2u_to_j2u_overflow`
+ * or `libj2_j2u_add_j2u_overflow` will return a
+ * result-overflow signal
+ *
+ * `libj2_j2u_add_j2u_overflow_p(a, b)` implements
+ * `libj2_j2u_add_j2u_to_j2u_overflow(a, b, &(struct libj2_j2u){})`
+ * in an efficient manner
+ *
+ * @param a The augend
+ * @param b The addend
+ * @return 1 if the addition would overflow, 0 otherwise
+ */
+inline int
+libj2_j2u_add_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ if (a == b)
+ return (int)(a->high >> (LIBJ2_JU_BIT - 1U));
+ else if (libj2_j2u_add_ju_overflow_p(a, b->low))
+ return 1;
+ else
+ return a->high > UINTMAX_MAX - b->high;
+}
diff --git a/libj2/bit-shifting.h b/libj2/bit-shifting.h
index a0c36d1..bb691bc 100644
--- a/libj2/bit-shifting.h
+++ b/libj2/bit-shifting.h
@@ -571,3 +571,109 @@ 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);
}
+
+
+/**
+ * Predict whether `libj2_j2u_lsh_overflow` or
+ * `libj2_j2u_lsh_to_j2u_overflow` will return
+ * a result-overflow signal
+ *
+ * `libj2_j2u_lsh_overflow_p(a, b)` implements
+ * `libj2_j2u_lsh_to_j2u_overflow(a, b, &(struct libj2_j2u){})`
+ * in an efficient manner
+ *
+ * @param a The integer to shift (dry-run)
+ * @param b The number of positions to shift each bit
+ * @return 1 if set bit would be be shifted out, 0 otherwise
+ */
+inline int
+libj2_j2u_lsh_overflow_p(const struct libj2_j2u *a, unsigned b)
+{
+ if (b >= LIBJ2_J2U_BIT)
+ return a->high || a->low;
+ else if (b > LIBJ2_JU_BIT)
+ return a->high || a->low >> (LIBJ2_J2U_BIT - b);
+ else if (b == LIBJ2_JU_BIT)
+ return !!a->high;
+ else if (b)
+ return !!(a->high >> (LIBJ2_JU_BIT - b));
+ else
+ return 0;
+}
+
+
+/**
+ * Predict whether `libj2_ju_lsh_to_j2u_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_ju_lsh_overflow_p(a, b)` implements
+ * `libj2_ju_lsh_to_j2u_overflow(a, b, &(struct libj2_j2u){})`
+ * in an efficient manner
+ *
+ * @param a The integer to shift (dry-run)
+ * @param b The number of positions to shift each bit
+ * @return 1 if set bit would be be shifted out, 0 otherwise
+ */
+inline int
+libj2_ju_lsh_overflow_p(uintmax_t a, unsigned b)
+{
+ if (b >= LIBJ2_J2U_BIT)
+ return !!a;
+ else if (b > LIBJ2_JU_BIT)
+ return !!(a >> (LIBJ2_J2U_BIT - b));
+ else
+ return 0;
+}
+
+
+/**
+ * Predict whether `libj2_j2u_rsh_underflow` or
+ * `libj2_j2u_rsh_to_j2u_underflow` will return
+ * a result-underflow signal
+ *
+ * `libj2_j2u_rsh_underflow_p(a, b)` implements
+ * `libj2_j2u_rsh_to_j2u_underflow(a, b, &(struct libj2_j2u){})`
+ * in an efficient manner
+ *
+ * @param a The integer to shift (dry-run)
+ * @param b The number of positions to shift each bit
+ * @return 1 if set bit would be be shifted out, 0 otherwise
+ */
+inline int
+libj2_j2u_rsh_underflow_p(const struct libj2_j2u *a, unsigned b)
+{
+ if (b >= LIBJ2_J2U_BIT)
+ return a->high || a->low;
+ else if (b > LIBJ2_JU_BIT)
+ return a->low || a->high >> (LIBJ2_J2U_BIT - b);
+ else if (b == LIBJ2_JU_BIT)
+ return !!a->low;
+ else if (b)
+ return !!(a->low << (LIBJ2_JU_BIT - b));
+ else
+ return 0;
+}
+
+
+/**
+ * Predict whether `libj2_ju_rsh_to_j2u_underflow`
+ * will return a result-underflowflow signal
+ *
+ * `libj2_ju_rsh_underflow_p(a, b)` implements
+ * `libj2_ju_rsh_to_j2u_underflow(a, b, &(struct libj2_j2u){})`
+ * in an efficient manner
+ *
+ * @param a The integer to shift (dry-run)
+ * @param b The number of positions to shift each bit
+ * @return 1 if set bit would be be shifted out, 0 otherwise
+ */
+inline int
+libj2_ju_rsh_underflow_p(uintmax_t a, unsigned b)
+{
+ if (b >= LIBJ2_JU_BIT)
+ return !!a;
+ else if (b)
+ return !!(a << (LIBJ2_JU_BIT - b));
+ else
+ return 0;
+}
diff --git a/libj2/multiplication.h b/libj2/multiplication.h
index 005fa5d..09ead3c 100644
--- a/libj2/multiplication.h
+++ b/libj2/multiplication.h
@@ -364,3 +364,238 @@ libj2_j2u_mul_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_
*res = *a;
return libj2_j2u_mul_j2u_overflow_destructive(res, &c);
}
+
+
+/**
+ * Variant of `libj2_j2u_mul_j2u_overflow_p` that
+ * that stops the overflow-prediction is costly
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @return `LIBJ2_OVERFLOW` (= 1) if the multiplication would overflow,
+ * `LIBJ2_NO_OVERFLOW` (= 0) if the multiplication would not overflow,
+ * or `LIBJ2_OVERFLOW_UNKNOWN` if the prediction was not made
+ */
+inline enum libj2_overflow
+libj2_j2u_mul_j2u_overflow_p_quick(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ unsigned lz;
+
+ if (!a->high == !b->high)
+ return a->high > 0 ? LIBJ2_OVERFLOW : LIBJ2_NO_OVERFLOW;
+ if (!a->high && a->low <= 1U)
+ return LIBJ2_NO_OVERFLOW;
+ if (!b->high && b->low <= 1U)
+ return LIBJ2_NO_OVERFLOW;
+
+ lz = libj2_clz_j2u(a) + libj2_clz_j2u(b);
+ if (lz <= LIBJ2_J2U_BIT)
+ return LIBJ2_OVERFLOW;
+ if (lz > LIBJ2_J2U_BIT - 1U)
+ return LIBJ2_NO_OVERFLOW;
+
+ return LIBJ2_OVERFLOW_UNKNOWN;
+}
+
+
+/**
+ * Variant of `libj2_j2u_mul_ju_overflow_p` that
+ * that stops the overflow-prediction is costly
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @return `LIBJ2_OVERFLOW` (= 1) if the multiplication would overflow,
+ * `LIBJ2_NO_OVERFLOW` (= 0) if the multiplication would not overflow,
+ * or `LIBJ2_OVERFLOW_UNKNOWN` if the prediction was not made
+ */
+inline enum libj2_overflow
+libj2_j2u_mul_ju_overflow_p_quick(const struct libj2_j2u *a, uintmax_t b)
+{
+ return libj2_j2u_mul_j2u_overflow_p_quick(a, &(struct libj2_j2u){.high = 0, .low = b});
+}
+
+
+/**
+ * Variant of `libj2_ju_mul_j2u_overflow_p` that
+ * that stops the overflow-prediction is costly
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @return `LIBJ2_OVERFLOW` (= 1) if the multiplication would overflow,
+ * `LIBJ2_NO_OVERFLOW` (= 0) if the multiplication would not overflow,
+ * or `LIBJ2_OVERFLOW_UNKNOWN` if the prediction was not made
+ */
+inline enum libj2_overflow
+libj2_ju_mul_j2u_overflow_p_quick(uintmax_t a, const struct libj2_j2u *b)
+{
+ return libj2_j2u_mul_ju_overflow_p_quick(b, a);
+}
+
+
+/**
+ * Predict whether `libj2_j2u_mul_j2u_overflow_destructive`
+ * `libj2_j2u_mul_j2u_overflow`, or `libj2_j2u_mul_j2u_to_j2u_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_j2u_mul_j2u_overflow_p(a, b)` implements
+ * `libj2_j2u_mul_j2u_to_j2u_overflow(a, b, &(struct libj2_j2u){})`
+ * in an efficient manner for most cases
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @return 1 if the multiplication would overflow, 0 otherwise
+ */
+inline int
+libj2_j2u_mul_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ enum libj2_overflow overflow;
+ struct libj2_j2u j2u;
+ uintmax_t ju, c;
+
+ overflow = libj2_j2u_mul_j2u_overflow_p_quick(a, b);
+ if (overflow != LIBJ2_OVERFLOW_UNKNOWN)
+ return (int)overflow;
+
+ if (a->high) {
+ j2u = *a;
+ ju = b->low;
+ } else {
+ j2u = *b;
+ ju = a->low;
+ }
+
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_mul_overflow(j2u.high, ju, &c))
+ return 1;
+#else
+ if (j2u.high > UINTMAX_MAX / ju)
+ return 1;
+ c = j2u.high * ju;
+#endif
+
+ libj2_ju_mul_ju_to_j2u(j2u.low, ju, &j2u);
+ return j2u.high > UINTMAX_MAX - c;
+}
+
+
+/**
+ * Predict whether `libj2_j2u_mul_ju_overflow`
+ * or `libj2_j2u_mul_ju_to_j2u_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_j2u_mul_ju_overflow_p(a, b)` implements
+ * `libj2_j2u_mul_ju_to_j2u_overflow(a, b, &(struct libj2_j2u){})`
+ * in an efficient manner for most cases
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @return 1 if the multiplication would overflow, 0 otherwise
+ */
+inline int
+libj2_j2u_mul_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b)
+{
+ return libj2_j2u_mul_j2u_overflow_p(a, &(struct libj2_j2u){.high = 0, .low = b});
+}
+
+
+/**
+ * Predict whether `libj2_ju_mul_j2u_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_ju_mul_j2u_overflow_p(a, b)` implements
+ * `libj2_ju_mul_j2u(&(struct libj2_j2u){.high = a->high, .low = a->low}, b)`
+ * in an efficient manner for most cases
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @return 1 if the multiplication would overflow, 0 otherwise
+ */
+inline int
+libj2_ju_mul_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b)
+{
+ return libj2_j2u_mul_ju_overflow_p(b, a);
+}
+
+
+/**
+ * Variant of `libj2_j2u_mul_j2u_overflow_p` that
+ * that performs the multiplication if the
+ * overflow-prediction is costly
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ * @param res_set Output parameter for whether `*res` is set,
+ * if set to 1 when the function returns,
+ * `*res` will be set to the product,
+ * if set to 0 when the function returns,
+ * `*res` will be unmodified;
+ * will never be set to any other value
+ * @return 1 if the multiplication would overflow
+ * (did overflow), 0 otherwise
+ */
+inline int
+libj2_j2u_mul_j2u_to_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res, int *res_set)
+{
+ enum libj2_overflow overflow;
+
+ overflow = libj2_j2u_mul_j2u_overflow_p_quick(a, b);
+ if (overflow != LIBJ2_OVERFLOW_UNKNOWN) {
+ *res_set = 0;
+ return (int)overflow;
+ }
+
+ *res_set = 1;
+ if (a->high)
+ return libj2_j2u_mul_ju_to_j2u_overflow(a, b->low, res);
+ else
+ return libj2_j2u_mul_ju_to_j2u_overflow(b, a->low, res);
+}
+
+
+/**
+ * Variant of `libj2_j2u_mul_ju_overflow_p` that
+ * that performs the multiplication if the
+ * overflow-prediction is costly
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ * @param res_set Output parameter for whether `*res` is set,
+ * if set to 1 when the function returns,
+ * `*res` will be set to the product,
+ * if set to 0 when the function returns,
+ * `*res` will be unmodified;
+ * will never be set to any other value
+ * @return 1 if the multiplication would overflow
+ * (did overflow), 0 otherwise
+ */
+inline int
+libj2_j2u_mul_ju_to_j2u_overflow_p(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res, int *res_set)
+{
+ return libj2_j2u_mul_j2u_to_j2u_overflow_p(a, &(struct libj2_j2u){.high = 0, .low = b}, res, res_set);
+}
+
+
+/**
+ * Variant of `libj2_ju_mul_j2u_overflow_p` that
+ * that performs the multiplication if the
+ * overflow-prediction is costly
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ * @param res_set Output parameter for whether `*res` is set,
+ * if set to 1 when the function returns,
+ * `*res` will be set to the product,
+ * if set to 0 when the function returns,
+ * `*res` will be unmodified;
+ * will never be set to any other value
+ * @return 1 if the multiplication would overflow
+ * (did overflow), 0 otherwise
+ */
+inline int
+libj2_ju_mul_j2u_to_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res, int *res_set)
+{
+ return libj2_j2u_mul_ju_to_j2u_overflow_p(b, a, res, res_set);
+}
diff --git a/libj2/subtraction.h b/libj2/subtraction.h
index 27ae9d6..7f0bbce 100644
--- a/libj2/subtraction.h
+++ b/libj2/subtraction.h
@@ -491,3 +491,119 @@ libj2_j2u_rsub_ju_overflow(struct libj2_j2u *a, uintmax_t b)
#endif
return overflow;
}
+
+
+/**
+ * Predict whether `libj2_j2u_sub_ju_to_j2u_overflow`
+ * or `libj2_j2u_sub_ju_overflow` will return a
+ * result-overflow signal
+ *
+ * `libj2_j2u_sub_ju_overflow_p(a, b)` implements
+ * `libj2_j2u_sub_ju_to_j2u_overflow(a, b, &(struct libj2_j2u){})`
+ * in an efficient manner
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @return 1 if the subtraction would overflow, 0 otherwise
+ */
+inline int
+libj2_j2u_sub_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b)
+{
+ return a->low < b && !a->high;
+}
+
+
+/**
+ * Predict whether `libj2_ju_sub_j2u_to_j2u_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_ju_sub_j2u_overflow_p(a, b)` implements
+ * `libj2_ju_sub_j2u_to_j2u_overflow(a, b, &(struct libj2_j2u){})`
+ * in an efficient manner
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @return 1 if the subtraction would overflow, 0 otherwise
+ */
+inline int
+libj2_ju_sub_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b)
+{
+ return b->high || b->low > a;
+}
+
+
+/**
+ * Predict whether `libj2_ju_sub_ju_to_j2u_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_ju_sub_ju_overflow_p(a, b)` implements
+ * `libj2_ju_sub_ju_to_j2u_overflow(a, b, &(struct libj2_j2u){})`
+ * in an efficient manner
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @return 1 if the subtraction would overflow, 0 otherwise
+ */
+inline int
+libj2_ju_sub_ju_overflow_p(uintmax_t a, uintmax_t b)
+{
+ return a < b;
+}
+
+
+/**
+ * Predict whether `libj2_j2u_sub_j2u_to_j2u_overflow`
+ * or `libj2_j2u_sub_j2u_overflow` will return a
+ * result-overflow signal
+ *
+ * `libj2_j2u_sub_j2u_overflow_p(a, b)` implements
+ * `libj2_j2u_sub_j2u_to_j2u_overflow(a, b, &(struct libj2_j2u){})`
+ * in an efficient manner
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @return 1 if the subtraction would overflow, 0 otherwise
+ */
+inline int
+libj2_j2u_sub_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ return libj2_j2u_sub_ju_overflow_p(a, b->low) || a->high < b->high;
+}
+
+
+/**
+ * Predict whether `libj2_j2u_rsub_j2u_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_j2u_rsub_j2u_overflow_p(a, b)` implements
+ * `libj2_j2u_rsub_j2u_overflow(&(struct libj2_j2u){.high = a->high, .low = a->low}, b)`
+ * in an efficient manner
+ *
+ * @param a The subtrahend (right-hand)
+ * @param b The minuend (left-hand)
+ * @return 1 if the subtraction would overflow, 0 otherwise
+ */
+inline int
+libj2_j2u_rsub_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ return libj2_j2u_sub_j2u_overflow_p(b, a);
+}
+
+
+/**
+ * Predict whether `libj2_j2u_rsub_ju_overflow`
+ * will return a result-overflow signal
+ *
+ * `libj2_j2u_rsub_ju_overflow_p(a, b)` implements
+ * `libj2_j2u_rsub_ju_overflow(&(struct libj2_j2u){.high = a->high, .low = a->low}, b)`
+ * in an efficient manner
+ *
+ * @param a The subtrahend (right-hand)
+ * @param b The minuend (left-hand)
+ * @return 1 if the subtraction would overflow, 0 otherwise
+ */
+inline int
+libj2_j2u_rsub_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b)
+{
+ return libj2_ju_sub_j2u_overflow_p(b, a);
+}
diff --git a/libj2_j2u_add_j2u.c b/libj2_j2u_add_j2u.c
index bd783a0..8aca375 100644
--- a/libj2_j2u_add_j2u.c
+++ b/libj2_j2u_add_j2u.c
@@ -56,13 +56,18 @@ check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low,
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));
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2u_add_j2u_overflow_p((const struct libj2_j2u *)&a, (const struct libj2_j2u *)&b) == r_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
r = (struct libj2_j2u){111, 222};
a = a_saved;
b = b_saved;
@@ -150,11 +155,14 @@ check_double(uintmax_t high, uintmax_t low)
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));
+ a = a_saved;
+ EXPECT(libj2_j2u_add_j2u_overflow_p((const struct libj2_j2u *)&a, (const struct libj2_j2u *)&a) == expected_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
r = (struct libj2_j2u){111, 222};
a = a_saved;
EXPECT(libj2_j2u_add_j2u_to_j2u_overflow(&a, &a, &r) == expected_overflow);
diff --git a/libj2_j2u_add_j2u_overflow_p.c b/libj2_j2u_add_j2u_overflow_p.c
new file mode 100644
index 0000000..eea2fe6
--- /dev/null
+++ b/libj2_j2u_add_j2u_overflow_p.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_p(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_add_j2u.c */
+
+#endif
diff --git a/libj2_j2u_add_ju.c b/libj2_j2u_add_ju.c
index 8592662..f368857 100644
--- a/libj2_j2u_add_ju.c
+++ b/libj2_j2u_add_ju.c
@@ -35,6 +35,11 @@ check_zero_low(uintmax_t high, uintmax_t low)
EXPECT(a.high == high);
EXPECT(a.low == low);
+ a = (struct libj2_j2u){.high = high, .low = 0};
+ EXPECT(libj2_j2u_add_ju_overflow_p((const struct libj2_j2u *)&a, low) == 0);
+ EXPECT(a.high == high);
+ EXPECT(a.low == 0);
+
r = (struct libj2_j2u){111, 222};
a = (struct libj2_j2u){.high = high, .low = 0};
libj2_j2u_add_ju_to_j2u(&a, low, &r);
@@ -86,6 +91,11 @@ check_zero_low(uintmax_t high, uintmax_t low)
EXPECT(libj2_ju_add_j2u_to_j2u_overflow(low, &a, &a) == 0);
EXPECT(a.high == high);
EXPECT(a.low == low);
+
+ a = (struct libj2_j2u){.high = high, .low = 0};
+ EXPECT(libj2_ju_add_j2u_overflow_p(low, (const struct libj2_j2u *)&a) == 0);
+ EXPECT(a.high == high);
+ EXPECT(a.low == 0);
}
@@ -107,6 +117,11 @@ check_max_low(uintmax_t high, uintmax_t 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_p((const struct libj2_j2u *)&a, low) == expected_overflow);
+ EXPECT(a.high == high);
+ EXPECT(a.low == UINTMAX_MAX);
+
r = (struct libj2_j2u){111, 222};
a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
libj2_j2u_add_ju_to_j2u(&a, low, &r);
@@ -158,6 +173,11 @@ check_max_low(uintmax_t high, uintmax_t low)
EXPECT(libj2_ju_add_j2u_to_j2u_overflow(low, &a, &a) == expected_overflow);
EXPECT(a.high == expected_high);
EXPECT(a.low == expected_low);
+
+ a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ EXPECT(libj2_ju_add_j2u_overflow_p(low, (const struct libj2_j2u *)&a) == expected_overflow);
+ EXPECT(a.high == high);
+ EXPECT(a.low == UINTMAX_MAX);
}
@@ -206,6 +226,11 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t 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_p((const struct libj2_j2u *)&a, b) == expected_overflow);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_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);
@@ -257,6 +282,11 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b)
EXPECT(libj2_ju_add_j2u_to_j2u_overflow(b, &a, &a) == expected_overflow);
EXPECT(a.high == expected_high);
EXPECT(a.low == expected_low);
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_ju_add_j2u_overflow_p(b, (const struct libj2_j2u *)&a) == expected_overflow);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
}
diff --git a/libj2_j2u_add_ju_overflow_p.c b/libj2_j2u_add_ju_overflow_p.c
new file mode 100644
index 0000000..11d436f
--- /dev/null
+++ b/libj2_j2u_add_ju_overflow_p.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_p(const 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_lsh.c b/libj2_j2u_lsh.c
index 85ca72b..914c3b2 100644
--- a/libj2_j2u_lsh.c
+++ b/libj2_j2u_lsh.c
@@ -126,6 +126,10 @@ check(const char *pattern)
EXPECT(libj2_j2u_lsh_overflow(&r, i) == overflows);
EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ r = a;
+ EXPECT(libj2_j2u_lsh_overflow_p((const struct libj2_j2u *)&r, i) == overflows);
+ EXPECT(libj2_j2u_eq_j2u(&r, &a));
+
r = (struct libj2_j2u){111, 222};
libj2_j2u_lsh_to_j2u(&a, i, &r);
EXPECT(libj2_j2u_eq_j2u(&r, &expected));
diff --git a/libj2_j2u_lsh_overflow_p.c b/libj2_j2u_lsh_overflow_p.c
new file mode 100644
index 0000000..3dbe8dc
--- /dev/null
+++ b/libj2_j2u_lsh_overflow_p.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_p(const 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_mul_j2u_destructive.c b/libj2_j2u_mul_j2u_destructive.c
index cfa36a2..ba986da 100644
--- a/libj2_j2u_mul_j2u_destructive.c
+++ b/libj2_j2u_mul_j2u_destructive.c
@@ -60,7 +60,9 @@ refmul(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *e
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;
+ struct libj2_j2u t, x, a_saved = *a, b_saved = *b, t_saved;
+ enum libj2_overflow ofp;
+ int set;
*expected = *a;
libj2_j2u_mul_j2u(expected, b);
@@ -72,10 +74,53 @@ mul_(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *exp
EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
t = *a;
+ libj2_j2u_mul_j2u_to_j2u(&t, b, &t);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+
+ t = *b;
+ libj2_j2u_mul_j2u_to_j2u(a, &t, &t);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_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 = *a;
+ EXPECT(libj2_j2u_mul_j2u_overflow_p(&t, b) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, a));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+
+ ofp = libj2_j2u_mul_j2u_overflow_p_quick(&t, b);
+ EXPECT(ofp == LIBJ2_OVERFLOW_UNKNOWN || (int)ofp == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, a));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+
+ set = 999;
+ t = (struct libj2_j2u){111, 222};
+ t_saved = t;
+ EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow_p(a, b, &t, &set) == expect_overflow);
+ EXPECT(set == 0 || set == 1);
+ EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : &t_saved));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+
+ set = 999;
+ t = *a;
+ EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow_p(&t, b, &t, &set) == expect_overflow);
+ EXPECT(set == 0 || set == 1);
+ EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+
+ set = 999;
+ t = *b;
+ EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow_p(a, &t, &t, &set) == expect_overflow);
+ EXPECT(set == 0 || set == 1);
+ EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_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));
@@ -83,6 +128,16 @@ mul_(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *exp
EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
t = *a;
+ EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow(&t, b, &t) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+
+ t = *b;
+ EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow(a, &t, &t) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+
+ t = *a;
x = *b;
libj2_j2u_mul_j2u_destructive(&t, &x);
EXPECT(libj2_j2u_eq_j2u(&t, expected));
@@ -106,6 +161,21 @@ mul_(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *exp
EXPECT(libj2_j2u_eq_j2u(&t, expected));
t = *a;
+ EXPECT(libj2_j2u_mul_j2u_overflow_p(&t, &t) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, a));
+
+ t = *a;
+ ofp = libj2_j2u_mul_j2u_overflow_p_quick(&t, &t);
+ EXPECT(ofp == LIBJ2_OVERFLOW_UNKNOWN || (int)ofp == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, a));
+
+ set = 999;
+ t = *a;
+ EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow_p(&t, &t, &t, &set) == expect_overflow);
+ EXPECT(set == 0 || set == 1);
+ EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : a));
+
+ t = *a;
EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow(&t, &t, &t) == expect_overflow);
EXPECT(libj2_j2u_eq_j2u(&t, expected));
}}
diff --git a/libj2_j2u_mul_j2u_overflow_p.c b/libj2_j2u_mul_j2u_overflow_p.c
new file mode 100644
index 0000000..5fa95c6
--- /dev/null
+++ b/libj2_j2u_mul_j2u_overflow_p.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_p(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_mul_j2u_destructive.c */
+
+#endif
diff --git a/libj2_j2u_mul_j2u_overflow_p_quick.c b/libj2_j2u_mul_j2u_overflow_p_quick.c
new file mode 100644
index 0000000..d26145b
--- /dev/null
+++ b/libj2_j2u_mul_j2u_overflow_p_quick.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline enum libj2_overflow libj2_j2u_mul_j2u_overflow_p_quick(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_mul_j2u_destructive.c */
+
+#endif
diff --git a/libj2_j2u_mul_j2u_to_j2u_overflow_p.c b/libj2_j2u_mul_j2u_to_j2u_overflow_p.c
new file mode 100644
index 0000000..db87add
--- /dev/null
+++ b/libj2_j2u_mul_j2u_to_j2u_overflow_p.c
@@ -0,0 +1,14 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_j2u_mul_j2u_to_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b,
+ struct libj2_j2u *res, int *res_set);
+/* 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
index 17fc453..6be737c 100644
--- a/libj2_j2u_mul_ju.c
+++ b/libj2_j2u_mul_ju.c
@@ -53,7 +53,9 @@ refmul(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *expected)
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;
+ struct libj2_j2u t, a_saved = *a, t_saved;
+ enum libj2_overflow ofp;
+ int set;
*expected = *a;
libj2_j2u_mul_ju(expected, b);
@@ -63,24 +65,84 @@ mul(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *expected, int expe
EXPECT(libj2_j2u_eq_j2u(&t, expected));
EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ t = *a;
+ libj2_j2u_mul_ju_to_j2u(&t, b, &t);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+
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;
+ libj2_ju_mul_j2u_to_j2u(b, &t, &t);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+
+ t = *a;
EXPECT(libj2_j2u_mul_ju_overflow(&t, b) == expect_overflow);
EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ t = *a;
+ EXPECT(libj2_j2u_mul_ju_overflow_p((const struct libj2_j2u *)&t, b) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, a));
+
+ t = *a;
+ ofp = libj2_j2u_mul_ju_overflow_p_quick((const struct libj2_j2u *)&t, b);
+ EXPECT(ofp == LIBJ2_OVERFLOW_UNKNOWN || (int)ofp == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, a));
+
+ set = 999;
+ t = (struct libj2_j2u){111, 222};
+ t_saved = t;
+ EXPECT(libj2_j2u_mul_ju_to_j2u_overflow_p((const struct libj2_j2u *)a, b, &t, &set) == expect_overflow);
+ EXPECT(set == 0 || set == 1);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : &t_saved));
+
+ set = 999;
+ t = *a;
+ EXPECT(libj2_j2u_mul_ju_to_j2u_overflow_p((const struct libj2_j2u *)&t, b, &t, &set) == expect_overflow);
+ EXPECT(set == 0 || set == 1);
+ EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : a));
+
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 = *a;
+ EXPECT(libj2_j2u_mul_ju_to_j2u_overflow(&t, b, &t) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+
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));
+
+ t = *a;
+ EXPECT(libj2_ju_mul_j2u_to_j2u_overflow(b, &t, &t) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&t, expected));
+
+ set = 999;
+ t = (struct libj2_j2u){111, 222};
+ t_saved = t;
+ EXPECT(libj2_ju_mul_j2u_to_j2u_overflow_p(b, a, &t, &set) == expect_overflow);
+ EXPECT(set == 0 || set == 1);
+ EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : &t_saved));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+
+ set = 999;
+ t = *a;
+ EXPECT(libj2_ju_mul_j2u_to_j2u_overflow_p(b, &t, &t, &set) == expect_overflow);
+ EXPECT(set == 0 || set == 1);
+ EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : a));
+
+ EXPECT(libj2_ju_mul_j2u_overflow_p(b, (const struct libj2_j2u *)a) == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+
+ ofp = libj2_ju_mul_j2u_overflow_p_quick(b, (const struct libj2_j2u *)a);
+ EXPECT(ofp == LIBJ2_OVERFLOW_UNKNOWN || (int)ofp == expect_overflow);
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
}
diff --git a/libj2_j2u_mul_ju_overflow_p.c b/libj2_j2u_mul_ju_overflow_p.c
new file mode 100644
index 0000000..aa25a2b
--- /dev/null
+++ b/libj2_j2u_mul_ju_overflow_p.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_p(const 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_overflow_p_quick.c b/libj2_j2u_mul_ju_overflow_p_quick.c
new file mode 100644
index 0000000..be12c11
--- /dev/null
+++ b/libj2_j2u_mul_ju_overflow_p_quick.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline enum libj2_overflow libj2_j2u_mul_ju_overflow_p_quick(const 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_overflow_p.c b/libj2_j2u_mul_ju_to_j2u_overflow_p.c
new file mode 100644
index 0000000..11b4216
--- /dev/null
+++ b/libj2_j2u_mul_ju_to_j2u_overflow_p.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_p(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res, int *res_set);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */
+
+#endif
diff --git a/libj2_j2u_rsh.c b/libj2_j2u_rsh.c
index 2a5ed50..3dc18e9 100644
--- a/libj2_j2u_rsh.c
+++ b/libj2_j2u_rsh.c
@@ -84,6 +84,10 @@ check(const char *pattern)
EXPECT(libj2_j2u_rsh_underflow(&r, i) == underflows);
EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ r = a;
+ EXPECT(libj2_j2u_rsh_underflow_p((const struct libj2_j2u *)&r, i) == underflows);
+ EXPECT(libj2_j2u_eq_j2u(&r, &a));
+
r = (struct libj2_j2u){111, 222};
libj2_j2u_rsh_to_j2u(&a, i, &r);
EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
diff --git a/libj2_j2u_rsh_underflow_p.c b/libj2_j2u_rsh_underflow_p.c
new file mode 100644
index 0000000..6e00eae
--- /dev/null
+++ b/libj2_j2u_rsh_underflow_p.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_p(const 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_overflow_p.c b/libj2_j2u_rsub_j2u_overflow_p.c
new file mode 100644
index 0000000..4bf6cab
--- /dev/null
+++ b/libj2_j2u_rsub_j2u_overflow_p.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_p(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_sub_j2u.c */
+
+#endif
diff --git a/libj2_j2u_rsub_ju_overflow_p.c b/libj2_j2u_rsub_ju_overflow_p.c
new file mode 100644
index 0000000..9666070
--- /dev/null
+++ b/libj2_j2u_rsub_ju_overflow_p.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_p(const 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
index 6727c71..bd645e2 100644
--- a/libj2_j2u_sub_j2u.c
+++ b/libj2_j2u_sub_j2u.c
@@ -56,13 +56,18 @@ check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low,
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));
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2u_sub_j2u_overflow_p((const struct libj2_j2u *)&a, (const struct libj2_j2u *)&b) == r_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
r = (struct libj2_j2u){111, 222};
a = a_saved;
b = b_saved;
@@ -89,12 +94,17 @@ check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low,
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));
+
+ a = a_saved;
+ b = b_saved;
+ EXPECT(libj2_j2u_rsub_j2u_overflow_p(&b, &a) == r_overflow);
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
}
@@ -146,11 +156,14 @@ check_double(uintmax_t high, uintmax_t low)
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));
+ a = a_saved;
+ EXPECT(libj2_j2u_sub_j2u_overflow_p((const struct libj2_j2u *)&a, (const struct libj2_j2u *)&a) == 0);
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
r = (struct libj2_j2u){111, 222};
a = a_saved;
EXPECT(libj2_j2u_sub_j2u_to_j2u_overflow(&a, &a, &r) == 0);
@@ -165,10 +178,13 @@ check_double(uintmax_t high, uintmax_t low)
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));
+
+ a = a_saved;
+ EXPECT(libj2_j2u_rsub_j2u_overflow_p((const struct libj2_j2u *)&a, (const struct libj2_j2u *)&a) == 0);
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
}
diff --git a/libj2_j2u_sub_j2u_overflow_p.c b/libj2_j2u_sub_j2u_overflow_p.c
new file mode 100644
index 0000000..424b9a0
--- /dev/null
+++ b/libj2_j2u_sub_j2u_overflow_p.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_p(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_sub_j2u.c */
+
+#endif
diff --git a/libj2_j2u_sub_ju.c b/libj2_j2u_sub_ju.c
index b2a3f47..0cd0343 100644
--- a/libj2_j2u_sub_ju.c
+++ b/libj2_j2u_sub_ju.c
@@ -41,6 +41,11 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b)
EXPECT(libj2_j2u_sub_ju_overflow(&a, b) == expected_overflow);
EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_j2u_sub_ju_overflow_p((const struct libj2_j2u *)&a, b) == expected_overflow);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+
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);
@@ -86,6 +91,11 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t 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_p((const struct libj2_j2u *)&a, b) == expected_roverflow);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+
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);
@@ -97,7 +107,12 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b)
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));
+ EXPECT(libj2_j2u_eq_j2u(&a, &expected));;
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ EXPECT(libj2_ju_sub_j2u_overflow_p(b, (const struct libj2_j2u *)&a) == expected_roverflow);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
}
diff --git a/libj2_j2u_sub_ju_overflow_p.c b/libj2_j2u_sub_ju_overflow_p.c
new file mode 100644
index 0000000..54b037d
--- /dev/null
+++ b/libj2_j2u_sub_ju_overflow_p.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_p(const 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_ju_add_j2u_overflow_p.c b/libj2_ju_add_j2u_overflow_p.c
new file mode 100644
index 0000000..bc827c8
--- /dev/null
+++ b/libj2_ju_add_j2u_overflow_p.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_overflow_p(uintmax_t a, const struct libj2_j2u *b);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_ju.c */
+
+#endif
diff --git a/libj2_ju_lsh_overflow_p.c b/libj2_ju_lsh_overflow_p.c
new file mode 100644
index 0000000..a10491c
--- /dev/null
+++ b/libj2_ju_lsh_overflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_lsh_overflow_p(uintmax_t a, unsigned b);
+/* 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_lsh_to_j2u.c b/libj2_ju_lsh_to_j2u.c
index 82aa61f..ca05fbf 100644
--- a/libj2_ju_lsh_to_j2u.c
+++ b/libj2_ju_lsh_to_j2u.c
@@ -142,6 +142,8 @@ check(const char *pattern)
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));
+
+ EXPECT(libj2_ju_lsh_overflow_p(a.low, i) == overflows);
}
}
diff --git a/libj2_ju_mul_j2u_overflow_p.c b/libj2_ju_mul_j2u_overflow_p.c
new file mode 100644
index 0000000..93a6328
--- /dev/null
+++ b/libj2_ju_mul_j2u_overflow_p.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_overflow_p(uintmax_t a, const struct libj2_j2u *b);
+/* 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_overflow_p_quick.c b/libj2_ju_mul_j2u_overflow_p_quick.c
new file mode 100644
index 0000000..8e7a71d
--- /dev/null
+++ b/libj2_ju_mul_j2u_overflow_p_quick.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline enum libj2_overflow libj2_ju_mul_j2u_overflow_p_quick(uintmax_t a, const struct libj2_j2u *b);
+/* 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_p.c b/libj2_ju_mul_j2u_to_j2u_overflow_p.c
new file mode 100644
index 0000000..2cd8d72
--- /dev/null
+++ b/libj2_ju_mul_j2u_to_j2u_overflow_p.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_p(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res, int *res_set);
+/* TODO Add man page */
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */
+
+#endif
diff --git a/libj2_ju_rsh_to_j2u.c b/libj2_ju_rsh_to_j2u.c
index 7c5913f..5c4c891 100644
--- a/libj2_ju_rsh_to_j2u.c
+++ b/libj2_ju_rsh_to_j2u.c
@@ -93,6 +93,8 @@ check(const char *pattern)
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));
+
+ EXPECT(libj2_ju_rsh_underflow_p(a.low, i) == underflows);
}
}
diff --git a/libj2_ju_rsh_underflow_p.c b/libj2_ju_rsh_underflow_p.c
new file mode 100644
index 0000000..e5bd73d
--- /dev/null
+++ b/libj2_ju_rsh_underflow_p.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline int libj2_ju_rsh_underflow_p(uintmax_t a, unsigned b);
+/* 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_overflow_p.c b/libj2_ju_sub_j2u_overflow_p.c
new file mode 100644
index 0000000..90fe79c
--- /dev/null
+++ b/libj2_ju_sub_j2u_overflow_p.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_overflow_p(uintmax_t a, const struct libj2_j2u *b);
+/* 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_overflow_p.c b/libj2_ju_sub_ju_overflow_p.c
new file mode 100644
index 0000000..05bc298
--- /dev/null
+++ b/libj2_ju_sub_ju_overflow_p.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_overflow_p(uintmax_t a, uintmax_t b);
+/* 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_sub_ju_to_j2u.c b/libj2_ju_sub_ju_to_j2u.c
index b61e96a..5de5046 100644
--- a/libj2_ju_sub_ju_to_j2u.c
+++ b/libj2_ju_sub_ju_to_j2u.c
@@ -36,6 +36,8 @@ check(uintmax_t a, uintmax_t b)
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));
+
+ EXPECT(libj2_ju_sub_ju_overflow_p(a, b) == expected_overflow);
}