@@ -250,11 +250,7 @@ typedef struct YT__Arg {
250250 { \
251251 .isOpt = false, .val = (uintptr_t)(v) \
252252 }
253- #define _ \
254- (YT__Arg) \
255- { \
256- .isOpt = true, .val = 0 \
257- }
253+ #define _ (YT__Arg){ .isOpt = true, .val = 0 }
258254
259255 #define YT__RECORD_CALL (n , f , ...) \
260256 do { \
@@ -848,25 +844,56 @@ static int YT__equal_string (const char* a, const char* b, int* i);
848844 #define AUTOTYPE __auto_type
849845 #endif /* __cplusplus */
850846
851- static bool yt__approxeq (double a , double b , double epsilon )
847+ /* Performs either relative or absolute comparison on floating point numbers.
848+ * Relative comparison: Checks if the difference is smaller than some percentage than the of the two
849+ * largest number.
850+ * Absolute comparison: Checks if the difference is smaller than an absolute number. The problem is
851+ * the floating point accuracy changes depending on how big or small the number is, so the epsilon
852+ * that works for smaller numbers will not work for larger ones.
853+ */
854+ static bool yt__approxeq (bool is_abs , double a , double b , double epsilon )
852855{
853- double ut_a = fabs (a );
854- double ut_b = fabs (b );
856+ double ut_a = fabs (a );
857+ double ut_b = fabs (b );
858+ double ut_diff = fabs (a - b );
859+
860+ // NanS are not numbers, so any compare with numbers must fail
861+ if (isnan (a ) || isnan (b ))
862+ return false;
855863
856- if ((isfinite (a ) && isfinite (b )) || (ut_a == 0.0 && ut_b == 0.0 ) || (isnan (a ) && isnan (b )))
864+ // Zero comparison does work well for relative checks, so this takes care of that, also handles
865+ // the trivial case.
866+ if ((a == b ) || (ut_a == 0.0 && ut_b == 0 ))
857867 return true;
858- if ((isfinite (a ) && !isfinite (b )) || (!isfinite (a ) && isfinite (b )))
868+
869+ // Infinities are treated as valid, but no comparison is done, instead test matches if both are
870+ // same, otherwise fails if only one is infinity and the other is not
871+ if (isinf (ut_a ) && isinf (ut_b ))
872+ return true;
873+
874+ if ((!isinf (ut_a ) && isinf (ut_b )) || (isinf (ut_a ) && !isinf (ut_b )))
859875 return false;
860876
861- // Source: https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
862- double ut_diff = fabs (a - b );
863- double ut_largest = (ut_a > ut_b ) ? ut_a : ut_b ;
864- return (ut_diff <= ut_largest * epsilon );
877+ if (is_abs ) {
878+ return (ut_diff <= epsilon );
879+ } else {
880+ double ut_largest = (ut_a > ut_b ) ? ut_a : ut_b ;
881+ return (ut_diff <= ut_largest * epsilon );
882+ }
865883}
866884
867- #define YT__TEST_DOUBLE (e , a , o , b ) \
885+ #define YT__TEST_DOUBLE_REL (e , a , o , b ) \
886+ do { \
887+ YT__current_testrecord->total_exp_count++; \
888+ if (!(yt__approxeq (false, a, b, e) o true)) { \
889+ YT__FAILED (a o b, "[%f !" #o " %f]", a, b); \
890+ } \
891+ } while (0)
892+
893+ #define YT__TEST_DOUBLE_ABS (e , a , o , b ) \
868894 do { \
869- if (!(yt__approxeq (a, b, e) o true)) { \
895+ YT__current_testrecord->total_exp_count++; \
896+ if (!(yt__approxeq (true, a, b, e) o true)) { \
870897 YT__FAILED (a o b, "[%f !" #o " %f]", a, b); \
871898 } \
872899 } while (0)
@@ -900,14 +927,16 @@ static bool yt__approxeq (double a, double b, double epsilon)
900927 YT__FAILED (a o b, "[Idx: %d, '%c' !" #o " '%c']", i, ut_a[i], ut_b[i]); \
901928 } while (0)
902929
903- #define YT_EQ_DOUBLE (a , b , e ) YT__TEST_DOUBLE (e, a, ==, b)
904- #define YT_NEQ_DOUBLE (a , b , e ) YT__TEST_DOUBLE (e, a, !=, b)
905- #define YT_EQ_SCALAR (a , b ) YT__TEST_SCALAR (a, ==, b)
906- #define YT_NEQ_SCALAR (a , b ) YT__TEST_SCALAR (a, !=, b)
907- #define YT_GEQ_SCALAR (a , b ) YT__TEST_SCALAR (a, >=, b)
908- #define YT_LEQ_SCALAR (a , b ) YT__TEST_SCALAR (a, <=, b)
909- #define YT_LES_SCALAR (a , b ) YT__TEST_SCALAR (a, <, b)
910- #define YT_GRT_SCALAR (a , b ) YT__TEST_SCALAR (a, >, b)
930+ #define YT_EQ_DOUBLE_REL (a , b , e ) YT__TEST_DOUBLE_REL (e, a, ==, b)
931+ #define YT_NEQ_DOUBLE_REL (a , b , e ) YT__TEST_DOUBLE_REL (e, a, !=, b)
932+ #define YT_EQ_DOUBLE_ABS (a , b , e ) YT__TEST_DOUBLE_ABS (e, a, ==, b)
933+ #define YT_NEQ_DOUBLE_ABS (a , b , e ) YT__TEST_DOUBLE_ABS (e, a, !=, b)
934+ #define YT_EQ_SCALAR (a , b ) YT__TEST_SCALAR (a, ==, b)
935+ #define YT_NEQ_SCALAR (a , b ) YT__TEST_SCALAR (a, !=, b)
936+ #define YT_GEQ_SCALAR (a , b ) YT__TEST_SCALAR (a, >=, b)
937+ #define YT_LEQ_SCALAR (a , b ) YT__TEST_SCALAR (a, <=, b)
938+ #define YT_LES_SCALAR (a , b ) YT__TEST_SCALAR (a, <, b)
939+ #define YT_GRT_SCALAR (a , b ) YT__TEST_SCALAR (a, >, b)
911940
912941 #define YT_EQ_MEM (a , b , sz ) YT__TEST_MEM (a, ==, b, sz)
913942 #define YT_NEQ_MEM (a , b , sz ) YT__TEST_MEM (a, !=, b, sz)
0 commit comments