From: Dotsenko Andrey Date: Tue, 8 Nov 2016 20:58:18 +0000 (+0300) Subject: Add comparison macros for floating point numbers (ck_assert_floating_*) X-Git-Tag: 0.11.0~9^2~5 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=052d1701b2775533b328ebe0b0e6222be7213899;p=check Add comparison macros for floating point numbers (ck_assert_floating_*) --- diff --git a/src/check.h.in b/src/check.h.in index 43867a6..07ecd6c 100644 --- a/src/check.h.in +++ b/src/check.h.in @@ -24,6 +24,8 @@ #include #include +#include +#include #include @@ -669,6 +671,696 @@ CK_DLL_EXP void CK_EXPORT _ck_assert_failed(const char *file, int line, */ #define ck_assert_uint_ge(X, Y) _ck_assert_uint(X, >=, Y) +/* Number of digits after the decimal point to output via printf */ +#ifndef CK_FLOATING_DIG +# define CK_FLOATING_DIG 6 +#endif /* CK_FLOATING_DIG */ + +/* Floating point number comparison macros with improved output + * compared to ck_assert(). */ +/* OP may be any comparison operator, TP is type, TM is type modifier. */ +#define _ck_assert_floating(X, OP, Y, TP, TM) do { \ + TP _ck_x = (X); \ + TP _ck_y = (Y); \ + ck_assert_msg(_ck_x OP _ck_y, \ + "Assertion '%s' failed: %s == %.*"TM"g, %s == %.*"TM"g", \ + #X" "#OP" "#Y, \ + #X, (int)CK_FLOATING_DIG, _ck_x, \ + #Y, (int)CK_FLOATING_DIG, _ck_y); \ +} while (0) + +/* Check floating point number is finise. */ +/* TP is type, TM is type modifier. */ +#define _ck_assert_floating_finite(X, TP, TM) \ +do { \ + TP _ck_x = (X); \ + ck_assert_msg(isfinite(_ck_x), \ + "Assertion '%s' failed: %s == %.*"TM"g", \ + #X" is finite", \ + #X, (int)CK_FLOATING_DIG, _ck_x); \ +} while (0) + +/* Check floating point number is infinise. */ +/* TP is type, TM is type modifier. */ +#define _ck_assert_floating_infinite(X, TP, TM) \ +do { \ + TP _ck_x = (X); \ + ck_assert_msg(isinf(_ck_x), \ + "Assertion '%s' failed: %s == %.*"TM"g", \ + #X" is infinite", \ + #X, (int)CK_FLOATING_DIG, _ck_x); \ +} while (0) + +/* Check floating point number is "Not a Number". */ +/* TP is type, TM is type modifier. */ +#define _ck_assert_floating_nan(X, TP, TM) \ +do { \ + TP _ck_x = (X); \ + ck_assert_msg(isnan(_ck_x), \ + "Assertion '%s' failed: %s == %.*"TM"g", \ + #X" is NaN", \ + #X, (int)CK_FLOATING_DIG, _ck_x); \ +} while (0) + +/* Check floating point number is not "Not a Number". */ +/* TP is type, TM is type modifier. */ +#define _ck_assert_floating_nonnan(X, TP, TM) \ +do { \ + TP _ck_x = (X); \ + ck_assert_msg(!isnan(_ck_x), \ + "Assertion '%s' failed: %s == %.*"TM"g", \ + #X" is not NaN", \ + #X, (int)CK_FLOATING_DIG, _ck_x); \ +} while (0) + +/* Floating point tolerance comparison macros with improved output + * compared to ck_assert(). */ +/* OP, D can have values: >, -1; <, 1. */ +#define _ck_assert_floating_op_tol(X, OP, Y, T, D, TP, TM) do { \ + TP _ck_x = (X); \ + TP _ck_y = (Y); \ + TP _ck_t = (T); \ + ck_assert_msg((_ck_x - _ck_y) OP _ck_t * (D), \ + "Assertion '%s' failed: %s == %.*"TM"g, %s == %.*"TM"g, %s == %.*"TM"g", \ + #X" "#OP"= "#Y", error < "#T, \ + #X, (int)CK_FLOATING_DIG, _ck_x, \ + #Y, (int)CK_FLOATING_DIG, _ck_y, \ + #T, (int)CK_FLOATING_DIG, _ck_t); \ +} while (0) + +/* Floating point tolerance comparison macros with improved output + * compared to ck_assert(). */ +/* OP can have values: <; >=. */ +#define _ck_assert_floating_absdiff_op_tol(X, Y, OP, T, TP, TM) \ +do { \ + TP _ck_x = (X); \ + TP _ck_y = (Y); \ + TP _ck_t = (T); \ + ck_assert_msg(fabsl(_ck_y - _ck_x) OP _ck_t, \ + "Assertion '%s' failed: %s == %.*"TM"g, %s == %.*"TM"g, %s == %.*"TM"g", \ + "fabsl("#Y" - "#X") "#OP" "#T, \ + #X, (int)CK_FLOATING_DIG, _ck_x, \ + #Y, (int)CK_FLOATING_DIG, _ck_y, \ + #T, (int)CK_FLOATING_DIG, _ck_t); \ +} while (0) + +/** + * Check two single precision floating point numbers to determine if X == Y + * + * If not X == Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_eq(X, Y) _ck_assert_floating(X, ==, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X != Y + * + * If not X != Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_ne(X, Y) _ck_assert_floating(X, !=, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X < Y + * + * If not X < Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_lt(X, Y) _ck_assert_floating(X, <, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X <= Y + * + * If not X <= Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_le(X, Y) _ck_assert_floating(X, <=, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X > Y + * + * If not X > Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_gt(X, Y) _ck_assert_floating(X, >, Y, float, "") +/** + * Check two single precision floating point numbers to determine if X >= Y + * + * If not X >= Y, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_ge(X, Y) _ck_assert_floating(X, >=, Y, float, "") + +/** + * Check two single precision floating point numbers to determine if X≈Y + * with specified tolerance + * + * If not X ≈ Y with error < T, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * @param T tolerance (float) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_eq_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, <, T, float, "") + +/** + * Check two single precision floating point numbers to determine if not X≈Y + * with specified tolerance + * + * If X ≈ Y with error < T, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * @param T tolerance (float) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_ne_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, >=, T, float, "") + +/** + * Check two single precision floating point numbers to determine if X>≈Y + * with specified tolerance + * + * If not X >≈ Y with error < T, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * @param T tolerance (float) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_ge_tol(X, Y, T) _ck_assert_floating_op_tol(X, >, Y, T, -1, float, "") + +/** + * Check two single precision floating point numbers to determine if X<≈Y + * with specified tolerance + * + * If not X <≈ Y with error < T, the test fails. + * + * @param X floating point number (float) + * @param Y floating point number (float) to compare against X + * @param T tolerance (float) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_le_tol(X, Y, T) _ck_assert_floating_op_tol(X, <, Y, T, 1, float, "") + +/** + * Check that a single precision floating point number is finite; i.e. is + * not +infinity, -infinity, or "Not a Number" (NaN) + * + * If X is +INFINITY or X is -INFINITY, or X is NaN, the test fails. + * + * @param X floating point number (float) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_finite(X) _ck_assert_floating_finite(X, float, "") + +/** + * Check that a single precision floating point number is infinite, + * either +infinity or -infinity + * + * If X is not +INFINITY and X is not -INFINITY, the test fails. + * + * @param X floating point number (float) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_infinite(X) _ck_assert_floating_infinite(X, float, "") + +/** + * Check that a single precision floating point number + * is "Not a Number" (NaN) + * + * If X is not NaN, the test fails. + * + * @param X floating point number (float) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_nan(X) _ck_assert_floating_nan(X, float, "") + +/** + * Check that a single precision floating point number is + * not "Not a Number" (NaN) + * + * If X is NaN, the test fails. + * + * @param X floating point number (float) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_float_nonnan(X) _ck_assert_floating_nonnan(X, float, "l") + +/** + * Check two double precision floating point numbers to determine if X == Y + * + * If not X == Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_eq(X, Y) _ck_assert_floating(X, ==, Y, double, "l") +/** + * Check two double precision floating point numbers to determine if X != Y + * + * If not X != Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_ne(X, Y) _ck_assert_floating(X, !=, Y, double, "l") +/** + * Check two double precision floating point numbers to determine if X < Y + * + * If not X < Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_lt(X, Y) _ck_assert_floating(X, <, Y, double, "l") +/** + * Check two double precision floating point numbers to determine if X <= Y + * + * If not X <= Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_le(X, Y) _ck_assert_floating(X, <=, Y, double, "l") +/** + * Check two double precision floating point numbers to determine if X > Y + * + * If not X > Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_gt(X, Y) _ck_assert_floating(X, >, Y, double, "l") +/** + * Check two double precision floating point numbers to determine if X >= Y + * + * If not X >= Y, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_ge(X, Y) _ck_assert_floating(X, >=, Y, double, "l") + +/** + * Check two double precision floating point numbers to determine if X≈Y + * with specified tolerance + * + * If not X ≈ Y with error < T, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * @param T tolerance (double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_eq_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, <, T, double, "l") + +/** + * Check two double precision floating point numbers to determine if not X≈Y + * with specified tolerance + * + * If X ≈ Y with error < T, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * @param T tolerance (double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_ne_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, >=, T, double, "l") + +/** + * Check two double precision floating point numbers to determine if X>≈Y + * with specified tolerance + * + * If not X >≈ Y with error < T, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * @param T tolerance (double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_ge_tol(X, Y, T) _ck_assert_floating_op_tol(X, >, Y, T, -1, double, "l") + +/** + * Check two double precision floating point numbers to determine if X<≈Y + * with specified tolerance + * + * If not X <≈ Y with error < T, the test fails. + * + * @param X floating point number (double) + * @param Y floating point number (double) to compare against X + * @param T tolerance (double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_le_tol(X, Y, T) _ck_assert_floating_op_tol(X, <, Y, T, 1, double, "l") + +/** + * Check that a double precision floating point number is finite; i.e. is + * not +infinity, -infinity, or "Not a Number" (NaN) + * + * If X is +INFINITY or X is -INFINITY, or X is NaN, the test fails. + * + * @param X floating point number (double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_finite(X) _ck_assert_floating_finite(X, double, "l") + +/** + * Check that a double precision floating point number is infinite, + * either +infinity or -infinity + * + * If X is not +INFINITY and X is not -INFINITY, the test fails. + * + * @param X floating point number (double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_infinite(X) _ck_assert_floating_infinite(X, double, "l") + +/** + * Check that a double precision floating point number + * is "Not a Number" (NaN) + * + * If X is not NaN, the test fails. + * + * @param X floating point number (double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_nan(X) _ck_assert_floating_nan(X, double, "l") + +/** + * Check that a double precision floating point number is + * not "Not a Number" (NaN) + * + * If X is NaN, the test fails. + * + * @param X floating point number (double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_double_nonnan(X) _ck_assert_floating_nonnan(X, double, "l") + +/** + * Check two double precision floating point numbers to determine if X == Y + * + * If not X == Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_eq(X, Y) _ck_assert_floating(X, ==, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X != Y + * + * If not X != Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_ne(X, Y) _ck_assert_floating(X, !=, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X < Y + * + * If not X < Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_lt(X, Y) _ck_assert_floating(X, <, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X <= Y + * + * If not X <= Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_le(X, Y) _ck_assert_floating(X, <=, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X > Y + * + * If not X > Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_gt(X, Y) _ck_assert_floating(X, >, Y, long double, "L") +/** + * Check two double precision floating point numbers to determine if X >= Y + * + * If not X >= Y, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_ge(X, Y) _ck_assert_floating(X, >=, Y, long double, "L") + +/** + * Check two double precision floating point numbers to determine if X≈Y + * with specified tolerance + * + * If not X ≈ Y with error < T, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * @param T tolerance (long double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_eq_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, <, T, long double, "L") + +/** + * Check two double precision floating point numbers to determine if not X≈Y + * with specified tolerance + * + * If X ≈ Y with error < T, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * @param T tolerance (long double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_ne_tol(X, Y, T) _ck_assert_floating_absdiff_op_tol(X, Y, >=, T, long double, "L") + +/** + * Check two double precision floating point numbers to determine if X>≈Y + * with specified tolerance + * + * If not X >≈ Y with error < T, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * @param T tolerance (long double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_ge_tol(X, Y, T) _ck_assert_floating_op_tol(X, >, Y, T, -1, long double, "L") + +/** + * Check two double precision floating point numbers to determine if X<≈Y + * with specified tolerance + * + * If not X <≈ Y with error < T, the test fails. + * + * @param X floating point number (long double) + * @param Y floating point number (long double) to compare against X + * @param T tolerance (long double) + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_le_tol(X, Y, T) _ck_assert_floating_op_tol(X, <, Y, T, 1, long double, "L") + +/** + * Check that a double precision floating point number is finite; i.e. is + * not +infinity, -infinity, or "Not a Number" (NaN) + * + * If X is +INFINITY or X is -INFINITY, or X is NaN, the test fails. + * + * @param X floating point number (long double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_finite(X) _ck_assert_floating_finite(X, long double, "L") + +/** + * Check that a double precision floating point number is infinite, + * either +infinity or -infinity + * + * If X is not +INFINITY and X is not -INFINITY, the test fails. + * + * @param X floating point number (long double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_infinite(X) _ck_assert_floating_infinite(X, long double, "L") + +/** + * Check that a double precision floating point number + * is "Not a Number" (NaN) + * + * If X is not NaN, the test fails. + * + * @param X floating point number (long double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_nan(X) _ck_assert_floating_nan(X, long double, "L") + +/** + * Check that a double precision floating point number is + * not "Not a Number" (NaN) + * + * If X is NaN, the test fails. + * + * @param X floating point number (long double) to be checked + * + * @note If the check fails, the remaining of the test is aborted + * + * @since 0.11.0 + */ +#define ck_assert_ldouble_nonnan(X) _ck_assert_floating_nonnan(X, long double, "L") + /* String comparison macros with improved output compared to ck_assert() */ /* OP might be any operator that can be used in '0 OP strcmp(X,Y)' comparison */ /* The x and y parameter swap in strcmp() is needed to handle >, >=, <, <= operators */