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