aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2026-02-11 11:20:10 +0100
committerMattias Andrée <m@maandree.se>2026-02-11 11:20:10 +0100
commit0d4c3e8f6be098e953502589b17cb28197322442 (patch)
treedf3a13e786769e78d3d6201150f4018dc0c22cb5
parentTest sat_add (diff)
downloadlibj2-0d4c3e8f6be098e953502589b17cb28197322442.tar.gz
libj2-0d4c3e8f6be098e953502589b17cb28197322442.tar.bz2
libj2-0d4c3e8f6be098e953502589b17cb28197322442.tar.xz
Finish signed saturated math
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to '')
-rw-r--r--Makefile7
-rw-r--r--README32
-rw-r--r--libj2.740
-rw-r--r--libj2.h2
-rw-r--r--libj2/saturated-math.h146
-rw-r--r--libj2_j2i_add_j2i.331
-rw-r--r--libj2_j2i_lsh.323
-rw-r--r--libj2_j2i_lsh.c21
-rw-r--r--libj2_j2i_mul_j2i.338
-rw-r--r--libj2_j2i_mul_j2i.c43
-rw-r--r--libj2_j2i_mul_ji.c39
l---------libj2_j2i_sat_add_j2i.31
-rw-r--r--libj2_j2i_sat_add_j2i.c7
l---------libj2_j2i_sat_lsh.31
-rw-r--r--libj2_j2i_sat_lsh.c7
-rw-r--r--libj2_j2i_sat_lsh_to_j2i.c2
l---------libj2_j2i_sat_mul_j2i.31
-rw-r--r--libj2_j2i_sat_mul_j2i.c12
l---------libj2_j2i_sat_mul_j2i_to_j2i.31
-rw-r--r--libj2_j2i_sat_mul_j2i_to_j2i.c12
l---------libj2_j2i_sat_mul_ji.31
-rw-r--r--libj2_j2i_sat_mul_ji.c12
l---------libj2_j2i_sat_mul_ji_to_j2i.31
-rw-r--r--libj2_j2i_sat_mul_ji_to_j2i.c12
-rw-r--r--libj2_j2i_sat_rsub_j2i.c2
-rw-r--r--libj2_j2i_sat_rsub_ji.c2
l---------libj2_j2i_sat_sub_j2i.31
-rw-r--r--libj2_j2i_sat_sub_j2i.c11
-rw-r--r--libj2_j2i_sat_sub_j2i_to_j2i.c2
-rw-r--r--libj2_j2i_sat_sub_ji.c2
-rw-r--r--libj2_j2i_sat_sub_ji_to_j2i.c2
-rw-r--r--libj2_j2i_sub_j2i.333
-rw-r--r--libj2_j2i_sub_j2i.c45
-rw-r--r--libj2_j2i_sub_ji.c29
l---------libj2_j2u_sat_add_j2u.31
-rw-r--r--libj2_j2u_sat_add_j2u.c7
l---------libj2_j2u_sat_lsh.31
-rw-r--r--libj2_j2u_sat_lsh.c5
l---------libj2_j2u_sat_mul_j2u.31
-rw-r--r--libj2_j2u_sat_mul_j2u.c8
l---------libj2_j2u_sat_sub_j2u.31
-rw-r--r--libj2_j2u_sat_sub_j2u.c10
-rw-r--r--libj2_j2u_sub_j2u.338
-rw-r--r--libj2_ji_sat_lsh_to_j2i.c2
l---------libj2_ji_sat_mul_j2i_to_j2i.31
-rw-r--r--libj2_ji_sat_mul_j2i_to_j2i.c12
-rw-r--r--libj2_ji_sat_sub_j2i_to_j2i.c2
47 files changed, 599 insertions, 111 deletions
diff --git a/Makefile b/Makefile
index d81787a..46770a1 100644
--- a/Makefile
+++ b/Makefile
@@ -521,7 +521,12 @@ OBJ =\
libj2_j2i_sat_sub_j2i_to_j2i.o\
libj2_ji_sat_sub_j2i_to_j2i.o\
libj2_j2i_sat_rsub_j2i.o\
- libj2_j2i_sat_rsub_ji.o
+ libj2_j2i_sat_rsub_ji.o\
+ libj2_j2i_sat_mul_j2i.o\
+ libj2_j2i_sat_mul_j2i_to_j2i.o\
+ libj2_j2i_sat_mul_ji.o\
+ libj2_j2i_sat_mul_ji_to_j2i.o\
+ libj2_ji_sat_mul_j2i_to_j2i.o
SUBHDR =\
libj2/constants.h\
diff --git a/README b/README
index c29bb6e..058794a 100644
--- a/README
+++ b/README
@@ -261,8 +261,9 @@ DESCRIPTION
libj2_ji_lsh_overflow_p(3), libj2_ju_lsh_overflow_p(3)
Predict overflow of left-shifting a value.
- libj2_j2u_sat_lsh(3), libj2_j2u_sat_lsh_to_j2u(3),
- libj2_ju_sat_lsh_to_j2u(3)
+ libj2_j2i_sat_lsh(3), libj2_j2i_sat_lsh_to_j2i(3),
+ libj2_ji_sat_lsh_to_j2i(3), libj2_j2u_sat_lsh(3),
+ libj2_j2u_sat_lsh_to_j2u(3), libj2_ju_sat_lsh_to_j2u(3)
Left-shift a value, but saturate on overflow.
libj2_j2i_rsh(3), libj2_j2i_rsh_to_j2i(3), libj2_ji_rsh_to_j2i(3),
@@ -360,9 +361,11 @@ DESCRIPTION
libj2_j2u_add_ju_overflow_p(3), libj2_ju_add_j2u_overflow_p(3)
Predict whether adding two values will result in an overflow.
- libj2_j2u_sat_add_j2u(3), libj2_j2u_sat_add_j2u_to_j2u(3),
- libj2_j2u_sat_add_ju(3), libj2_j2u_sat_add_ju_to_j2u(3),
- libj2_ju_sat_add_j2u_to_j2u(3)
+ libj2_j2i_sat_add_j2i(3), libj2_j2i_sat_add_j2i_to_j2i(3),
+ libj2_j2i_sat_add_ji(3), libj2_j2i_sat_add_ji_to_j2i(3),
+ libj2_ji_sat_add_j2i_to_j2i(3), libj2_j2u_sat_add_j2u(3),
+ libj2_j2u_sat_add_j2u_to_j2u(3), libj2_j2u_sat_add_ju(3),
+ libj2_j2u_sat_add_ju_to_j2u(3), libj2_ju_sat_add_j2u_to_j2u(3)
Calculate the sum of two values, but saturate on overflow.
libj2_j2i_sub_j2i(3), libj2_j2i_sub_j2i_to_j2i(3),
@@ -403,12 +406,16 @@ DESCRIPTION
Predict whether subtracting a value will result in an overflow.
These functions swap the position of the two operands.
- libj2_j2u_sat_sub_j2u(3), libj2_j2u_sat_sub_j2u_to_j2u(3),
- libj2_j2u_sat_sub_ju(3), libj2_j2u_sat_sub_ju_to_j2u(3),
- libj2_ju_sat_sub_j2u_to_j2u(3), libj2_ju_sat_sub_ju_to_j2u(3)
+ libj2_j2i_sat_sub_j2i(3), libj2_j2i_sat_sub_j2i_to_j2i(3),
+ libj2_j2i_sat_sub_ji(3), libj2_j2i_sat_sub_ji_to_j2i(3),
+ libj2_ji_sat_sub_j2i_to_j2i(3), libj2_j2u_sat_sub_j2u(3),
+ libj2_j2u_sat_sub_j2u_to_j2u(3), libj2_j2u_sat_sub_ju(3),
+ libj2_j2u_sat_sub_ju_to_j2u(3), libj2_ju_sat_sub_j2u_to_j2u(3),
+ libj2_ju_sat_sub_ju_to_j2u(3)
Calculate the difference between two values, but saturate on
overflow.
+ libj2_j2i_sat_rsub_j2i(3), libj2_j2i_sat_rsub_ji(3),
libj2_j2u_sat_rsub_j2u(3), libj2_j2u_sat_rsub_ju(3)
Calculate the difference between two values, but saturate on
overflow. These functions swap the position of the two operands.
@@ -455,9 +462,12 @@ DESCRIPTION
overflow, and if the prediction is costly, perform the
multiplication.
- libj2_j2u_sat_mul_j2u(3), libj2_j2u_sat_mul_j2u_to_j2u(3),
- libj2_j2u_sat_mul_ju(3), libj2_j2u_sat_mul_ju_to_j2u(3),
- libj2_ju_sat_mul_j2u_to_j2u(3), libj2_j2u_sat_mul_j2u_destructive(3)
+ libj2_j2i_sat_mul_j2i(3), libj2_j2i_sat_mul_j2i_to_j2i(3),
+ libj2_j2i_sat_mul_ji(3), libj2_j2i_sat_mul_ji_to_j2i(3),
+ libj2_ji_sat_mul_j2i_to_j2i(3), libj2_j2u_sat_mul_j2u(3),
+ libj2_j2u_sat_mul_j2u_to_j2u(3), libj2_j2u_sat_mul_ju(3),
+ libj2_j2u_sat_mul_ju_to_j2u(3), libj2_ju_sat_mul_j2u_to_j2u(3),
+ libj2_j2u_sat_mul_j2u_destructive(3)
Calculate the product of two values, but saturate on overflow.
libj2_j2i_divmod_j2i(3), libj2_j2i_divmod_j2i_to_j2i(3),
diff --git a/libj2.7 b/libj2.7
index 102e53e..ae0cccc 100644
--- a/libj2.7
+++ b/libj2.7
@@ -626,6 +626,12 @@ Left-shift a value, and detect overflow.
.BR libj2_ju_lsh_overflow_p (3)
Predict overflow of left-shifting a value.
.TP
+.BR libj2_j2i_sat_lsh (3),
+.TQ
+.BR libj2_j2i_sat_lsh_to_j2i (3),
+.TQ
+.BR libj2_ji_sat_lsh_to_j2i (3),
+.TQ
.BR libj2_j2u_sat_lsh (3),
.TQ
.BR libj2_j2u_sat_lsh_to_j2u (3),
@@ -811,6 +817,16 @@ Calculate the sum of two values, and detect overflow.
.BR libj2_ju_add_j2u_overflow_p (3)
Predict whether adding two values will result in an overflow.
.TP
+.BR libj2_j2i_sat_add_j2i (3),
+.TQ
+.BR libj2_j2i_sat_add_j2i_to_j2i (3),
+.TQ
+.BR libj2_j2i_sat_add_ji (3),
+.TQ
+.BR libj2_j2i_sat_add_ji_to_j2i (3),
+.TQ
+.BR libj2_ji_sat_add_j2i_to_j2i (3),
+.TQ
.BR libj2_j2u_sat_add_j2u (3),
.TQ
.BR libj2_j2u_sat_add_j2u_to_j2u (3),
@@ -916,6 +932,16 @@ Predict whether subtracting a value will result in an overflow.
Predict whether subtracting a value will result in an overflow.
These functions swap the position of the two operands.
.TP
+.BR libj2_j2i_sat_sub_j2i (3),
+.TQ
+.BR libj2_j2i_sat_sub_j2i_to_j2i (3),
+.TQ
+.BR libj2_j2i_sat_sub_ji (3),
+.TQ
+.BR libj2_j2i_sat_sub_ji_to_j2i (3),
+.TQ
+.BR libj2_ji_sat_sub_j2i_to_j2i (3),
+.TQ
.BR libj2_j2u_sat_sub_j2u (3),
.TQ
.BR libj2_j2u_sat_sub_j2u_to_j2u (3),
@@ -930,6 +956,10 @@ These functions swap the position of the two operands.
Calculate the difference between two values, but saturate on
overflow.
.TP
+.BR libj2_j2i_sat_rsub_j2i (3),
+.TQ
+.BR libj2_j2i_sat_rsub_ji (3),
+.TQ
.BR libj2_j2u_sat_rsub_j2u (3),
.TQ
.BR libj2_j2u_sat_rsub_ju (3)
@@ -1029,6 +1059,16 @@ Predict whether multiplying two values will result in an
overflow, and if the prediction is costly, perform the
multiplication.
.TP
+.BR libj2_j2i_sat_mul_j2i (3),
+.TQ
+.BR libj2_j2i_sat_mul_j2i_to_j2i (3),
+.TQ
+.BR libj2_j2i_sat_mul_ji (3),
+.TQ
+.BR libj2_j2i_sat_mul_ji_to_j2i (3),
+.TQ
+.BR libj2_ji_sat_mul_j2i_to_j2i (3),
+.TQ
.BR libj2_j2u_sat_mul_j2u (3),
.TQ
.BR libj2_j2u_sat_mul_j2u_to_j2u (3),
diff --git a/libj2.h b/libj2.h
index 1648c5e..8097746 100644
--- a/libj2.h
+++ b/libj2.h
@@ -166,7 +166,7 @@ enum libj2_overflow {
#include "libj2/subtraction.h"
#include "libj2/multiplication.h"
#include "libj2/division.h"
-#include "libj2/saturated-math.h" /* TODO add signed versions (mul) */
+#include "libj2/saturated-math.h"
#include "libj2/strings.h"
diff --git a/libj2/saturated-math.h b/libj2/saturated-math.h
index 0e5627f..9333a2f 100644
--- a/libj2/saturated-math.h
+++ b/libj2/saturated-math.h
@@ -1078,3 +1078,149 @@ libj2_j2u_sat_mul_j2u_to_j2u(const struct libj2_j2u *a, const struct libj2_j2u *
*res = *a;
libj2_j2u_sat_mul_j2u_destructive(res, &c);
}
+
+
+/**
+ * Calculate the saturated product of a signed
+ * double-max precision integer (multiplier) and a
+ * signed max precision integer (multiplicand)
+ *
+ * `libj2_j2i_sat_mul_ji` is a version
+ * `libj2_j2i_mul_ji` that uses saturated arithmetics,
+ * meaning that if the result is too large to be
+ * represented it is saturated into the maximum value
+ * (if positive) or minimum value (if negative) 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_j2i_sat_mul_ji(struct libj2_j2i *a, intmax_t b)
+{
+ int r = libj2_j2i_mul_ji_overflow(a, b);
+ if (r > 0)
+ libj2_j2i_max(a);
+ else if (r)
+ libj2_j2i_min(a);
+}
+
+
+/**
+ * Calculate the saturated product of a signed
+ * double-max precision integer (multiplier) and a
+ * signed max precision integer (multiplicand)
+ *
+ * `libj2_j2i_sat_mul_ji_to_j2i` is a version
+ * `libj2_j2i_mul_ji_to_j2i` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the maximum value (if positive) or minimum
+ * value (if negative) that can be represented
+ * can be represented
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_sat_mul_ji_to_j2i(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res)
+{
+ int r = libj2_j2i_mul_ji_to_j2i_overflow(a, b, res);
+ if (r > 0)
+ libj2_j2i_max(res);
+ else if (r)
+ libj2_j2i_min(res);
+}
+
+
+/**
+ * Calculate the saturated product of a signed
+ * max precision integer (multiplier) and a signed
+ * double-max precision integer (multiplicand)
+ *
+ * `libj2_ji_sat_mul_j2i_to_j2i` is a version
+ * `libj2_ji_mul_j2i_to_j2i` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the maximum value (if positive) or minimum
+ * value (if negative) that can be represented
+ * can be represented
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ *
+ * @since 1.1
+ */
+inline void
+libj2_ji_sat_mul_j2i_to_j2i(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ int r = libj2_ji_mul_j2i_to_j2i_overflow(a, b, res);
+ if (r > 0)
+ libj2_j2i_max(res);
+ else if (r)
+ libj2_j2i_min(res);
+}
+
+
+/**
+ * Calculate the saturated product of two signed
+ * double-max precision integers
+ *
+ * `libj2_j2i_sat_mul_j2i` is a version
+ * `libj2_j2i_mul_j2i` that uses saturated arithmetics,
+ * meaning that if the result is too large to be
+ * represented it is saturated into the maximum value
+ * (if positive) or minimum value (if negative) 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_j2i_sat_mul_j2i(struct libj2_j2i *a, const struct libj2_j2i *b)
+{
+ int r = libj2_j2i_mul_j2i_overflow(a, b);
+ if (r > 0)
+ libj2_j2i_max(a);
+ else if (r)
+ libj2_j2i_min(a);
+}
+
+
+/**
+ * Calculate the saturated product of two signed
+ * double-max precision integers
+ *
+ * `libj2_j2i_sat_mul_j2i_to_j2i` is a version
+ * `libj2_j2i_mul_j2i_to_j2i` that uses saturated
+ * arithmetics, meaning that if the result is too
+ * large to be represented it is saturated into
+ * the maximum value (if positive) or minimum
+ * value (if negative) that can be represented
+ * can be represented
+ *
+ * @param a The multiplier
+ * @param b The multiplicand
+ * @param res Output parameter for the product
+ *
+ * @since 1.1
+ */
+inline void
+libj2_j2i_sat_mul_j2i_to_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res)
+{
+ int r = libj2_j2i_mul_j2i_to_j2i_overflow(a, b, res);
+ if (r > 0)
+ libj2_j2i_max(res);
+ else if (r)
+ libj2_j2i_min(res);
+}
diff --git a/libj2_j2i_add_j2i.3 b/libj2_j2i_add_j2i.3
index 8dce9ba..df0debd 100644
--- a/libj2_j2i_add_j2i.3
+++ b/libj2_j2i_add_j2i.3
@@ -39,6 +39,18 @@ int \fBlibj2_ju_add_j2u_to_j2u_overflow\fP(uintmax_t \fIa\fP, const struct libj2
int \fBlibj2_j2u_add_j2u_overflow_p\fP(const struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP);
int \fBlibj2_j2u_add_ju_overflow_p\fP(const struct libj2_j2u *\fIa\fP, uintmax_t \fIb\fP);
int \fBlibj2_ju_add_j2u_overflow_p\fP(uintmax_t \fIa\fP, const struct libj2_j2u *\fIb\fP);
+
+void \fBlibj2_j2i_sat_add_j2i\fP(struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP);
+void \fBlibj2_j2i_sat_add_j2i_to_j2i\fP(const struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP, struct libj2_j2i *\fIr\fP);
+void \fBlibj2_j2i_sat_add_ji\fP(struct libj2_j2i *\fIa\fP, intmax_t \fIb\fP);
+void \fBlibj2_j2i_sat_add_ji_to_j2i\fP(const struct libj2_j2i *\fIa\fP, intmax_t \fIb\fP, struct libj2_j2i *\fIr\fP);
+void \fBlibj2_ji_sat_add_j2i_to_j2i\fP(intmax_t \fIa\fP, const struct libj2_j2i *\fIb\fP, struct libj2_j2i *\fIr\fP);
+
+void \fBlibj2_j2u_sat_add_j2u\fP(struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP);
+void \fBlibj2_j2u_sat_add_j2u_to_j2u\fP(const struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP, struct libj2_j2u *\fIr\fP);
+void \fBlibj2_j2u_sat_add_ju\fP(struct libj2_j2u *\fIa\fP, uintmax_t \fIb\fP);
+void \fBlibj2_j2u_sat_add_ju_to_j2u\fP(const struct libj2_j2u *\fIa\fP, uintmax_t \fIb\fP, struct libj2_j2u *\fIr\fP);
+void \fBlibj2_ju_sat_add_j2u_to_j2u\fP(uintmax_t \fIa\fP, const struct libj2_j2u *\fIb\fP, struct libj2_j2u *\fIr\fP);
.fi
.PP
Link with
@@ -74,7 +86,12 @@ in their name), detect arithmetic overflow.
.PP
The result is truncated to the least significant
bits, as many as can be stored, in case of overflow;
-that is, modular arithmetics is used.
+that is, modular arithmetics is used. However, the
+.BR sat_add -functions
+use saturated arithmetics, meaning that the result
+will be the maximum representable value on positive
+overflow and the minimum representable value on
+negative overflow.
.PP
The arguments are assumed to be
.RI non- NULL .
@@ -124,8 +141,18 @@ The
.BR libj2_ji_add_j2i_to_j2i_overflow (),
.BR libj2_j2i_add_j2i_overflow_p (),
.BR libj2_j2i_add_ji_overflow_p (),
+.BR libj2_ji_add_j2i_overflow_p (),
+.BR libj2_j2i_sat_add_j2i (),
+.BR libj2_j2i_sat_add_j2i_to_j2i (),
+.BR libj2_j2i_sat_add_ji (),
+.BR libj2_j2i_sat_add_ji_to_j2i (),
+.BR libj2_ji_sat_add_j2i_to_j2i (),
+.BR libj2_j2u_sat_add_j2u (),
+.BR libj2_j2u_sat_add_j2u_to_j2u (),
+.BR libj2_j2u_sat_add_ju (),
+.BR libj2_j2u_sat_add_ju_to_j2u (),
and
-.BR libj2_ji_add_j2i_overflow_p ()
+.BR libj2_ju_sat_add_j2u_to_j2u ()
functions were added in version 1.1 of
.BR libj2 .
diff --git a/libj2_j2i_lsh.3 b/libj2_j2i_lsh.3
index 26c2455..aa89dbd 100644
--- a/libj2_j2i_lsh.3
+++ b/libj2_j2i_lsh.3
@@ -27,6 +27,14 @@ int \fBlibj2_ju_lsh_to_j2u_overflow\fP(uintmax_t \fIa\fP, unsigned \fIb\fP, stru
int \fBlibj2_j2u_lsh_overflow_p\fP(const struct libj2_j2u *\fIa\fP, unsigned \fIb\fP);
int \fBlibj2_ju_lsh_overflow_p\fP(uintmax_t \fIa\fP, unsigned \fIb\fP);
+
+void \fBlibj2_j2i_sat_lsh\fP(struct libj2_j2i *\fIa\fP, unsigned \fIb\fP);
+void \fBlibj2_j2i_sat_lsh_to_j2i\fP(const struct libj2_j2i *\fIa\fP, unsigned \fIb\fP, struct libj2_j2i *\fIr\fP);
+void \fBlibj2_ji_sat_lsh_to_j2i\fP(intmax_t \fIa\fP, unsigned \fIb\fP, struct libj2_j2i *\fIr\fP);
+
+void \fBlibj2_j2u_sat_lsh\fP(struct libj2_j2u *\fIa\fP, unsigned \fIb\fP);
+void \fBlibj2_j2u_sat_lsh_to_j2u\fP(const struct libj2_j2u *\fIa\fP, unsigned \fIb\fP, struct libj2_j2u *\fIr\fP);
+void \fBlibj2_ju_sat_lsh_to_j2u\fP(uintmax_t \fIa\fP, unsigned \fIb\fP, struct libj2_j2u *\fIr\fP);
.fi
.PP
Link with
@@ -83,6 +91,13 @@ if any discarded bit (any of the
.I b
most significant bits) was set.
.PP
+The
+.BR sat_lsh -functions
+use saturated arithmetics, meaning that the result
+will be the maximum representable value on positive
+overflow and the minimum representable value on
+negative overflow.
+.PP
The arguments are assumed to be
.RI non- NULL .
@@ -120,8 +135,14 @@ The
.BR libj2_j2i_lsh_to_j2i_overflow (),
.BR libj2_ji_lsh_to_j2i_overflow (),
.BR libj2_j2i_lsh_overflow_p (),
+.BR libj2_ji_lsh_overflow_p (),
+.BR libj2_j2i_sat_lsh (),
+.BR libj2_j2i_sat_lsh_to_j2i (),
+.BR libj2_ji_sat_lsh_to_j2i (),
+.BR libj2_j2u_sat_lsh (),
+.BR libj2_j2u_sat_lsh_to_j2u (),
and
-.BR libj2_ji_lsh_overflow_p ()
+.BR libj2_ju_sat_lsh_to_j2u ()
functions were added in version 1.1 of
.BR libj2 .
diff --git a/libj2_j2i_lsh.c b/libj2_j2i_lsh.c
index 053ece7..aff86bb 100644
--- a/libj2_j2i_lsh.c
+++ b/libj2_j2i_lsh.c
@@ -25,6 +25,11 @@ check(const struct libj2_j2i *a, unsigned shift, const struct libj2_j2i *expecte
EXPECT(libj2_j2i_lsh_overflow(&r, shift) == overflow);
EXPECT(libj2_j2i_eq_j2i(&r, expected));
+ r = *a;
+ libj2_j2i_sat_lsh(&r, shift);
+ EXPECT(overflow > 0 ? libj2_j2i_is_max(&r) :
+ overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, expected));
+
r = (struct libj2_j2i){111, 222};
libj2_j2i_lsh_to_j2i((const struct libj2_j2i *)a, shift, &r);
EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
@@ -43,6 +48,17 @@ check(const struct libj2_j2i *a, unsigned shift, const struct libj2_j2i *expecte
EXPECT(libj2_j2i_lsh_to_j2i_overflow(&r, shift, &r) == overflow);
EXPECT(libj2_j2i_eq_j2i(&r, expected));
+ r = (struct libj2_j2i){111, 222};
+ libj2_j2i_sat_lsh_to_j2i((const struct libj2_j2i *)a, shift, &r);
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
+ EXPECT(overflow > 0 ? libj2_j2i_is_max(&r) :
+ overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, expected));
+
+ r = *a;
+ libj2_j2i_sat_lsh_to_j2i(&r, shift, &r);
+ EXPECT(overflow > 0 ? libj2_j2i_is_max(&r) :
+ overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, expected));
+
if (libj2_j2i_is_negative(a)) {
if (a->high != UINTMAX_MAX || ~a->low > UINTMAX_MAX >> 1)
return;
@@ -62,6 +78,11 @@ check(const struct libj2_j2i *a, unsigned shift, const struct libj2_j2i *expecte
r = (struct libj2_j2i){111, 222};
EXPECT(libj2_ji_lsh_to_j2i_overflow(v, shift, &r) == overflow);
EXPECT(libj2_j2i_eq_j2i(&r, expected));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_sat_lsh_to_j2i(v, shift, &r);
+ EXPECT(overflow > 0 ? libj2_j2i_is_max(&r) :
+ overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, expected));
}
diff --git a/libj2_j2i_mul_j2i.3 b/libj2_j2i_mul_j2i.3
index d8ff10e..b77b77c 100644
--- a/libj2_j2i_mul_j2i.3
+++ b/libj2_j2i_mul_j2i.3
@@ -68,6 +68,19 @@ enum libj2_overflow \fBlibj2_ju_mul_j2u_overflow_p_quick\fP(uintmax_t \fIa\fP, c
int \fBlibj2_j2u_mul_j2u_to_j2u_overflow_p\fP(const struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP, struct libj2_j2u *\fIr\fP, int *\fIr_set\fP);
int \fBlibj2_j2u_mul_ju_to_j2u_overflow_p\fP(const struct libj2_j2u *\fIa\fP, uintmax_t \fIb\fP, struct libj2_j2u *\fIr\fP, int *\fIr_set\fP);
int \fBlibj2_ju_mul_j2u_to_j2u_overflow_p\fP(uintmax_t \fIa\fP, const struct libj2_j2u *\fIb\fP, struct libj2_j2u *\fIr\fP, int *\fIr_set\fP);
+
+void \fBlibj2_j2i_sat_mul_j2i\fP(struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP);
+void \fBlibj2_j2i_sat_mul_j2i_to_j2i\fP(const struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP, struct libj2_j2i *\fIr\fP);
+void \fBlibj2_j2i_sat_mul_ji\fP(struct libj2_j2i *\fIa\fP, intmax_t \fIb\fP);
+void \fBlibj2_j2i_sat_mul_ji_to_j2i\fP(const struct libj2_j2i *\fIa\fP, intmax_t \fIb\fP, struct libj2_j2i *\fIr\fP);
+void \fBlibj2_ji_sat_mul_j2i_to_j2i\fP(intmax_t \fIa\fP, const struct libj2_j2i *\fIb\fP, struct libj2_j2i *\fIr\fP);
+
+void \fBlibj2_j2u_sat_mul_j2u\fP(struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP);
+void \fBlibj2_j2u_sat_mul_j2u_to_j2u\fP(const struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP, struct libj2_j2u *\fIr\fP);
+void \fBlibj2_j2u_sat_mul_ju\fP(struct libj2_j2u *\fIa\fP, uintmax_t \fIb\fP);
+void \fBlibj2_j2u_sat_mul_ju_to_j2u\fP(const struct libj2_j2u *\fIa\fP, uintmax_t \fIb\fP, struct libj2_j2u *\fIr\fP);
+void \fBlibj2_ju_sat_mul_j2u_to_j2u\fP(uintmax_t \fIa\fP, const struct libj2_j2u *\fIb\fP, struct libj2_j2u *\fIr\fP);
+void \fBlibj2_j2u_sat_mul_j2u_destructive\fP(struct libj2_j2u *restrict \fIa\fP, struct libj2_j2u *restrict \fIb\fP);
.fi
.PP
Link with
@@ -140,12 +153,18 @@ in their name), detect arithmetic overflow.
.PP
The result is truncated to the least significant
bits, as many as can be stored, in case of overflow;
-that is, modular arithmetics is used.
+that is, modular arithmetics is used. However, the
+.BR sat_mul -functions
+use saturated arithmetics, meaning that the result
+will be the maximum representable value on positive
+overflow and the minimum representable value on
+negative overflow.
.PP
The
-.BR libj2_j2u_mul_j2u_destructive ()
+.BR libj2_j2u_mul_j2u_destructive (),
+.BR libj2_j2u_mul_j2u_overflow_destructive (),
and
-.BR libj2_j2u_mul_j2u_overflow_destructive ()
+.BR libj2_j2u_sat_mul_j2u_destructive ()
functions modifies
.I b
arbitrarily, and do not support
@@ -257,8 +276,19 @@ The
.BR libj2_ji_mul_j2i_overflow_p_quick (),
.BR libj2_j2i_mul_j2i_to_j2i_overflow_p (),
.BR libj2_j2i_mul_ji_to_j2i_overflow_p (),
+.BR libj2_ji_mul_j2i_to_j2i_overflow_p (),
+.BR libj2_j2i_sat_mul_j2i (),
+.BR libj2_j2i_sat_mul_j2i_to_j2i (),
+.BR libj2_j2i_sat_mul_ji (),
+.BR libj2_j2i_sat_mul_ji_to_j2i (),
+.BR libj2_ji_sat_mul_j2i_to_j2i (),
+.BR libj2_j2u_sat_mul_j2u (),
+.BR libj2_j2u_sat_mul_j2u_destructive (),
+.BR libj2_j2u_sat_mul_j2u_to_j2u (),
+.BR libj2_j2u_sat_mul_ju (),
+.BR libj2_j2u_sat_mul_ju_to_j2u (),
and
-.BR libj2_ji_mul_j2i_to_j2i_overflow_p ()
+.BR libj2_ju_sat_mul_j2u_to_j2u ()
functions and the
.IR LIBJ2_POSITIVE_OVERFLOW ,
.IR LIBJ2_POSITIVE_OVERFLOW_UNKNOWN ,
diff --git a/libj2_j2i_mul_j2i.c b/libj2_j2i_mul_j2i.c
index ff93594..11b3228 100644
--- a/libj2_j2i_mul_j2i.c
+++ b/libj2_j2i_mul_j2i.c
@@ -72,6 +72,24 @@ check_double(uintmax_t a_high, uintmax_t a_low, struct libj2_j2i *r_out)
EXPECT(libj2_j2i_mul_j2i_overflow(&r, CONST_ARG &r) == expected_overflow);
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+
+ r = (struct libj2_j2i){111, 222};
+ libj2_j2i_sat_mul_j2i_to_j2i(CONST_ARG &a, CONST_ARG &a, &r);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ libj2_j2i_sat_mul_j2i_to_j2i(CONST_ARG &r, CONST_ARG &r, &r);
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ libj2_j2i_sat_mul_j2i(&r, CONST_ARG &r);
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+
r = (struct libj2_j2i){111, 222};
libj2_j2i_mul_j2i_to_j2i(CONST_ARG &a, CONST_ARG &a, &r);
EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
@@ -138,6 +156,13 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low)
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
r = (struct libj2_j2i){111, 222};
+ libj2_j2i_sat_mul_j2i_to_j2i(CONST_ARG &a, CONST_ARG &b, &r);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+ r = (struct libj2_j2i){111, 222};
libj2_j2i_mul_j2i_to_j2i(CONST_ARG &a, CONST_ARG &b, &r);
EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
@@ -149,6 +174,12 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low)
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
r = a;
+ libj2_j2i_sat_mul_j2i_to_j2i(CONST_ARG &r, CONST_ARG &b, &r);
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
libj2_j2i_mul_j2i_to_j2i(CONST_ARG &r, CONST_ARG &b, &r);
EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
@@ -159,6 +190,12 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low)
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
r = b;
+ libj2_j2i_sat_mul_j2i_to_j2i(CONST_ARG &a, CONST_ARG &r, &r);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+ r = b;
libj2_j2i_mul_j2i_to_j2i(CONST_ARG &a, CONST_ARG &r, &r);
EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
@@ -169,6 +206,12 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low)
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
r = a;
+ libj2_j2i_sat_mul_j2i(&r, CONST_ARG &b);
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
libj2_j2i_mul_j2i(&r, CONST_ARG &b);
EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
diff --git a/libj2_j2i_mul_ji.c b/libj2_j2i_mul_ji.c
index e451f6a..9c7ac3c 100644
--- a/libj2_j2i_mul_ji.c
+++ b/libj2_j2i_mul_ji.c
@@ -100,11 +100,10 @@ mul_(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *expected, int expe
EXPECT(libj2_j2i_mul_ji_overflow(&t, b) == expect_overflow);
EXPECT(libj2_j2i_eq_j2i(&t, expected));
-#if 0 /* TODO saturated multiplication */
t = *a;
- libj2_j2u_sat_mul_ju(&t, b);
- EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
-#endif
+ libj2_j2i_sat_mul_ji(&t, b);
+ EXPECT(expect_overflow > 0 ? libj2_j2i_is_max(&t) :
+ expect_overflow ? libj2_j2i_is_min(&t) : libj2_j2i_eq_j2i(&t, expected));
t = *a;
EXPECT(libj2_j2i_mul_ji_overflow_p((const struct libj2_j2i *)&t, b) == expect_overflow);
@@ -138,16 +137,16 @@ mul_(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *expected, int expe
EXPECT(libj2_j2i_mul_ji_to_j2i_overflow(&t, b, &t) == expect_overflow);
EXPECT(libj2_j2i_eq_j2i(&t, expected));
-#if 0 /* TODO saturated multiplication */
- t = (struct libj2_j2u){111, 222};
- libj2_j2u_sat_mul_ju_to_j2u(a, b, &t);
- EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
- EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ t = (struct libj2_j2i){111, 222};
+ libj2_j2i_sat_mul_ji_to_j2i(a, b, &t);
+ EXPECT(expect_overflow > 0 ? libj2_j2i_is_max(&t) :
+ expect_overflow ? libj2_j2i_is_min(&t) : libj2_j2i_eq_j2i(&t, expected));
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
t = *a;
- libj2_j2u_sat_mul_ju_to_j2u(&t, b, &t);
- EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
-#endif
+ libj2_j2i_sat_mul_ji_to_j2i(&t, b, &t);
+ EXPECT(expect_overflow > 0 ? libj2_j2i_is_max(&t) :
+ expect_overflow ? libj2_j2i_is_min(&t) : libj2_j2i_eq_j2i(&t, expected));
t = (struct libj2_j2i){111, 222};
EXPECT(libj2_ji_mul_j2i_to_j2i_overflow(b, a, &t) == expect_overflow);
@@ -158,16 +157,16 @@ mul_(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *expected, int expe
EXPECT(libj2_ji_mul_j2i_to_j2i_overflow(b, &t, &t) == expect_overflow);
EXPECT(libj2_j2i_eq_j2i(&t, expected));
-#if 0 /* TODO saturated multiplication */
- t = (struct libj2_j2u){111, 222};
- libj2_ju_sat_mul_j2u_to_j2u(b, a, &t);
- EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
- EXPECT(libj2_j2u_eq_j2u(a, &a_saved));
+ t = (struct libj2_j2i){111, 222};
+ libj2_ji_sat_mul_j2i_to_j2i(b, a, &t);
+ EXPECT(expect_overflow > 0 ? libj2_j2i_is_max(&t) :
+ expect_overflow ? libj2_j2i_is_min(&t) : libj2_j2i_eq_j2i(&t, expected));
+ EXPECT(libj2_j2i_eq_j2i(a, &a_saved));
t = *a;
- libj2_ju_sat_mul_j2u_to_j2u(b, &t, &t);
- EXPECT(expect_overflow ? libj2_j2u_is_max(&t) : libj2_j2u_eq_j2u(&t, expected));
-#endif
+ libj2_ji_sat_mul_j2i_to_j2i(b, &t, &t);
+ EXPECT(expect_overflow > 0 ? libj2_j2i_is_max(&t) :
+ expect_overflow ? libj2_j2i_is_min(&t) : libj2_j2i_eq_j2i(&t, expected));
set = 999;
t = (struct libj2_j2i){111, 222};
diff --git a/libj2_j2i_sat_add_j2i.3 b/libj2_j2i_sat_add_j2i.3
new file mode 120000
index 0000000..668244f
--- /dev/null
+++ b/libj2_j2i_sat_add_j2i.3
@@ -0,0 +1 @@
+libj2_j2i_add_j2i.3 \ No newline at end of file
diff --git a/libj2_j2i_sat_add_j2i.c b/libj2_j2i_sat_add_j2i.c
index f3f263d..faae5a9 100644
--- a/libj2_j2i_sat_add_j2i.c
+++ b/libj2_j2i_sat_add_j2i.c
@@ -3,13 +3,6 @@
#ifndef TEST
extern inline void libj2_j2i_sat_add_j2i(struct libj2_j2i *a, const struct libj2_j2i *b);
-/* TODO Add man pages
- * libj2_j2i_sat_add_j2i
- * libj2_j2i_sat_add_j2i_to_j2i
- * libj2_j2i_sat_add_ji
- * libj2_j2i_sat_add_ji_to_j2i
- * libj2_ji_sat_add_j2i_to_j2i
- */
#else
diff --git a/libj2_j2i_sat_lsh.3 b/libj2_j2i_sat_lsh.3
new file mode 120000
index 0000000..7b89b30
--- /dev/null
+++ b/libj2_j2i_sat_lsh.3
@@ -0,0 +1 @@
+libj2_j2i_lsh.3 \ No newline at end of file
diff --git a/libj2_j2i_sat_lsh.c b/libj2_j2i_sat_lsh.c
index 49f5818..b19c835 100644
--- a/libj2_j2i_sat_lsh.c
+++ b/libj2_j2i_sat_lsh.c
@@ -3,15 +3,10 @@
#ifndef TEST
extern inline void libj2_j2i_sat_lsh(struct libj2_j2i *a, unsigned b);
-/* TODO Add man pages
- * libj2_j2i_sat_lsh
- * libj2_j2i_sat_lsh_to_j2i
- * libj2_ji_sat_lsh_to_j2i
- */
#else
-CONST int main(void) { return 0; } /* TODO test */
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_lsh.c */
#endif
diff --git a/libj2_j2i_sat_lsh_to_j2i.c b/libj2_j2i_sat_lsh_to_j2i.c
index 476f2e5..ac50792 100644
--- a/libj2_j2i_sat_lsh_to_j2i.c
+++ b/libj2_j2i_sat_lsh_to_j2i.c
@@ -7,6 +7,6 @@ extern inline void libj2_j2i_sat_lsh_to_j2i(const struct libj2_j2i *a, unsigned
#else
-CONST int main(void) { return 0; } /* TODO test */
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_lsh.c */
#endif
diff --git a/libj2_j2i_sat_mul_j2i.3 b/libj2_j2i_sat_mul_j2i.3
new file mode 120000
index 0000000..c7c2849
--- /dev/null
+++ b/libj2_j2i_sat_mul_j2i.3
@@ -0,0 +1 @@
+libj2_j2i_mul_j2i.3 \ No newline at end of file
diff --git a/libj2_j2i_sat_mul_j2i.c b/libj2_j2i_sat_mul_j2i.c
new file mode 100644
index 0000000..837d7f6
--- /dev/null
+++ b/libj2_j2i_sat_mul_j2i.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_sat_mul_j2i(struct libj2_j2i *a, const struct libj2_j2i *b);
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_j2i.c */
+
+#endif
diff --git a/libj2_j2i_sat_mul_j2i_to_j2i.3 b/libj2_j2i_sat_mul_j2i_to_j2i.3
new file mode 120000
index 0000000..6e1cee4
--- /dev/null
+++ b/libj2_j2i_sat_mul_j2i_to_j2i.3
@@ -0,0 +1 @@
+libj2_j2i_sat_mul_j2i.3 \ No newline at end of file
diff --git a/libj2_j2i_sat_mul_j2i_to_j2i.c b/libj2_j2i_sat_mul_j2i_to_j2i.c
new file mode 100644
index 0000000..a4a4363
--- /dev/null
+++ b/libj2_j2i_sat_mul_j2i_to_j2i.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_sat_mul_j2i_to_j2i(const struct libj2_j2i *a, const struct libj2_j2i *b, struct libj2_j2i *res);
+
+
+#else
+
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_mul_j2i.c */
+
+#endif
diff --git a/libj2_j2i_sat_mul_ji.3 b/libj2_j2i_sat_mul_ji.3
new file mode 120000
index 0000000..6e1cee4
--- /dev/null
+++ b/libj2_j2i_sat_mul_ji.3
@@ -0,0 +1 @@
+libj2_j2i_sat_mul_j2i.3 \ No newline at end of file
diff --git a/libj2_j2i_sat_mul_ji.c b/libj2_j2i_sat_mul_ji.c
new file mode 100644
index 0000000..da8b2c1
--- /dev/null
+++ b/libj2_j2i_sat_mul_ji.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_sat_mul_ji(struct libj2_j2i *a, intmax_t b);
+
+
+#else
+
+CONST int main(void) { return 0; }
+
+#endif
diff --git a/libj2_j2i_sat_mul_ji_to_j2i.3 b/libj2_j2i_sat_mul_ji_to_j2i.3
new file mode 120000
index 0000000..6e1cee4
--- /dev/null
+++ b/libj2_j2i_sat_mul_ji_to_j2i.3
@@ -0,0 +1 @@
+libj2_j2i_sat_mul_j2i.3 \ No newline at end of file
diff --git a/libj2_j2i_sat_mul_ji_to_j2i.c b/libj2_j2i_sat_mul_ji_to_j2i.c
new file mode 100644
index 0000000..d00a98c
--- /dev/null
+++ b/libj2_j2i_sat_mul_ji_to_j2i.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_j2i_sat_mul_ji_to_j2i(const struct libj2_j2i *a, intmax_t b, struct libj2_j2i *res);
+
+
+#else
+
+CONST int main(void) { return 0; }
+
+#endif
diff --git a/libj2_j2i_sat_rsub_j2i.c b/libj2_j2i_sat_rsub_j2i.c
index 3d7853f..5e3a0c1 100644
--- a/libj2_j2i_sat_rsub_j2i.c
+++ b/libj2_j2i_sat_rsub_j2i.c
@@ -7,6 +7,6 @@ extern inline void libj2_j2i_sat_rsub_j2i(struct libj2_j2i *a, const struct libj
#else
-CONST int main(void) { return 0; } /* TODO test */
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_j2i.c */
#endif
diff --git a/libj2_j2i_sat_rsub_ji.c b/libj2_j2i_sat_rsub_ji.c
index 91dfc5f..3b11390 100644
--- a/libj2_j2i_sat_rsub_ji.c
+++ b/libj2_j2i_sat_rsub_ji.c
@@ -7,6 +7,6 @@ extern inline void libj2_j2i_sat_rsub_ji(struct libj2_j2i *a, intmax_t b);
#else
-CONST int main(void) { return 0; } /* TODO test */
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_ji.c */
#endif
diff --git a/libj2_j2i_sat_sub_j2i.3 b/libj2_j2i_sat_sub_j2i.3
new file mode 120000
index 0000000..2bb1ba8
--- /dev/null
+++ b/libj2_j2i_sat_sub_j2i.3
@@ -0,0 +1 @@
+libj2_j2i_sub_j2i.3 \ No newline at end of file
diff --git a/libj2_j2i_sat_sub_j2i.c b/libj2_j2i_sat_sub_j2i.c
index 0ddda43..2b43af0 100644
--- a/libj2_j2i_sat_sub_j2i.c
+++ b/libj2_j2i_sat_sub_j2i.c
@@ -3,19 +3,10 @@
#ifndef TEST
extern inline void libj2_j2i_sat_sub_j2i(struct libj2_j2i *a, const struct libj2_j2i *b);
-/* TODO Add man pages
- * libj2_j2i_sat_sub_j2i
- * libj2_j2i_sat_sub_j2i_to_j2i
- * libj2_j2i_sat_sub_ji
- * libj2_j2i_sat_sub_ji_to_j2i
- * libj2_ji_sat_sub_j2i_to_j2i
- * libj2_j2i_sat_rsub_j2i
- * libj2_j2i_sat_rsub_ji
- */
#else
-CONST int main(void) { return 0; } /* TODO test */
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_j2i.c */
#endif
diff --git a/libj2_j2i_sat_sub_j2i_to_j2i.c b/libj2_j2i_sat_sub_j2i_to_j2i.c
index 27f39e1..06d4f27 100644
--- a/libj2_j2i_sat_sub_j2i_to_j2i.c
+++ b/libj2_j2i_sat_sub_j2i_to_j2i.c
@@ -7,6 +7,6 @@ extern inline void libj2_j2i_sat_sub_j2i_to_j2i(const struct libj2_j2i *a, const
#else
-CONST int main(void) { return 0; } /* TODO test */
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_j2i.c */
#endif
diff --git a/libj2_j2i_sat_sub_ji.c b/libj2_j2i_sat_sub_ji.c
index 8747163..03d8891 100644
--- a/libj2_j2i_sat_sub_ji.c
+++ b/libj2_j2i_sat_sub_ji.c
@@ -7,6 +7,6 @@ extern inline void libj2_j2i_sat_sub_ji(struct libj2_j2i *a, intmax_t b);
#else
-CONST int main(void) { return 0; } /* TODO test */
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_ji.c */
#endif
diff --git a/libj2_j2i_sat_sub_ji_to_j2i.c b/libj2_j2i_sat_sub_ji_to_j2i.c
index 6008108..1502937 100644
--- a/libj2_j2i_sat_sub_ji_to_j2i.c
+++ b/libj2_j2i_sat_sub_ji_to_j2i.c
@@ -7,6 +7,6 @@ extern inline void libj2_j2i_sat_sub_ji_to_j2i(const struct libj2_j2i *a, intmax
#else
-CONST int main(void) { return 0; } /* TODO test */
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_sub_ji.c */
#endif
diff --git a/libj2_j2i_sub_j2i.3 b/libj2_j2i_sub_j2i.3
index 466c84a..c0b7a35 100644
--- a/libj2_j2i_sub_j2i.3
+++ b/libj2_j2i_sub_j2i.3
@@ -31,6 +31,15 @@ int \fBlibj2_j2i_rsub_ji_overflow\fP(struct libj2_j2i *\fIb\fP, intmax_t \fIa\fP
int \fBlibj2_j2i_rsub_j2i_overflow_p\fP(const struct libj2_j2i *\fIb\fP, const struct libj2_j2i *\fIa\fP);
int \fBlibj2_j2i_rsub_ji_overflow_p\fP(const struct libj2_j2i *\fIb\fP, intmax_t \fIa\fP);
+
+void \fBlibj2_j2i_sat_sub_j2i\fP(struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP);
+void \fBlibj2_j2i_sat_sub_j2i_to_j2i\fP(const struct libj2_j2i *\fIa\fP, const struct libj2_j2i *\fIb\fP, struct libj2_j2i *\fIr\fP);
+void \fBlibj2_j2i_sat_sub_ji\fP(struct libj2_j2i *\fIa\fP, intmax_t \fIb\fP);
+void \fBlibj2_j2i_sat_sub_ji_to_j2i\fP(const struct libj2_j2i *\fIa\fP, intmax_t \fIb\fP, struct libj2_j2i *\fIr\fP);
+void \fBlibj2_ji_sat_sub_j2i_to_j2i\fP(intmax_t \fIa\fP, const struct libj2_j2i *\fIb\fP, struct libj2_j2i *\fIr\fP);
+
+void \fBlibj2_j2i_sat_rsub_j2i\fP(struct libj2_j2i *\fIb\fP, const struct libj2_j2i *\fIa\fP);
+void \fBlibj2_j2i_sat_rsub_ji\fP(struct libj2_j2i *\fIb\fP, intmax_t \fIa\fP);
.fi
.PP
Link with
@@ -56,15 +65,17 @@ except the functions
.BR libj2_ji_sub_j2i_overflow_p (),
.BR libj2_j2i_rsub_j2i_overflow_p (),
and
-.BR libj2_j2i_rsub_ji_overflow_p (),
+.BR libj2_j2i_rsub_ji_overflow_p ()
only predict overflow, and do not calculate
the difference, and therefore does store it
anywhere; and except the functions
.BR libj2_j2i_rsub_j2i (),
.BR libj2_j2i_rsub_ji (),
.BR libj2_j2i_rsub_j2i_overflow (),
-and
.BR libj2_j2i_rsub_ji_overflow (),
+.BR libj2_j2i_sat_rsub_j2i (),
+and
+.BR libj2_j2i_sat_rsub_ji ()
store the result in
.IR b .
.PP
@@ -75,7 +86,14 @@ in their name), detect arithmetic overflow.
.PP
The result is truncated to the least significant
bits, as many as can be stored, in case of overflow;
-that is, modular arithmetics is used.
+that is, modular arithmetics is used. However, the
+.BR sat_sub -
+and
+.BR sat_rsub -functions
+use saturated arithmetics, meaning that the result
+will be the maximum representable value on positive
+overflow and the minimum representable value on
+negative overflow.
.PP
The arguments are assumed to be
.RI non- NULL .
@@ -110,8 +128,15 @@ The
.BR libj2_j2i_rsub_j2i_overflow (),
.BR libj2_j2i_rsub_ji_overflow (),
.BR libj2_j2i_rsub_j2i_overflow_p (),
+.BR libj2_j2i_rsub_ji_overflow_p (),
+.BR libj2_j2i_sat_sub_j2i (),
+.BR libj2_j2i_sat_sub_j2i_to_j2i (),
+.BR libj2_j2i_sat_sub_ji (),
+.BR libj2_j2i_sat_sub_ji_to_j2i (),
+.BR libj2_ji_sat_sub_j2i_to_j2i (),
+.BR libj2_j2i_sat_rsub_j2i (),
and
-.BR libj2_j2i_rsub_ji_overflow_p ()
+.BR libj2_j2i_sat_rsub_ji ()
functions were added in version 1.1 of
.BR libj2 .
diff --git a/libj2_j2i_sub_j2i.c b/libj2_j2i_sub_j2i.c
index 0492bea..78dea79 100644
--- a/libj2_j2i_sub_j2i.c
+++ b/libj2_j2i_sub_j2i.c
@@ -100,14 +100,12 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low)
r = a;
EXPECT(libj2_j2i_sub_j2i_to_j2i_overflow(CONST_ARG &r, CONST_ARG &b, &r) == expected_overflow);
- EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
r = b;
EXPECT(libj2_j2i_sub_j2i_to_j2i_overflow(CONST_ARG &a, CONST_ARG &r, &r) == expected_overflow);
EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
- EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
r = a;
@@ -115,6 +113,29 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low)
EXPECT(libj2_j2i_is_zero(&r));
r = (struct libj2_j2i){111, 222};
+ libj2_j2i_sat_sub_j2i_to_j2i(CONST_ARG &a, CONST_ARG &b, &r);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ libj2_j2i_sat_sub_j2i_to_j2i(CONST_ARG &r, CONST_ARG &b, &r);
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+ r = b;
+ libj2_j2i_sat_sub_j2i_to_j2i(CONST_ARG &a, CONST_ARG &r, &r);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ libj2_j2i_sat_sub_j2i_to_j2i(CONST_ARG &r, CONST_ARG &r, &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = (struct libj2_j2i){111, 222};
libj2_j2i_sub_j2i_to_j2i(CONST_ARG &a, CONST_ARG &b, &r);
EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
@@ -152,6 +173,16 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low)
EXPECT(libj2_j2i_is_zero(&r));
r = a;
+ libj2_j2i_sat_sub_j2i(&r, CONST_ARG &b);
+ EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ libj2_j2i_sat_sub_j2i(&r, CONST_ARG &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = a;
libj2_j2i_sub_j2i(&r, CONST_ARG &b);
EXPECT(libj2_j2i_eq_j2i(&b, &b_saved));
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
@@ -178,6 +209,16 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low)
EXPECT(libj2_j2i_is_zero(&r));
r = b;
+ libj2_j2i_sat_rsub_j2i(&r, CONST_ARG &a);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
+ libj2_j2i_sat_rsub_j2i(&r, CONST_ARG &r);
+ EXPECT(libj2_j2i_is_zero(&r));
+
+ r = b;
libj2_j2i_rsub_j2i(&r, CONST_ARG &a);
EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
diff --git a/libj2_j2i_sub_ji.c b/libj2_j2i_sub_ji.c
index 4fc8e0e..34222f6 100644
--- a/libj2_j2i_sub_ji.c
+++ b/libj2_j2i_sub_ji.c
@@ -97,6 +97,13 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t ub)
validate(a.high, a.low, b < 0 ? UINTMAX_MAX : 0U, ub, expected.high, expected.low, expected_overflow);
+ a = a_saved;
+ r = (struct libj2_j2i){111, 222};
+ libj2_j2i_sat_sub_ji_to_j2i((const struct libj2_j2i *)&a, b, &r);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
r = (struct libj2_j2i){111, 222};
libj2_j2i_sub_ji_to_j2i((const struct libj2_j2i *)&a, b, &r);
EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
@@ -115,6 +122,11 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t ub)
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
r = a;
+ libj2_j2i_sat_sub_ji(&r, b);
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
libj2_j2i_sub_ji(&r, b);
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
@@ -126,6 +138,13 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t ub)
EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+ a = a_saved;
+ r = (struct libj2_j2i){111, 222};
+ libj2_ji_sat_sub_j2i_to_j2i(b, (const struct libj2_j2i *)&a, &r);
+ EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
validate(b < 0 ? UINTMAX_MAX : 0U, ub, a.high, a.low, expected.high, expected.low, expected_overflow);
EXPECT(libj2_ji_sub_j2i_overflow_p(b, (const struct libj2_j2i *)&a) == expected_overflow);
@@ -145,9 +164,19 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t ub)
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
r = a;
+ libj2_ji_sat_sub_j2i_to_j2i(b, (const struct libj2_j2i *)&r, &r);
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
+ r = a;
EXPECT(libj2_j2i_rsub_ji_overflow(&r, b) == expected_overflow);
EXPECT(libj2_j2i_eq_j2i(&r, &expected));
+ r = a;
+ libj2_j2i_sat_rsub_ji(&r, b);
+ EXPECT(expected_overflow > 0 ? libj2_j2i_is_max(&r) :
+ expected_overflow ? libj2_j2i_is_min(&r) : libj2_j2i_eq_j2i(&r, &expected));
+
EXPECT(libj2_j2i_rsub_ji_overflow_p((const struct libj2_j2i *)&a, b) == expected_overflow);
EXPECT(libj2_j2i_eq_j2i(&a, &a_saved));
diff --git a/libj2_j2u_sat_add_j2u.3 b/libj2_j2u_sat_add_j2u.3
new file mode 120000
index 0000000..668244f
--- /dev/null
+++ b/libj2_j2u_sat_add_j2u.3
@@ -0,0 +1 @@
+libj2_j2i_add_j2i.3 \ No newline at end of file
diff --git a/libj2_j2u_sat_add_j2u.c b/libj2_j2u_sat_add_j2u.c
index e37a6ea..4d18abb 100644
--- a/libj2_j2u_sat_add_j2u.c
+++ b/libj2_j2u_sat_add_j2u.c
@@ -3,13 +3,6 @@
#ifndef TEST
extern inline void libj2_j2u_sat_add_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
-/* TODO Add man pages
- * libj2_j2u_sat_add_j2u
- * libj2_j2u_sat_add_j2u_to_j2u
- * libj2_j2u_sat_add_ju
- * libj2_j2u_sat_add_ju_to_j2u
- * libj2_ju_sat_add_j2u_to_j2u
- */
#else
diff --git a/libj2_j2u_sat_lsh.3 b/libj2_j2u_sat_lsh.3
new file mode 120000
index 0000000..7b89b30
--- /dev/null
+++ b/libj2_j2u_sat_lsh.3
@@ -0,0 +1 @@
+libj2_j2i_lsh.3 \ No newline at end of file
diff --git a/libj2_j2u_sat_lsh.c b/libj2_j2u_sat_lsh.c
index a3a8007..15aa80b 100644
--- a/libj2_j2u_sat_lsh.c
+++ b/libj2_j2u_sat_lsh.c
@@ -3,11 +3,6 @@
#ifndef TEST
extern inline void libj2_j2u_sat_lsh(struct libj2_j2u *a, unsigned b);
-/* TODO Add man pages
- * libj2_j2u_sat_lsh
- * libj2_j2u_sat_lsh_to_j2u
- * libj2_ju_sat_lsh_to_j2u
- */
#else
diff --git a/libj2_j2u_sat_mul_j2u.3 b/libj2_j2u_sat_mul_j2u.3
new file mode 120000
index 0000000..1f6f78e
--- /dev/null
+++ b/libj2_j2u_sat_mul_j2u.3
@@ -0,0 +1 @@
+libj2_j2u_mul_j2u.3 \ No newline at end of file
diff --git a/libj2_j2u_sat_mul_j2u.c b/libj2_j2u_sat_mul_j2u.c
index 135a8b0..d374c73 100644
--- a/libj2_j2u_sat_mul_j2u.c
+++ b/libj2_j2u_sat_mul_j2u.c
@@ -3,14 +3,6 @@
#ifndef TEST
extern inline void libj2_j2u_sat_mul_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
-/* TODO Add man pages
- * libj2_j2u_sat_mul_j2u
- * libj2_j2u_sat_mul_j2u_destructive
- * libj2_j2u_sat_mul_j2u_to_j2u
- * libj2_j2u_sat_mul_ju
- * libj2_j2u_sat_mul_ju_to_j2u
- * libj2_ju_sat_mul_j2u_to_j2u
- */
#else
diff --git a/libj2_j2u_sat_sub_j2u.3 b/libj2_j2u_sat_sub_j2u.3
new file mode 120000
index 0000000..126e9a9
--- /dev/null
+++ b/libj2_j2u_sat_sub_j2u.3
@@ -0,0 +1 @@
+libj2_j2u_sub_j2u.3 \ No newline at end of file
diff --git a/libj2_j2u_sat_sub_j2u.c b/libj2_j2u_sat_sub_j2u.c
index 1fc5ced..f6aa5a6 100644
--- a/libj2_j2u_sat_sub_j2u.c
+++ b/libj2_j2u_sat_sub_j2u.c
@@ -3,16 +3,6 @@
#ifndef TEST
extern inline void libj2_j2u_sat_sub_j2u(struct libj2_j2u *a, const struct libj2_j2u *b);
-/* TODO Add man pages
- * libj2_j2u_sat_sub_j2u
- * libj2_j2u_sat_sub_j2u_to_j2u
- * libj2_j2u_sat_sub_ju
- * libj2_j2u_sat_sub_ju_to_j2u
- * libj2_ju_sat_sub_j2u_to_j2u
- * libj2_ju_sat_sub_ju_to_j2u
- * libj2_j2u_sat_rsub_j2u
- * libj2_j2u_sat_rsub_ju
- */
#else
diff --git a/libj2_j2u_sub_j2u.3 b/libj2_j2u_sub_j2u.3
index 7fb94c5..cbadfd2 100644
--- a/libj2_j2u_sub_j2u.3
+++ b/libj2_j2u_sub_j2u.3
@@ -33,6 +33,16 @@ int \fBlibj2_j2u_rsub_ju_overflow\fP(struct libj2_j2u *\fIb\fP, uintmax_t \fIa\f
int \fBlibj2_j2u_rsub_j2u_overflow_p\fP(const struct libj2_j2u *\fIb\fP, const struct libj2_j2u *\fIa\fP);
int \fBlibj2_j2u_rsub_ju_overflow_p\fP(const struct libj2_j2u *\fIb\fP, uintmax_t \fIa\fP);
+
+void \fBlibj2_j2u_sat_sub_j2u\fP(struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP);
+void \fBlibj2_j2u_sat_sub_j2u_to_j2u\fP(const struct libj2_j2u *\fIa\fP, const struct libj2_j2u *\fIb\fP, struct libj2_j2u *\fIr\fP);
+void \fBlibj2_j2u_sat_sub_ju\fP(struct libj2_j2u *\fIa\fP, uintmax_t \fIb\fP);
+void \fBlibj2_j2u_sat_sub_ju_to_j2u\fP(const struct libj2_j2u *\fIa\fP, uintmax_t \fIb\fP, struct libj2_j2u *\fIr\fP);
+void \fBlibj2_ju_sat_sub_j2u_to_j2u\fP(uintmax_t \fIa\fP, const struct libj2_j2u *\fIb\fP, struct libj2_j2u *\fIr\fP);
+void \fBlibj2_ju_sat_sub_ju_to_j2u\fP(uintmax_t \fIa\fP, uintmax_t \fIb\fP, struct libj2_j2u *\fIr\fP);
+
+void \fBlibj2_j2u_sat_rsub_j2u\fP(struct libj2_j2u *\fIb\fP, const struct libj2_j2u *\fIa\fP);
+void \fBlibj2_j2u_sat_rsub_ju\fP(struct libj2_j2u *\fIb\fP, uintmax_t \fIa\fP);
.fi
.PP
Link with
@@ -59,15 +69,17 @@ except the functions
.BR libj2_ju_sub_ju_overflow_p (),
.BR libj2_j2u_rsub_j2u_overflow_p (),
and
-.BR libj2_j2u_rsub_ju_overflow_p (),
+.BR libj2_j2u_rsub_ju_overflow_p ()
only predict overflow, and do not calculate
the difference, and therefore does store it
anywhere; and except the functions
.BR libj2_j2u_rsub_j2u (),
.BR libj2_j2u_rsub_ju (),
.BR libj2_j2u_rsub_j2u_overflow (),
-and
.BR libj2_j2u_rsub_ju_overflow (),
+.BR libj2_j2u_sat_rsub_j2u (),
+and
+.BR libj2_j2u_sat_rsub_ju ()
store the result in
.IR b .
.PP
@@ -78,8 +90,13 @@ in their name), detect arithmetic overflow.
.PP
The result is truncated to the least significant
bits, as many as can be stored, in case of overflow;
-that is, modular arithmetics is used.
-
+that is, modular arithmetics is used. However, the
+.BR sat_sub -
+and
+.BR sat_rsub -functions
+use saturated arithmetics, meaning that the result
+will be the maximum representable value on positive
+overflow and the value zero on negative overflow.
.PP
The arguments are assumed to be
.RI non- NULL .
@@ -119,6 +136,19 @@ and
.BR libj2_j2u_rsub_ju_overflow_p ()
functions were added in version 1.0 of
.BR libj2 .
+.PP
+The
+.BR libj2_j2u_sat_sub_j2u (),
+.BR libj2_j2u_sat_sub_j2u_to_j2u (),
+.BR libj2_j2u_sat_sub_ju (),
+.BR libj2_j2u_sat_sub_ju_to_j2u (),
+.BR libj2_ju_sat_sub_j2u_to_j2u (),
+.BR libj2_ju_sat_sub_ju_to_j2u (),
+.BR libj2_j2u_sat_rsub_j2u (),
+and
+.BR libj2_j2u_sat_rsub_ju ()
+functions were added in version 1.1 of
+.BR libj2 .
.SH NOTES
The return value 1 represents negative
diff --git a/libj2_ji_sat_lsh_to_j2i.c b/libj2_ji_sat_lsh_to_j2i.c
index 9fc6b09..4cc2d19 100644
--- a/libj2_ji_sat_lsh_to_j2i.c
+++ b/libj2_ji_sat_lsh_to_j2i.c
@@ -7,6 +7,6 @@ extern inline void libj2_ji_sat_lsh_to_j2i(intmax_t a, unsigned b, struct libj2_
#else
-CONST int main(void) { return 0; } /* TODO test */
+CONST int main(void) { return 0; } /* Tested in libj2_j2i_lsh.c */
#endif
diff --git a/libj2_ji_sat_mul_j2i_to_j2i.3 b/libj2_ji_sat_mul_j2i_to_j2i.3
new file mode 120000
index 0000000..6e1cee4
--- /dev/null
+++ b/libj2_ji_sat_mul_j2i_to_j2i.3
@@ -0,0 +1 @@
+libj2_j2i_sat_mul_j2i.3 \ No newline at end of file
diff --git a/libj2_ji_sat_mul_j2i_to_j2i.c b/libj2_ji_sat_mul_j2i_to_j2i.c
new file mode 100644
index 0000000..94d4f95
--- /dev/null
+++ b/libj2_ji_sat_mul_j2i_to_j2i.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+extern inline void libj2_ji_sat_mul_j2i_to_j2i(intmax_t a, const struct libj2_j2i *b, struct libj2_j2i *res);
+
+
+#else
+
+CONST int main(void) { return 0; }
+
+#endif
diff --git a/libj2_ji_sat_sub_j2i_to_j2i.c b/libj2_ji_sat_sub_j2i_to_j2i.c
index f214305..4c55e52 100644
--- a/libj2_ji_sat_sub_j2i_to_j2i.c
+++ b/libj2_ji_sat_sub_j2i_to_j2i.c
@@ -7,6 +7,6 @@ extern inline void libj2_ji_sat_sub_j2i_to_j2i(intmax_t a, const struct libj2_j2
#else
-CONST int main(void) { return 0; } /* TODO test */
+CONST int main(void) { return 0; } /* Tested libj2_j2i_sub_ji.c */
#endif