aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2025-12-06 16:13:53 +0100
committerMattias Andrée <m@maandree.se>2025-12-06 16:13:53 +0100
commitbc03a666203de25faf6246847fecbc8502267212 (patch)
tree080080b24980640c6d4935a4684bf78b4d2d3077
parentAdd division with underflow detection (diff)
downloadlibj2-bc03a666203de25faf6246847fecbc8502267212.tar.gz
libj2-bc03a666203de25faf6246847fecbc8502267212.tar.bz2
libj2-bc03a666203de25faf6246847fecbc8502267212.tar.xz
Add saturated arithmetic operations
Signed-off-by: Mattias Andrée <m@maandree.se>
-rw-r--r--Makefile29
-rw-r--r--libj2.h1
-rw-r--r--libj2/addition.h10
-rw-r--r--libj2/bit-shifting.h36
-rw-r--r--libj2/saturated-math.h633
-rw-r--r--libj2/subtraction.h26
-rw-r--r--libj2_j2u_add_j2u.c40
-rw-r--r--libj2_j2u_add_ju.c93
-rw-r--r--libj2_j2u_lsh.c13
-rw-r--r--libj2_j2u_mul_j2u_destructive.c34
-rw-r--r--libj2_j2u_mul_ju.c22
-rw-r--r--libj2_j2u_sat_add_j2u.c13
-rw-r--r--libj2_j2u_sat_add_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_sat_add_ju.c13
-rw-r--r--libj2_j2u_sat_add_ju_to_j2u.c13
-rw-r--r--libj2_j2u_sat_lsh.c13
-rw-r--r--libj2_j2u_sat_lsh_to_j2u.c13
-rw-r--r--libj2_j2u_sat_mul_j2u.c13
-rw-r--r--libj2_j2u_sat_mul_j2u_destructive.c13
-rw-r--r--libj2_j2u_sat_mul_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_sat_mul_ju.c13
-rw-r--r--libj2_j2u_sat_mul_ju_to_j2u.c13
-rw-r--r--libj2_j2u_sat_rsub_j2u.c13
-rw-r--r--libj2_j2u_sat_rsub_ju.c13
-rw-r--r--libj2_j2u_sat_sub_j2u.c13
-rw-r--r--libj2_j2u_sat_sub_j2u_to_j2u.c13
-rw-r--r--libj2_j2u_sat_sub_ju.c13
-rw-r--r--libj2_j2u_sat_sub_ju_to_j2u.c13
-rw-r--r--libj2_j2u_sub_j2u.c50
-rw-r--r--libj2_j2u_sub_ju.c47
-rw-r--r--libj2_ju_lsh_to_j2u.c4
-rw-r--r--libj2_ju_sat_add_j2u_to_j2u.c13
-rw-r--r--libj2_ju_sat_lsh_to_j2u.c13
-rw-r--r--libj2_ju_sat_mul_j2u_to_j2u.c13
-rw-r--r--libj2_ju_sat_sub_j2u_to_j2u.c13
-rw-r--r--libj2_ju_sat_sub_ju_to_j2u.c13
-rw-r--r--libj2_ju_sub_ju_to_j2u.c4
37 files changed, 1288 insertions, 40 deletions
diff --git a/Makefile b/Makefile
index 7cf9041..82f60d0 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@ include mk/$(OS).mk
LIB_MAJOR = 1
-LIB_MINOR = 0
+LIB_MINOR = 1
LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR)
LIB_NAME = j2
@@ -276,7 +276,29 @@ OBJ =\
libj2_j2u_div_j2u_to_j2u_underflow.o\
libj2_j2u_rdiv_j2u_underflow.o\
libj2_j2u_div_ju_underflow.o\
- libj2_j2u_div_ju_to_j2u_underflow.o
+ libj2_j2u_div_ju_to_j2u_underflow.o\
+ libj2_j2u_sat_lsh.o\
+ libj2_j2u_sat_lsh_to_j2u.o\
+ libj2_ju_sat_lsh_to_j2u.o\
+ libj2_j2u_sat_add_ju.o\
+ libj2_j2u_sat_add_ju_to_j2u.o\
+ libj2_ju_sat_add_j2u_to_j2u.o\
+ libj2_j2u_sat_add_j2u.o\
+ libj2_j2u_sat_add_j2u_to_j2u.o\
+ libj2_j2u_sat_sub_ju.o\
+ libj2_j2u_sat_sub_ju_to_j2u.o\
+ libj2_ju_sat_sub_ju_to_j2u.o\
+ libj2_j2u_sat_sub_j2u.o\
+ libj2_j2u_sat_sub_j2u_to_j2u.o\
+ libj2_ju_sat_sub_j2u_to_j2u.o\
+ libj2_j2u_sat_rsub_j2u.o\
+ libj2_j2u_sat_rsub_ju.o\
+ libj2_j2u_sat_mul_ju.o\
+ libj2_j2u_sat_mul_ju_to_j2u.o\
+ libj2_ju_sat_mul_j2u_to_j2u.o\
+ libj2_j2u_sat_mul_j2u_destructive.o\
+ libj2_j2u_sat_mul_j2u.o\
+ libj2_j2u_sat_mul_j2u_to_j2u.o
SUBHDR =\
libj2/constants.h\
@@ -290,7 +312,8 @@ SUBHDR =\
libj2/addition.h\
libj2/subtraction.h\
libj2/multiplication.h\
- libj2/division.h
+ libj2/division.h\
+ libj2/saturated-math.h
HDR =\
$(SUBHDR)\
diff --git a/libj2.h b/libj2.h
index bb4832b..a413327 100644
--- a/libj2.h
+++ b/libj2.h
@@ -98,6 +98,7 @@ enum libj2_overflow {
#include "libj2/subtraction.h"
#include "libj2/multiplication.h"
#include "libj2/division.h"
+#include "libj2/saturated-math.h"
#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
diff --git a/libj2/addition.h b/libj2/addition.h
index 033284e..48df7d4 100644
--- a/libj2/addition.h
+++ b/libj2/addition.h
@@ -294,11 +294,11 @@ libj2_j2u_add_j2u_overflow(struct libj2_j2u *a, const struct libj2_j2u *b)
* `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
+ * @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
*
* @since 1.0
*/
diff --git a/libj2/bit-shifting.h b/libj2/bit-shifting.h
index acceb4c..c31674f 100644
--- a/libj2/bit-shifting.h
+++ b/libj2/bit-shifting.h
@@ -5,7 +5,7 @@
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in an unsigned double-max precision
* integer to more signficant positions (left-shift)
*
* Bits shifted out of precision will be discarded,
@@ -41,7 +41,7 @@ libj2_j2u_lsh(struct libj2_j2u *a, unsigned b)
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in an unsigned double-max precision
* integer to more signficant positions (left-shift)
*
* Bits shifted out of precision will be discarded,
@@ -68,7 +68,7 @@ libj2_j2u_lsh_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *re
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in 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)
@@ -105,7 +105,7 @@ libj2_ju_lsh_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res)
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in an unsigned double-max precision
* integer to more signficant positions (left-shift)
*
* Bits shifted out of precision will be discarded,
@@ -157,7 +157,7 @@ libj2_j2u_lsh_overflow(struct libj2_j2u *a, unsigned b)
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in an unsigned double-max precision
* integer to more signficant positions (left-shift)
*
* Bits shifted out of precision will be discarded,
@@ -187,7 +187,7 @@ libj2_j2u_lsh_to_j2u_overflow(const struct libj2_j2u *a, unsigned b, struct libj
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in 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)
@@ -220,7 +220,7 @@ libj2_ju_lsh_to_j2u_overflow(uintmax_t a, unsigned b, struct libj2_j2u *res)
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in an unsigned double-max precision
* integer to less signficant positions (right-shift)
*
* Bits shifted out of precision will be discarded,
@@ -256,7 +256,7 @@ libj2_j2u_rsh(struct libj2_j2u *a, unsigned b)
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in an unsigned double-max precision
* integer to less signficant positions (right-shift)
*
* Bits shifted out of precision will be discarded,
@@ -283,7 +283,7 @@ libj2_j2u_rsh_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *re
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in 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)
@@ -313,7 +313,7 @@ libj2_ju_rsh_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res)
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in an unsigned double-max precision
* integer to less signficant positions (right-shift)
*
* Bits shifted out of precision will be discarded,
@@ -365,7 +365,7 @@ libj2_j2u_rsh_underflow(struct libj2_j2u *a, unsigned b)
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in an unsigned double-max precision
* integer to less signficant positions (right-shift)
*
* Bits shifted out of precision will be discarded,
@@ -395,7 +395,7 @@ libj2_j2u_rsh_to_j2u_underflow(const struct libj2_j2u *a, unsigned b, struct lib
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in 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)
@@ -428,7 +428,7 @@ libj2_ju_rsh_to_j2u_underflow(uintmax_t a, unsigned b, struct libj2_j2u *res)
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in an unsigned double-max precision
* integer to more signficant positions
*
* Bits shifted out of precision are wrapped around
@@ -466,7 +466,7 @@ libj2_j2u_lrot(struct libj2_j2u *a, unsigned b)
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in an unsigned double-max precision
* integer to more signficant positions
*
* Bits shifted out of precision are wrapped around
@@ -491,7 +491,7 @@ libj2_j2u_lrot_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *r
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in 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
@@ -519,7 +519,7 @@ libj2_ju_lrot_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res)
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in an unsigned double-max precision
* integer to less signficant positions
*
* Bits shifted out of precision are wrapped around
@@ -557,7 +557,7 @@ libj2_j2u_rrot(struct libj2_j2u *a, unsigned b)
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in an unsigned double-max precision
* integer to less signficant positions
*
* Bits shifted out of precision are wrapped around
@@ -582,7 +582,7 @@ libj2_j2u_rrot_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *r
/**
- * Shift the bits an unsigned double-max precision
+ * Shift the bits in 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
diff --git a/libj2/saturated-math.h b/libj2/saturated-math.h
new file mode 100644
index 0000000..9812e9b
--- /dev/null
+++ b/libj2/saturated-math.h
@@ -0,0 +1,633 @@
+/* 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 in an unsigned double-max precision
+ * integer to more signficant positions (left-shift)
+ *
+ * If any set bit is shifted out of precision, it will
+ * be regarded an arithmetic overflow, and the result
+ * will be saturated to the maximum value that can be
+ * represented
+ *
+ * `libj2_j2u_sat_lsh` is a version `libj2_j2u_lsh`
+ * that uses saturated arithmetics
+ *
+ * This is equivalent to multiplying `a` by the `b`th
+ * power of 2, using satured multiplication
+ *
+ * @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
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_lsh(struct libj2_j2u *a, unsigned b)
+{
+ if (libj2_j2u_lsh_overflow(a, b))
+ libj2_j2u_max(a);
+}
+
+
+/**
+ * Shift the bits in an unsigned double-max precision
+ * integer to more signficant positions (left-shift)
+ *
+ * If any set bit is shifted out of precision, it will
+ * be regarded an arithmetic overflow, and the result
+ * will be saturated to the maximum value that can be
+ * represented
+ *
+ * `libj2_j2u_sat_lsh_to_j2u` is a version
+ * `libj2_j2u_lsh_to_j2u` that uses saturated arithmetics
+ *
+ * This is equivalent to multiplying `a` by the `b`th
+ * power of 2, using satured multiplication
+ *
+ * @param a The integer to shift
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_lsh_to_j2u(const struct libj2_j2u *a, unsigned b, struct libj2_j2u *res)
+{
+ if (libj2_j2u_lsh_to_j2u_overflow(a, b, res))
+ libj2_j2u_max(res);
+}
+
+
+/**
+ * Shift the bits in 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)
+ *
+ * If any set bit is shifted out of precision, it will
+ * be regarded an arithmetic overflow, and the result
+ * will be saturated to the maximum value that can be
+ * represented
+ *
+ * `libj2_ju_sat_lsh_to_j2u` is a version
+ * `libj2_ju_lsh_to_j2u` that uses saturated arithmetics
+ *
+ * This is equivalent to multiplying `a` by the `b`th
+ * power of 2, using satured multiplication
+ *
+ * @param a The integer to shift
+ * @param b The number of positions to shift each bit
+ * @param res Output parameter for the result
+ *
+ * @since 1.1
+ */
+inline void
+libj2_ju_sat_lsh_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res)
+{
+ if (libj2_ju_lsh_to_j2u_overflow(a, b, res))
+ libj2_j2u_max(res);
+}
+
+
+
+
+
+/**
+ * Calculate the saturated sum of an unsigned double-max
+ * precision integer and an unsigned max precision integer
+ *
+ * `libj2_j2u_sat_add_ju` is a version
+ * `libj2_j2u_add_ju` that uses saturated arithmetics,
+ * meaning that if the result is too large to be
+ * represented it is saturated into the maximum value
+ * that can be represented
+ *
+ * @param a The augend, and output parameter for the sum
+ * @param b The addend
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_add_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ if (libj2_j2u_add_ju_overflow(a, b))
+ libj2_j2u_max(a);
+}
+
+
+/**
+ * Calculate the saturated sum of an unsigned double-max
+ * precision integer and an unsigned max precision integer
+ *
+ * `libj2_j2u_sat_add_ju_to_j2u` is a version
+ * `libj2_j2u_add_ju_to_j2u` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the maximum value that can be represented
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_add_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ if (libj2_j2u_add_ju_to_j2u_overflow(a, b, res))
+ libj2_j2u_max(res);
+}
+
+
+/**
+ * Calculate the saturated sum of an unsigned max precision
+ * integer and an unsigned double-max precision integer
+ *
+ * `libj2_ju_sat_add_j2u_to_j2u` is a version
+ * `libj2_ju_add_j2u_to_j2u` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the maximum value that can be represented
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ *
+ * @since 1.1
+ */
+inline void
+libj2_ju_sat_add_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ if (libj2_ju_add_j2u_to_j2u_overflow(a, b, res))
+ libj2_j2u_max(res);
+}
+
+
+/**
+ * Calculate the saturated sum of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_sat_add_j2u` is a version
+ * `libj2_j2u_add_j2u` that uses saturated arithmetics,
+ * meaning that if the result is too large to be
+ * represented it is saturated into the maximum value
+ * that can be represented
+ *
+ * @param a The augend, and output parameter for the sum
+ * @param b The addend
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_add_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ if (libj2_j2u_add_j2u_overflow(a, b))
+ libj2_j2u_max(a);
+}
+
+
+/**
+ * Calculate the saturated sum of two unsigned double-max
+ * precision integers
+ *
+ * `libj2_j2u_sat_add_j2u_to_j2u` is a version
+ * `libj2_j2u_add_j2u_to_j2u` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the maximum value that can be represented
+ *
+ * @param a The augend
+ * @param b The addend
+ * @param res Output parameter for the sum
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_add_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ if (libj2_j2u_add_j2u_to_j2u_overflow(a, b, res))
+ libj2_j2u_max(res);
+}
+
+
+
+
+
+/**
+ * Calculate the saturated difference between an
+ * unsigned double-max precision integer (minuend)
+ * and an unsigned max precision integer (subtrahend)
+ *
+ * `libj2_j2u_sat_sub_ju` is a version
+ * `libj2_j2u_sub_ju` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the value zero
+ *
+ * @param a The minuend (left-hand), also used as the
+ * output parameter for the difference
+ * @param b The subtrahend (right-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_sub_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ if (libj2_j2u_sub_ju_overflow(a, b))
+ libj2_j2u_min(a);
+}
+
+
+/**
+ * Calculate the saturated difference between an
+ * unsigned double-max precision integer (minuend)
+ * and an unsigned max precision integer (subtrahend)
+ *
+ * `libj2_j2u_sat_sub_ju_to_j2u` is a version
+ * `libj2_j2u_sub_ju_to_j2u` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the value zero
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @param res Output parameter for the difference
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_sub_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ if (libj2_j2u_sub_ju_to_j2u_overflow(a, b, res))
+ libj2_j2u_min(res);
+}
+
+
+/**
+ * Calculate the saturated difference between two unsigned
+ * max precision integers, as an unsigned double-max
+ * precision integer
+ *
+ * `libj2_ju_sat_sub_ju_to_j2u` is a version
+ * `libj2_ju_sub_ju_to_j2u` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the value zero
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @param res Output parameter for the difference
+ *
+ * @since 1.1
+ */
+inline void
+libj2_ju_sat_sub_ju_to_j2u(uintmax_t a, uintmax_t b, struct libj2_j2u *res)
+{
+ if (libj2_ju_sub_ju_to_j2u_overflow(a, b, res))
+ libj2_j2u_min(res);
+}
+
+
+/**
+ * Calculate the saturated difference between two
+ * unsigned double-max precision integers
+ *
+ * `libj2_j2u_sat_sub_j2u` is a version
+ * `libj2_j2u_sub_j2u` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the value zero
+ *
+ * @param a The minuend (left-hand), also used
+ * as the output parameter for the difference
+ * @param b The subtrahend (right-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_sub_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ if (libj2_j2u_sub_j2u_overflow(a, b))
+ libj2_j2u_min(a);
+}
+
+
+/**
+ * Calculate the saturated difference between two
+ * unsigned double-max precision integers
+ *
+ * `libj2_j2u_sat_sub_j2u_to_j2u` is a version
+ * `libj2_j2u_sub_j2u_to_j2u` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the value zero
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @param res Output parameter for the difference
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_sub_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ if (libj2_j2u_sub_j2u_to_j2u_overflow(a, b, res))
+ libj2_j2u_min(res);
+}
+
+
+/**
+ * Calculate the saturated difference between an
+ * unsigned max precision integer (minuend) and an
+ * unsigned double-max precision integer (subtrahend)
+ *
+ * `libj2_ju_sat_sub_j2u_to_j2u` is a version
+ * `libj2_ju_sub_j2u_to_j2u` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the value zero
+ *
+ * @param a The minuend (left-hand)
+ * @param b The subtrahend (right-hand)
+ * @param res Output parameter for the difference
+ *
+ * @since 1.1
+ */
+inline void
+libj2_ju_sat_sub_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ if (libj2_ju_sub_j2u_to_j2u_overflow(a, b, res))
+ libj2_j2u_min(res);
+}
+
+
+/**
+ * Calculate the saturated 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_sat_rsub_j2u` is a version
+ * `libj2_j2u_rsub_j2u` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the value zero
+ *
+ * @param a The subtrahend (right-hand), also used as
+ * the output parameter for the difference
+ * @param b The minuend (left-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_rsub_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ if (libj2_j2u_rsub_j2u_overflow(a, b))
+ libj2_j2u_min(a);
+}
+
+
+/**
+ * Calculate the saturated 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_sat_rsub_ju` is a version
+ * `libj2_j2u_rsub_ju` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the value zero
+ *
+ * @param a The subtrahend (right-hand), also used as
+ * the output parameter for the difference
+ * @param b The minuend (left-hand)
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_rsub_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ if (libj2_j2u_rsub_ju_overflow(a, b))
+ libj2_j2u_min(a);
+}
+
+
+
+
+
+/**
+ * Calculate the saturated product of an unsigned
+ * double-max precision integer (multiplier) and an
+ * unsigned max precision integer (multiplicand)
+ *
+ * `libj2_j2u_sat_mul_ju` is a version
+ * `libj2_j2u_mul_ju` that uses saturated arithmetics,
+ * meaning that if the result is too large to be
+ * represented it is saturated into the maximum value
+ * that can be represented
+ *
+ * @param a The multiplier, also used as the
+ * output parameter for the product
+ * @param b The multiplicand
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_mul_ju(struct libj2_j2u *a, uintmax_t b)
+{
+ uintmax_t c;
+
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_mul_overflow(a->high, b, &c))
+ goto overflow;
+#else
+ if (b && a->high > UINTMAX_MAX / b)
+ goto overflow;
+ c = a->high * b;
+#endif
+
+ libj2_ju_mul_ju_to_j2u(a->low, b, a);
+
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_add_overflow(a->high, c, &a->high))
+ goto overflow;
+#else
+ if (a->high > UINTMAX_MAX - c)
+ goto overflow;
+ a->high += c;
+#endif
+
+ return;
+
+overflow:
+ libj2_j2u_max(a);
+}
+
+
+/**
+ * Calculate the saturated product of an unsigned
+ * double-max precision integer (multiplier) and an
+ * unsigned max precision integer (multiplicand)
+ *
+ * `libj2_j2u_sat_mul_ju_to_j2u` is a version
+ * `libj2_j2u_mul_ju_to_j2u` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the maximum value that can be represented
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_mul_ju_to_j2u(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res)
+{
+ *res = *a;
+ libj2_j2u_sat_mul_ju(res, b);
+}
+
+
+/**
+ * Calculate the saturated product of an unsigned
+ * max precision integer (multiplier) and an unsigned
+ * double-max precision integer (multiplicand)
+ *
+ * `libj2_ju_sat_mul_j2u_to_j2u` is a version
+ * `libj2_ju_mul_j2u_to_j2u` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the maximum value that can be represented
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ *
+ * @since 1.1
+ */
+inline void
+libj2_ju_sat_mul_j2u_to_j2u(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res)
+{
+ *res = *b;
+ libj2_j2u_sat_mul_ju(res, a);
+}
+
+
+/**
+ * Calculate the saturated product of two unsigned
+ * double-max precision integers
+ *
+ * `libj2_j2u_sat_mul_j2u_destructive` is a version
+ * `libj2_j2u_mul_j2u_destructive` that uses saturated
+ * arithmetics, meaning that if the result is too large
+ * to be represented it is saturated into the maximum
+ * value that can be represented
+ *
+ * @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
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_mul_j2u_destructive(struct libj2_j2u *restrict a /* result */, struct libj2_j2u *restrict b /* destructed */)
+{
+ if (a->high && b->high)
+ goto overflow;
+
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_mul_overflow(a->high, b->low, &a->high))
+ goto overflow;
+ if (__builtin_mul_overflow(b->high, a->low, &b->high))
+ goto overflow;
+ if (__builtin_add_overflow(b->high, a->high, &b->high))
+ goto overflow;
+#else
+ if (b->low && a->high > UINTMAX_MAX / b->low)
+ goto overflow;
+ a->high *= b->low;
+ if (a->low && b->high > UINTMAX_MAX / a->low)
+ goto overflow;
+ b->high *= a->low;
+ if (b->high > UINTMAX_MAX - a->high)
+ goto overflow;
+ b->high += a->high;
+#endif
+
+ libj2_ju_mul_ju_to_j2u(a->low, b->low, a);
+
+#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_)
+ if (__builtin_add_overflow(a->high, b->high, &a->high))
+ goto overflow;
+#else
+ if (a->high > UINTMAX_MAX - b->high)
+ goto overflow;
+ a->high += b->high;
+#endif
+
+ return;
+
+overflow:
+ libj2_j2u_max(a);
+}
+
+
+/**
+ * Calculate the saturated product of two unsigned
+ * double-max precision integers
+ *
+ * `libj2_j2u_sat_mul_j2u` is a version
+ * `libj2_j2u_mul_j2u` that uses saturated arithmetics,
+ * meaning that if the result is too large to be
+ * represented it is saturated into the maximum value
+ * that can be represented
+ *
+ * @param a The multiplier, also used as the
+ * output parameter for the product
+ * @param b The multiplicand
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_mul_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
+{
+ struct libj2_j2u c = *b;
+ libj2_j2u_sat_mul_j2u_destructive(a, &c);
+}
+
+
+/**
+ * Calculate the saturated product of two unsigned
+ * double-max precision integers
+ *
+ * `libj2_j2u_sat_mul_j2u_to_j2u` is a version
+ * `libj2_j2u_mul_j2u_to_j2u` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the maximum value that can be represented
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2u_sat_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_sat_mul_j2u_destructive(res, &c);
+}
diff --git a/libj2/subtraction.h b/libj2/subtraction.h
index 9c2f775..5d4ee2e 100644
--- a/libj2/subtraction.h
+++ b/libj2/subtraction.h
@@ -141,7 +141,7 @@ libj2_j2u_sub_ju_to_j2u_overflow(const struct libj2_j2u *a, uintmax_t b, struct
* max precision integers, as an unsigned double-max
* precision integer
*
- * `libj2_ju_sub_ju_to_j2u_overflow(a, b, res)`
+ * `libj2_ju_sub_ju_to_j2u(a, b, res)`
* implements `*res = a - b`, where `a` and `b`
* are converted into `struct libj2_j2u`'s
*
@@ -419,12 +419,12 @@ libj2_j2u_rsub_j2u(struct libj2_j2u *a, const struct libj2_j2u *b)
* `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
+ * @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
*
* @since 1.0
*/
@@ -494,12 +494,12 @@ libj2_j2u_rsub_ju(struct libj2_j2u *a, uintmax_t b)
* `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
+ * @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
*
* @since 1.0
*/
diff --git a/libj2_j2u_add_j2u.c b/libj2_j2u_add_j2u.c
index 8aca375..5f26629 100644
--- a/libj2_j2u_add_j2u.c
+++ b/libj2_j2u_add_j2u.c
@@ -64,6 +64,12 @@ check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low,
a = a_saved;
b = b_saved;
+ libj2_j2u_sat_add_j2u(&a, &b);
+ EXPECT(r_overflow ? libj2_j2u_is_max(&a) : 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));
@@ -87,6 +93,26 @@ check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low,
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));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ b = b_saved;
+ libj2_j2u_sat_add_j2u_to_j2u(&a, &b, &r);
+ EXPECT(r_overflow ? libj2_j2u_is_max(&r) : 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_sat_add_j2u_to_j2u(&a, &b, &a);
+ EXPECT(r_overflow ? libj2_j2u_is_max(&a) : libj2_j2u_eq_j2u(&a, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2u_sat_add_j2u_to_j2u(&a, &b, &b);
+ EXPECT(r_overflow ? libj2_j2u_is_max(&b) : libj2_j2u_eq_j2u(&b, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
}
@@ -160,6 +186,10 @@ check_double(uintmax_t high, uintmax_t low)
EXPECT(libj2_j2u_eq_j2u(&a, &expected));
a = a_saved;
+ libj2_j2u_sat_add_j2u(&a, &a);
+ EXPECT(expected_overflow ? libj2_j2u_is_max(&a) : 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));
@@ -172,6 +202,16 @@ check_double(uintmax_t high, uintmax_t low)
a = a_saved;
EXPECT(libj2_j2u_add_j2u_to_j2u_overflow(&a, &a, &a) == expected_overflow);
EXPECT(libj2_j2u_eq_j2u(&a, &expected));
+
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ libj2_j2u_sat_add_j2u_to_j2u(&a, &a, &r);
+ EXPECT(expected_overflow ? libj2_j2u_is_max(&r) : libj2_j2u_eq_j2u(&r, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+
+ a = a_saved;
+ libj2_j2u_sat_add_j2u_to_j2u(&a, &a, &a);
+ EXPECT(expected_overflow ? libj2_j2u_is_max(&a) : libj2_j2u_eq_j2u(&a, &expected));
}
diff --git a/libj2_j2u_add_ju.c b/libj2_j2u_add_ju.c
index f368857..1b6458f 100644
--- a/libj2_j2u_add_ju.c
+++ b/libj2_j2u_add_ju.c
@@ -36,6 +36,11 @@ check_zero_low(uintmax_t high, uintmax_t low)
EXPECT(a.low == low);
a = (struct libj2_j2u){.high = high, .low = 0};
+ libj2_j2u_sat_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_p((const struct libj2_j2u *)&a, low) == 0);
EXPECT(a.high == high);
EXPECT(a.low == 0);
@@ -68,6 +73,19 @@ check_zero_low(uintmax_t high, uintmax_t low)
r = (struct libj2_j2u){111, 222};
a = (struct libj2_j2u){.high = high, .low = 0};
+ libj2_j2u_sat_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_sat_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};
libj2_ju_add_j2u_to_j2u(low, &a, &r);
EXPECT(a.high == high);
EXPECT(a.low == 0);
@@ -92,6 +110,19 @@ check_zero_low(uintmax_t high, uintmax_t low)
EXPECT(a.high == high);
EXPECT(a.low == low);
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = high, .low = 0};
+ libj2_ju_sat_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_sat_add_j2u_to_j2u(low, &a, &a);
+ 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);
@@ -118,6 +149,11 @@ check_max_low(uintmax_t high, uintmax_t low)
EXPECT(a.low == expected_low);
a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ libj2_j2u_sat_add_ju(&a, low);
+ EXPECT(a.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(a.low == (expected_overflow ? UINTMAX_MAX : 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);
@@ -150,6 +186,19 @@ check_max_low(uintmax_t high, uintmax_t low)
r = (struct libj2_j2u){111, 222};
a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ libj2_j2u_sat_add_ju_to_j2u(&a, low, &r);
+ EXPECT(a.high == high);
+ EXPECT(a.low == UINTMAX_MAX);
+ EXPECT(r.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(r.low == (expected_overflow ? UINTMAX_MAX : expected_low));
+
+ a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ libj2_j2u_sat_add_ju_to_j2u(&a, low, &a);
+ EXPECT(a.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(a.low == (expected_overflow ? UINTMAX_MAX : 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);
@@ -174,6 +223,19 @@ check_max_low(uintmax_t high, uintmax_t low)
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_sat_add_j2u_to_j2u(low, &a, &r);
+ EXPECT(a.high == high);
+ EXPECT(a.low == UINTMAX_MAX);
+ EXPECT(r.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(r.low == (expected_overflow ? UINTMAX_MAX : expected_low));
+
+ a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX};
+ libj2_ju_sat_add_j2u_to_j2u(low, &a, &a);
+ EXPECT(a.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(a.low == (expected_overflow ? UINTMAX_MAX : 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);
@@ -227,6 +289,11 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b)
EXPECT(a.low == expected_low);
a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_sat_add_ju(&a, b);
+ EXPECT(a.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(a.low == (expected_overflow ? UINTMAX_MAX : 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);
@@ -259,6 +326,19 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b)
r = (struct libj2_j2u){111, 222};
a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_sat_add_ju_to_j2u(&a, b, &r);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(r.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(r.low == (expected_overflow ? UINTMAX_MAX : expected_low));
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_sat_add_ju_to_j2u(&a, b, &a);
+ EXPECT(a.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(a.low == (expected_overflow ? UINTMAX_MAX : 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);
@@ -283,6 +363,19 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b)
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_sat_add_j2u_to_j2u(b, &a, &r);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(r.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(r.low == (expected_overflow ? UINTMAX_MAX : expected_low));
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_ju_sat_add_j2u_to_j2u(b, &a, &a);
+ EXPECT(a.high == (expected_overflow ? UINTMAX_MAX : expected_high));
+ EXPECT(a.low == (expected_overflow ? UINTMAX_MAX : 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);
diff --git a/libj2_j2u_lsh.c b/libj2_j2u_lsh.c
index 914c3b2..3d4f7fd 100644
--- a/libj2_j2u_lsh.c
+++ b/libj2_j2u_lsh.c
@@ -127,6 +127,10 @@ check(const char *pattern)
EXPECT(libj2_j2u_eq_j2u(&r, &expected));
r = a;
+ libj2_j2u_sat_lsh(&r, i);
+ EXPECT(overflows ? libj2_j2u_is_max(&r) : 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));
@@ -140,6 +144,11 @@ check(const char *pattern)
EXPECT(libj2_j2u_eq_j2u(&r, &expected));
EXPECT(libj2_j2u_eq_j2u(&a, &a_saved));
+ r = (struct libj2_j2u){111, 222};
+ libj2_j2u_sat_lsh_to_j2u(&a, i, &r);
+ EXPECT(overflows ? libj2_j2u_is_max(&r) : 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));
@@ -147,6 +156,10 @@ check(const char *pattern)
r = a;
EXPECT(libj2_j2u_lsh_to_j2u_overflow(&r, i, &r) == overflows);
EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+
+ r = a;
+ libj2_j2u_sat_lsh_to_j2u(&r, i, &r);
+ EXPECT(overflows ? libj2_j2u_is_max(&r) : libj2_j2u_eq_j2u(&r, &expected));
}
}
diff --git a/libj2_j2u_mul_j2u_destructive.c b/libj2_j2u_mul_j2u_destructive.c
index ba986da..04b4428 100644
--- a/libj2_j2u_mul_j2u_destructive.c
+++ b/libj2_j2u_mul_j2u_destructive.c
@@ -89,6 +89,11 @@ 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_sat_mul_j2u(&t, b);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : 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));
@@ -137,6 +142,22 @@ mul_(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *exp
EXPECT(libj2_j2u_eq_j2u(&t, expected));
EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ t = (struct libj2_j2u){111, 222};
+ libj2_j2u_sat_mul_j2u_to_j2u(a, b, &t);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+
+ t = *a;
+ libj2_j2u_sat_mul_j2u_to_j2u(&t, b, &t);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(b, &b_saved));
+
+ t = *b;
+ libj2_j2u_sat_mul_j2u_to_j2u(a, &t, &t);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+
t = *a;
x = *b;
libj2_j2u_mul_j2u_destructive(&t, &x);
@@ -147,6 +168,11 @@ mul_(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *exp
EXPECT(libj2_j2u_mul_j2u_overflow_destructive(&t, &x) == expect_overflow);
EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ t = *a;
+ x = *b;
+ libj2_j2u_sat_mul_j2u_destructive(&t, &x);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
+
if (a == b) {
t = *a;
libj2_j2u_mul_j2u(&t, &t);
@@ -161,6 +187,10 @@ mul_(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *exp
EXPECT(libj2_j2u_eq_j2u(&t, expected));
t = *a;
+ libj2_j2u_sat_mul_j2u(&t, &t);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : 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));
@@ -178,6 +208,10 @@ mul_(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *exp
t = *a;
EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow(&t, &t, &t) == expect_overflow);
EXPECT(libj2_j2u_eq_j2u(&t, expected));
+
+ t = *a;
+ libj2_j2u_sat_mul_j2u_to_j2u(&t, &t, &t);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
}}
diff --git a/libj2_j2u_mul_ju.c b/libj2_j2u_mul_ju.c
index 6be737c..33eabba 100644
--- a/libj2_j2u_mul_ju.c
+++ b/libj2_j2u_mul_ju.c
@@ -83,6 +83,10 @@ mul(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *expected, int expe
EXPECT(libj2_j2u_eq_j2u(&t, expected));
t = *a;
+ libj2_j2u_sat_mul_ju(&t, b);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : 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));
@@ -115,6 +119,15 @@ mul(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *expected, int expe
EXPECT(libj2_j2u_eq_j2u(&t, expected));
t = (struct libj2_j2u){111, 222};
+ libj2_j2u_sat_mul_ju_to_j2u(a, b, &t);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+
+ t = *a;
+ libj2_j2u_sat_mul_ju_to_j2u(&t, b, &t);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
+
+ 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));
@@ -123,6 +136,15 @@ mul(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *expected, int expe
EXPECT(libj2_ju_mul_j2u_to_j2u_overflow(b, &t, &t) == expect_overflow);
EXPECT(libj2_j2u_eq_j2u(&t, expected));
+ t = (struct libj2_j2u){111, 222};
+ libj2_ju_sat_mul_j2u_to_j2u(b, a, &t);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
+ EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+
+ t = *a;
+ libj2_ju_sat_mul_j2u_to_j2u(b, &t, &t);
+ EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
+
set = 999;
t = (struct libj2_j2u){111, 222};
t_saved = t;
diff --git a/libj2_j2u_sat_add_j2u.c b/libj2_j2u_sat_add_j2u.c
new file mode 100644
index 0000000..d45033f
--- /dev/null
+++ b/libj2_j2u_sat_add_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_sat_add_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_add_j2u.c */
+
+#endif
diff --git a/libj2_j2u_sat_add_j2u_to_j2u.c b/libj2_j2u_sat_add_j2u_to_j2u.c
new file mode 100644
index 0000000..7bc5be6
--- /dev/null
+++ b/libj2_j2u_sat_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_sat_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_sat_add_ju.c b/libj2_j2u_sat_add_ju.c
new file mode 100644
index 0000000..4479457
--- /dev/null
+++ b/libj2_j2u_sat_add_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_sat_add_ju(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_sat_add_ju_to_j2u.c b/libj2_j2u_sat_add_ju_to_j2u.c
new file mode 100644
index 0000000..c975416
--- /dev/null
+++ b/libj2_j2u_sat_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_sat_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_sat_lsh.c b/libj2_j2u_sat_lsh.c
new file mode 100644
index 0000000..c665c83
--- /dev/null
+++ b/libj2_j2u_sat_lsh.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_sat_lsh(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_sat_lsh_to_j2u.c b/libj2_j2u_sat_lsh_to_j2u.c
new file mode 100644
index 0000000..41b7c73
--- /dev/null
+++ b/libj2_j2u_sat_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_sat_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_sat_mul_j2u.c b/libj2_j2u_sat_mul_j2u.c
new file mode 100644
index 0000000..f683f97
--- /dev/null
+++ b/libj2_j2u_sat_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_sat_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_sat_mul_j2u_destructive.c b/libj2_j2u_sat_mul_j2u_destructive.c
new file mode 100644
index 0000000..0a34fbb
--- /dev/null
+++ b/libj2_j2u_sat_mul_j2u_destructive.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_sat_mul_j2u_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_sat_mul_j2u_to_j2u.c b/libj2_j2u_sat_mul_j2u_to_j2u.c
new file mode 100644
index 0000000..d807ebb
--- /dev/null
+++ b/libj2_j2u_sat_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_sat_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_sat_mul_ju.c b/libj2_j2u_sat_mul_ju.c
new file mode 100644
index 0000000..feda494
--- /dev/null
+++ b/libj2_j2u_sat_mul_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_sat_mul_ju(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_sat_mul_ju_to_j2u.c b/libj2_j2u_sat_mul_ju_to_j2u.c
new file mode 100644
index 0000000..8d5d545
--- /dev/null
+++ b/libj2_j2u_sat_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_sat_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_sat_rsub_j2u.c b/libj2_j2u_sat_rsub_j2u.c
new file mode 100644
index 0000000..f03ded2
--- /dev/null
+++ b/libj2_j2u_sat_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_sat_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_sat_rsub_ju.c b/libj2_j2u_sat_rsub_ju.c
new file mode 100644
index 0000000..f431f38
--- /dev/null
+++ b/libj2_j2u_sat_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_sat_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_sat_sub_j2u.c b/libj2_j2u_sat_sub_j2u.c
new file mode 100644
index 0000000..e3e1b37
--- /dev/null
+++ b/libj2_j2u_sat_sub_j2u.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_sat_sub_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_sat_sub_j2u_to_j2u.c b/libj2_j2u_sat_sub_j2u_to_j2u.c
new file mode 100644
index 0000000..da41aea
--- /dev/null
+++ b/libj2_j2u_sat_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_sat_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_sat_sub_ju.c b/libj2_j2u_sat_sub_ju.c
new file mode 100644
index 0000000..376ec94
--- /dev/null
+++ b/libj2_j2u_sat_sub_ju.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2u_sat_sub_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_sat_sub_ju_to_j2u.c b/libj2_j2u_sat_sub_ju_to_j2u.c
new file mode 100644
index 0000000..6cadeee
--- /dev/null
+++ b/libj2_j2u_sat_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_sat_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_j2u.c b/libj2_j2u_sub_j2u.c
index bd645e2..d69fb02 100644
--- a/libj2_j2u_sub_j2u.c
+++ b/libj2_j2u_sub_j2u.c
@@ -64,6 +64,12 @@ check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low,
a = a_saved;
b = b_saved;
+ libj2_j2u_sat_sub_j2u(&a, &b);
+ EXPECT(r_overflow ? libj2_j2u_is_zero(&a) : 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));
@@ -88,6 +94,26 @@ 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;
+ libj2_j2u_sat_sub_j2u_to_j2u(&a, &b, &r);
+ EXPECT(r_overflow ? libj2_j2u_is_zero(&r) : 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_sat_sub_j2u_to_j2u(&a, &b, &a);
+ EXPECT(r_overflow ? libj2_j2u_is_zero(&a) : libj2_j2u_eq_j2u(&a, &expected));
+ EXPECT(libj2_j2u_eq_j2u(&b, &b_saved));
+
+ a = a_saved;
+ b = b_saved;
+ libj2_j2u_sat_sub_j2u_to_j2u(&a, &b, &b);
+ EXPECT(r_overflow ? libj2_j2u_is_zero(&b) : 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);
@@ -102,6 +128,12 @@ check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low,
a = a_saved;
b = b_saved;
+ libj2_j2u_sat_rsub_j2u(&b, &a);
+ EXPECT(r_overflow ? libj2_j2u_is_zero(&b) : 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));
@@ -161,6 +193,10 @@ check_double(uintmax_t high, uintmax_t low)
EXPECT(libj2_j2u_is_zero(&a));
a = a_saved;
+ libj2_j2u_sat_sub_j2u(&a, &a);
+ 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));
@@ -174,6 +210,16 @@ check_double(uintmax_t high, uintmax_t low)
EXPECT(libj2_j2u_sub_j2u_to_j2u_overflow(&a, &a, &a) == 0);
EXPECT(libj2_j2u_is_zero(&a));
+ r = (struct libj2_j2u){111, 222};
+ a = a_saved;
+ libj2_j2u_sat_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_sat_sub_j2u_to_j2u(&a, &a, &a);
+ EXPECT(libj2_j2u_is_zero(&a));
+
a = a_saved;
libj2_j2u_rsub_j2u(&a, &a);
EXPECT(libj2_j2u_is_zero(&a));
@@ -183,6 +229,10 @@ check_double(uintmax_t high, uintmax_t low)
EXPECT(libj2_j2u_is_zero(&a));
a = a_saved;
+ libj2_j2u_sat_rsub_j2u(&a, &a);
+ 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_ju.c b/libj2_j2u_sub_ju.c
index 0cd0343..651cd1c 100644
--- a/libj2_j2u_sub_ju.c
+++ b/libj2_j2u_sub_ju.c
@@ -42,6 +42,10 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b)
EXPECT(libj2_j2u_eq_j2u(&a, &expected));
a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_sat_sub_ju(&a, b);
+ EXPECT(expected_overflow ? libj2_j2u_is_zero(&a) : 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);
@@ -70,6 +74,17 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b)
r = (struct libj2_j2u){111, 222};
a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_sat_sub_ju_to_j2u(&a, b, &r);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ EXPECT(expected_overflow ? libj2_j2u_is_zero(&r) : libj2_j2u_eq_j2u(&r, &expected));
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_sat_sub_ju_to_j2u(&a, b, &a);
+ EXPECT(expected_overflow ? libj2_j2u_is_zero(&a) : 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);
@@ -92,6 +107,15 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b)
EXPECT(libj2_j2u_eq_j2u(&a, &expected));
a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_j2u_sat_rsub_ju(&a, b);
+ if (expected_roverflow) {
+ EXPECT(libj2_j2u_is_zero(&a));
+ } else {
+ 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);
@@ -107,7 +131,28 @@ 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));
+
+ r = (struct libj2_j2u){111, 222};
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_ju_sat_sub_j2u_to_j2u(b, &a, &r);
+ EXPECT(a.high == a_high);
+ EXPECT(a.low == a_low);
+ if (expected_roverflow) {
+ EXPECT(libj2_j2u_is_zero(&r));
+ } else {
+ libj2_minus_j2u(&r);
+ EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ }
+
+ a = (struct libj2_j2u){.high = a_high, .low = a_low};
+ libj2_ju_sat_sub_j2u_to_j2u(b, &a, &a);
+ if (expected_roverflow) {
+ EXPECT(libj2_j2u_is_zero(&a));
+ } else {
+ libj2_minus_j2u(&a);
+ 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);
diff --git a/libj2_ju_lsh_to_j2u.c b/libj2_ju_lsh_to_j2u.c
index ca05fbf..d2495e1 100644
--- a/libj2_ju_lsh_to_j2u.c
+++ b/libj2_ju_lsh_to_j2u.c
@@ -143,6 +143,10 @@ check(const char *pattern)
EXPECT(libj2_ju_lsh_to_j2u_overflow(a.low, i, &r) == overflows);
EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_sat_lsh_to_j2u(a.low, i, &r);
+ EXPECT(overflows ? libj2_j2u_is_max(&r) : libj2_j2u_eq_j2u(&r, &expected));
+
EXPECT(libj2_ju_lsh_overflow_p(a.low, i) == overflows);
}
}
diff --git a/libj2_ju_sat_add_j2u_to_j2u.c b/libj2_ju_sat_add_j2u_to_j2u.c
new file mode 100644
index 0000000..c2623fd
--- /dev/null
+++ b/libj2_ju_sat_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_sat_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_sat_lsh_to_j2u.c b/libj2_ju_sat_lsh_to_j2u.c
new file mode 100644
index 0000000..9841109
--- /dev/null
+++ b/libj2_ju_sat_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_ju_sat_lsh_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_lsh_to_j2u.c */
+
+#endif
diff --git a/libj2_ju_sat_mul_j2u_to_j2u.c b/libj2_ju_sat_mul_j2u_to_j2u.c
new file mode 100644
index 0000000..b86dfc7
--- /dev/null
+++ b/libj2_ju_sat_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_sat_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_sat_sub_j2u_to_j2u.c b/libj2_ju_sat_sub_j2u_to_j2u.c
new file mode 100644
index 0000000..9245de9
--- /dev/null
+++ b/libj2_ju_sat_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_sat_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_sat_sub_ju_to_j2u.c b/libj2_ju_sat_sub_ju_to_j2u.c
new file mode 100644
index 0000000..34549c7
--- /dev/null
+++ b/libj2_ju_sat_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_ju_sat_sub_ju_to_j2u(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_sub_ju_to_j2u.c b/libj2_ju_sub_ju_to_j2u.c
index 5de5046..cedc6f3 100644
--- a/libj2_ju_sub_ju_to_j2u.c
+++ b/libj2_ju_sub_ju_to_j2u.c
@@ -37,6 +37,10 @@ check(uintmax_t a, uintmax_t b)
EXPECT(libj2_ju_sub_ju_to_j2u_overflow(a, b, &r) == expected_overflow);
EXPECT(libj2_j2u_eq_j2u(&r, &expected));
+ r = (struct libj2_j2u){111, 222};
+ libj2_ju_sat_sub_ju_to_j2u(a, b, &r);
+ EXPECT(expected_overflow ? libj2_j2u_is_zero(&r) : libj2_j2u_eq_j2u(&r, &expected));
+
EXPECT(libj2_ju_sub_ju_overflow_p(a, b) == expected_overflow);
}