diff options
| author | Mattias Andrée <m@maandree.se> | 2026-02-11 11:20:10 +0100 |
|---|---|---|
| committer | Mattias Andrée <m@maandree.se> | 2026-02-11 11:20:10 +0100 |
| commit | 0d4c3e8f6be098e953502589b17cb28197322442 (patch) | |
| tree | df3a13e786769e78d3d6201150f4018dc0c22cb5 | |
| parent | Test sat_add (diff) | |
| download | libj2-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 '')
47 files changed, 599 insertions, 111 deletions
@@ -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\ @@ -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), @@ -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), @@ -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 |
