Skip to content

Commit

Permalink
Improved relative epsilon checks.
Browse files Browse the repository at this point in the history
Allow both the absolute and relative epsilon values to be set differently.
This allows for more flexibility, especially for very small values.

Added missing SIMD implementation for relative equals of dsVector2d.
  • Loading branch information
akb825 committed Jun 19, 2024
1 parent 7f322f7 commit 563c0b2
Show file tree
Hide file tree
Showing 13 changed files with 168 additions and 136 deletions.
24 changes: 15 additions & 9 deletions modules/Math/include/DeepSea/Math/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,13 +302,17 @@ DS_MATH_EXPORT inline bool dsEpsilonEquald(double x, double y, double epsilon);
*
* @param x The first value.
* @param y The second value.
* @param epsilon The epsilon to compare with.
* @param absoluteEps The absolute epsilon to compare with.
* @param relativeEps The relative epsilon to compare with. This will be scaled based on the values
* being compared.
* @return True the values of x and y are within epsilon.
*/
DS_MATH_EXPORT inline bool dsRelativeEpsilonEqualf(float x, float y, float epsilon);
DS_MATH_EXPORT inline bool dsRelativeEpsilonEqualf(float x, float y, float absoluteEps,
float relativeEps);

/** @copydoc dsEpsilonEqualf() */
DS_MATH_EXPORT inline bool dsRelativeEpsilonEquald(double x, double y, double epsilon);
DS_MATH_EXPORT inline bool dsRelativeEpsilonEquald(double x, double y, double absoluteEps,
double relativeEps);

/**
* @brief Checks to see if a value is equal to zero within an epsilon.
Expand Down Expand Up @@ -379,26 +383,28 @@ DS_MATH_EXPORT inline bool dsEpsilonEquald(double x, double y, double epsilon)
return fabs(x - y) <= epsilon;
}

DS_MATH_EXPORT inline bool dsRelativeEpsilonEqualf(float x, float y, float epsilon)
DS_MATH_EXPORT inline bool dsRelativeEpsilonEqualf(float x, float y, float absoluteEps,
float relativeEps)
{
float diff = fabsf(x - y);
if (diff <= epsilon)
if (diff <= absoluteEps)
return true;

float absX = fabsf(x);
float absY = fabsf(y);
return diff <= dsMax(absX, absY)*epsilon;
return diff <= dsMax(absX, absY)*relativeEps;
}

DS_MATH_EXPORT inline bool dsRelativeEpsilonEquald(double x, double y, double epsilon)
DS_MATH_EXPORT inline bool dsRelativeEpsilonEquald(double x, double y, double absoluteEps,
double relativeEps)
{
double diff = fabs(x - y);
if (diff <= epsilon)
if (diff <= absoluteEps)
return true;

double absX = fabs(x);
double absY = fabs(y);
return diff <= dsMax(absX, absY)*epsilon;
return diff <= dsMax(absX, absY)*relativeEps;
}

DS_MATH_EXPORT inline bool dsEpsilonEqualsZerof(float x, float epsilon)
Expand Down
36 changes: 26 additions & 10 deletions modules/Math/include/DeepSea/Math/Vector2.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 Aaron Barany
* Copyright 2016-2024 Aaron Barany
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -234,15 +234,17 @@ DS_MATH_EXPORT inline bool dsVector2d_epsilonEqual(const dsVector2d* a, const ds
* @brief Checks to see if two values are equal within a relative epsilon.
* @param a The first value.
* @param b The second value.
* @param epsilon The epsilon to compare with.
* @param absoluteEps The absolute epsilon to compare with.
* @param relativeEps The relative epsilon to compare with. This will be scaled based on the values
* being compared.
* @return True the values of a and b are within epsilon.
*/
DS_MATH_EXPORT inline bool dsVector2f_relativeEpsilonEqual(const dsVector2f* a, const dsVector2f* b,
float epsilon);
float absoluteEps, float relativeEps);

/** @copydoc dsVector2f_epsilonEqual() */
DS_MATH_EXPORT inline bool dsVector2d_relativeEpsilonEqual(const dsVector2d* a, const dsVector2d* b,
double epsilon);
double absoluteEps, double relativeEps);

/** @copydoc dsVector2_add() */
DS_MATH_EXPORT inline void dsVector2f_add(dsVector2f* result, const dsVector2f* a,
Expand Down Expand Up @@ -767,17 +769,31 @@ inline bool dsVector2d_epsilonEqual(const dsVector2d* a, const dsVector2d* b, do
#endif
}

inline bool dsVector2f_relativeEpsilonEqual(const dsVector2f* a, const dsVector2f* b, float epsilon)
inline bool dsVector2f_relativeEpsilonEqual(const dsVector2f* a, const dsVector2f* b,
float absoluteEps, float relativeEps)
{
return dsRelativeEpsilonEqualf(a->values[0], b->values[0], epsilon) &&
dsRelativeEpsilonEqualf(a->values[1], b->values[1], epsilon);
return dsRelativeEpsilonEqualf(a->values[0], b->values[0], absoluteEps, relativeEps) &&
dsRelativeEpsilonEqualf(a->values[1], b->values[1], absoluteEps, relativeEps);
}

inline bool dsVector2d_relativeEpsilonEqual(const dsVector2d* a, const dsVector2d* b,
double epsilon)
double absoluteEps, double relativeEps)
{
return dsRelativeEpsilonEquald(a->values[0], b->values[0], epsilon) &&
dsRelativeEpsilonEquald(a->values[1], b->values[1], epsilon);
#if DS_SIMD_ALWAYS_DOUBLE2
dsSIMD2d diff = dsSIMD2d_abs(dsSIMD2d_sub(a->simd, b->simd));

dsSIMD2d epsEqual = dsSIMD2d_cmple(diff, dsSIMD2d_set1(absoluteEps));
dsSIMD2d relativeEqual = dsSIMD2d_cmple(diff,
dsSIMD2d_mul(dsSIMD2d_max(dsSIMD2d_abs(a->simd), dsSIMD2d_abs(b->simd)),
dsSIMD2d_set1(relativeEps)));

dsVector2l result;
result.simd = dsSIMD2db_or(epsEqual, relativeEqual);
return result.x && result.y;
#else
return dsRelativeEpsilonEquald(a->values[0], b->values[0], absoluteEps, relativeEps) &&
dsRelativeEpsilonEquald(a->values[1], b->values[1], absoluteEps, relativeEps);
#endif
}

#ifdef __cplusplus
Expand Down
27 changes: 15 additions & 12 deletions modules/Math/include/DeepSea/Math/Vector3.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 Aaron Barany
* Copyright 2016-2024 Aaron Barany
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -259,15 +259,17 @@ DS_MATH_EXPORT inline bool dsVector3d_epsilonEqual(const dsVector3d* a, const ds
* @brief Checks to see if two values are equal within a relative epsilon.
* @param a The first value.
* @param b The second value.
* @param epsilon The epsilon to compare with.
* @param absoluteEps The absolute epsilon to compare with.
* @param relativeEps The relative epsilon to compare with. This will be scaled based on the values
* being compared.
* @return True the values of a and b are within epsilon.
*/
DS_MATH_EXPORT inline bool dsVector3f_relativeEpsilonEqual(const dsVector3f* a, const dsVector3f* b,
float epsilon);
float absoluteEps, float relativeEps);

/** @copydoc dsVector3f_relativeEpsilonEqual() */
DS_MATH_EXPORT inline bool dsVector3d_relativeEpsilonEqual(const dsVector3d* a, const dsVector3d* b,
double epsilon);
double absoluteEps, double relativeEps);

/** @copydoc dsVector3_add() */
DS_MATH_EXPORT inline void dsVector3f_add(dsVector3f* result, const dsVector3f* a,
Expand Down Expand Up @@ -785,19 +787,20 @@ inline bool dsVector3d_epsilonEqual(const dsVector3d* a, const dsVector3d* b, do
dsEpsilonEquald(a->values[2], b->values[2], epsilon);
}

inline bool dsVector3f_relativeEpsilonEqual(const dsVector3f* a, const dsVector3f* b, float epsilon)
inline bool dsVector3f_relativeEpsilonEqual(const dsVector3f* a, const dsVector3f* b,
float absoluteEps, float relativeEps)
{
return dsRelativeEpsilonEqualf(a->values[0], b->values[0], epsilon) &&
dsRelativeEpsilonEqualf(a->values[1], b->values[1], epsilon) &&
dsRelativeEpsilonEqualf(a->values[2], b->values[2], epsilon);
return dsRelativeEpsilonEqualf(a->values[0], b->values[0], absoluteEps, relativeEps) &&
dsRelativeEpsilonEqualf(a->values[1], b->values[1], absoluteEps, relativeEps) &&
dsRelativeEpsilonEqualf(a->values[2], b->values[2], absoluteEps, relativeEps);
}

inline bool dsVector3d_relativeEpsilonEqual(const dsVector3d* a, const dsVector3d* b,
double epsilon)
double absoluteEps, double relativeEps)
{
return dsRelativeEpsilonEquald(a->values[0], b->values[0], epsilon) &&
dsRelativeEpsilonEquald(a->values[1], b->values[1], epsilon) &&
dsRelativeEpsilonEquald(a->values[2], b->values[2], epsilon);
return dsRelativeEpsilonEquald(a->values[0], b->values[0], absoluteEps, relativeEps) &&
dsRelativeEpsilonEquald(a->values[1], b->values[1], absoluteEps, relativeEps) &&
dsRelativeEpsilonEquald(a->values[2], b->values[2], absoluteEps, relativeEps);
}

#ifdef __cplusplus
Expand Down
49 changes: 27 additions & 22 deletions modules/Math/include/DeepSea/Math/Vector4.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 Aaron Barany
* Copyright 2016-2024 Aaron Barany
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -256,15 +256,17 @@ DS_MATH_EXPORT inline bool dsVector4d_epsilonEqual(const dsVector4d* a, const ds
* @brief Checks to see if two values are equal within a relative epsilon.
* @param a The first value.
* @param b The second value.
* @param epsilon The epsilon to compare with.
* @param absoluteEps The absolute epsilon to compare with.
* @param relativeEps The relative epsilon to compare with. This will be scaled based on the values
* being compared.
* @return True the values of a and b are within epsilon.
*/
DS_MATH_EXPORT inline bool dsVector4f_relativeEpsilonEqual(const dsVector4f* a, const dsVector4f* b,
float epsilon);
float absoluteEps, float relativeEps);

/** @copydoc dsVector4f_epsilonEqual() */
DS_MATH_EXPORT inline bool dsVector4d_relativeEpsilonEqual(const dsVector4d* a, const dsVector4d* b,
double epsilon);
double absoluteEps, double relativeEps);

/** @copydoc dsVector4_add() */
DS_MATH_EXPORT inline void dsVector4f_add(dsVector4f* result, const dsVector4f* a,
Expand Down Expand Up @@ -883,54 +885,57 @@ DS_MATH_EXPORT inline bool dsVector4d_epsilonEqual(const dsVector4d* a, const ds
}

DS_MATH_EXPORT inline bool dsVector4f_relativeEpsilonEqual(const dsVector4f* a, const dsVector4f* b,
float epsilon)
float absoluteEps, float relativeEps)
{
#if DS_SIMD_ALWAYS_FLOAT4
dsSIMD4f diff = dsSIMD4f_abs(dsSIMD4f_sub(a->simd, b->simd));
dsSIMD4f eps4 = dsSIMD4f_set1(epsilon);
dsSIMD4fb epsEqual = dsSIMD4f_cmple(diff, eps4);
dsSIMD4fb epsEqual = dsSIMD4f_cmple(diff, dsSIMD4f_set1(absoluteEps));
dsSIMD4fb relativeEqual = dsSIMD4f_cmple(diff,
dsSIMD4f_mul(dsSIMD4f_max(dsSIMD4f_abs(a->simd), dsSIMD4f_abs(b->simd)), eps4));
dsSIMD4f_mul(dsSIMD4f_max(dsSIMD4f_abs(a->simd), dsSIMD4f_abs(b->simd)),
dsSIMD4f_set1(relativeEps)));

dsVector4i result;
result.simd = dsSIMD4fb_or(epsEqual, relativeEqual);
return result.x && result.y && result.z && result.w;
#else
return dsRelativeEpsilonEqualf(a->values[0], b->values[0], epsilon) &&
dsRelativeEpsilonEqualf(a->values[1], b->values[1], epsilon) &&
dsRelativeEpsilonEqualf(a->values[2], b->values[2], epsilon) &&
dsRelativeEpsilonEqualf(a->values[3], b->values[3], epsilon);
return dsRelativeEpsilonEqualf(a->values[0], b->values[0], absoluteEps, relativeEps) &&
dsRelativeEpsilonEqualf(a->values[1], b->values[1], absoluteEps, relativeEps) &&
dsRelativeEpsilonEqualf(a->values[2], b->values[2], absoluteEps, relativeEps) &&
dsRelativeEpsilonEqualf(a->values[3], b->values[3], absoluteEps, relativeEps);
#endif
}

DS_MATH_EXPORT inline bool dsVector4d_relativeEpsilonEqual(const dsVector4d* a, const dsVector4d* b,
double epsilon)
double absoluteEps, double relativeEps)
{
#if DS_SIMD_ALWAYS_DOUBLE2
dsVector4d diff;
diff.simd2[0] = dsSIMD2d_abs(dsSIMD2d_sub(a->simd2[0], b->simd2[0]));
diff.simd2[1] = dsSIMD2d_abs(dsSIMD2d_sub(a->simd2[1], b->simd2[1]));
dsSIMD2d eps2 = dsSIMD2d_set1(epsilon);
dsSIMD2d absoluteEps2 = dsSIMD2d_set1(absoluteEps);
dsSIMD2d relativeEps2 = dsSIMD2d_set1(relativeEps);

dsVector4l epsEqual;
epsEqual.simd2[0] = dsSIMD2d_cmple(diff.simd2[0], eps2);
epsEqual.simd2[1] = dsSIMD2d_cmple(diff.simd2[1], eps2);
epsEqual.simd2[0] = dsSIMD2d_cmple(diff.simd2[0], absoluteEps2);
epsEqual.simd2[1] = dsSIMD2d_cmple(diff.simd2[1], absoluteEps2);

dsVector4l relativeEqual;
relativeEqual.simd2[0] = dsSIMD2d_cmple(diff.simd2[0],
dsSIMD2d_mul(dsSIMD2d_max(dsSIMD2d_abs(a->simd2[0]), dsSIMD2d_abs(b->simd2[0])), eps2));
dsSIMD2d_mul(dsSIMD2d_max(dsSIMD2d_abs(a->simd2[0]), dsSIMD2d_abs(b->simd2[0])),
relativeEps2));
relativeEqual.simd2[1] = dsSIMD2d_cmple(diff.simd2[1],
dsSIMD2d_mul(dsSIMD2d_max(dsSIMD2d_abs(a->simd2[1]), dsSIMD2d_abs(b->simd2[1])), eps2));
dsSIMD2d_mul(dsSIMD2d_max(dsSIMD2d_abs(a->simd2[1]), dsSIMD2d_abs(b->simd2[1])),
relativeEps2));

dsVector4l result;
result.simd2[0] = dsSIMD2db_or(epsEqual.simd2[0], relativeEqual.simd2[0]);
result.simd2[1] = dsSIMD2db_or(epsEqual.simd2[1], relativeEqual.simd2[1]);
return result.x && result.y && result.z && result.w;
#else
return dsRelativeEpsilonEquald(a->values[0], b->values[0], epsilon) &&
dsRelativeEpsilonEquald(a->values[1], b->values[1], epsilon) &&
dsRelativeEpsilonEquald(a->values[2], b->values[2], epsilon) &&
dsRelativeEpsilonEquald(a->values[3], b->values[3], epsilon);
return dsRelativeEpsilonEquald(a->values[0], b->values[0], absoluteEps, relativeEps) &&
dsRelativeEpsilonEquald(a->values[1], b->values[1], absoluteEps, relativeEps) &&
dsRelativeEpsilonEquald(a->values[2], b->values[2], absoluteEps, relativeEps) &&
dsRelativeEpsilonEquald(a->values[3], b->values[3], absoluteEps, relativeEps);
#endif
}

Expand Down
6 changes: 3 additions & 3 deletions modules/Math/src/Core.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Aaron Barany
* Copyright 2016-2024 Aaron Barany
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -29,8 +29,8 @@ double dsWrapd(double x, double min, double max);
bool dsEpsilonEqualf(float x, float y, float epsilon);
bool dsEpsilonEquald(double x, double y, double epsilon);

bool dsRelativeEpsilonEqualf(float x, float y, float epsilon);
bool dsRelativeEpsilonEquald(double x, double y, double epsilon);
bool dsRelativeEpsilonEqualf(float x, float y, float absoluteEps, float relativeEps);
bool dsRelativeEpsilonEquald(double x, double y, double absoluteEps, double relativeEps);

bool dsEpsilonEqualsZerof(float x, float epsilon);
bool dsEpsilonEqualsZerod(double x, double epsilon);
8 changes: 5 additions & 3 deletions modules/Math/src/Vector2.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 Aaron Barany
* Copyright 2016-2024 Aaron Barany
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -87,5 +87,7 @@ void dsVector2d_normalize(dsVector2d* result, const dsVector2d* a);
bool dsVector2f_epsilonEqual(const dsVector2f* a, const dsVector2f* b, float epsilon);
bool dsVector2d_epsilonEqual(const dsVector2d* a, const dsVector2d* b, double epsilon);

bool dsVector2f_relativeEpsilonEqual(const dsVector2f* a, const dsVector2f* b, float epsilon);
bool dsVector2d_relativeEpsilonEqual(const dsVector2d* a, const dsVector2d* b, double epsilon);
bool dsVector2f_relativeEpsilonEqual(const dsVector2f* a, const dsVector2f* b, float absoluteEps,
float relativeEps);
bool dsVector2d_relativeEpsilonEqual(const dsVector2d* a, const dsVector2d* b, double absoluteEps,
double relativeEps);
8 changes: 5 additions & 3 deletions modules/Math/src/Vector3.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 Aaron Barany
* Copyright 2016-2024 Aaron Barany
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -92,5 +92,7 @@ void dsVector3d_normalize(dsVector3d* result, const dsVector3d* a);
bool dsVector3f_epsilonEqual(const dsVector3f* a, const dsVector3f* b, float epsilon);
bool dsVector3d_epsilonEqual(const dsVector3d* a, const dsVector3d* b, double epsilon);

bool dsVector3f_relativeEpsilonEqual(const dsVector3f* a, const dsVector3f* b, float epsilon);
bool dsVector3d_relativeEpsilonEqual(const dsVector3d* a, const dsVector3d* b, double epsilon);
bool dsVector3f_relativeEpsilonEqual(const dsVector3f* a, const dsVector3f* b, float absoluteEps,
float relativeEps);
bool dsVector3d_relativeEpsilonEqual(const dsVector3d* a, const dsVector3d* b, double absoluteEps,
double relativeEps);
8 changes: 5 additions & 3 deletions modules/Math/src/Vector4.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 Aaron Barany
* Copyright 2016-2024 Aaron Barany
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -87,5 +87,7 @@ void dsVector4d_normalize(dsVector4d* result, const dsVector4d* a);
bool dsVector4f_epsilonEqual(const dsVector4f* a, const dsVector4f* b, float epsilon);
bool dsVector4d_epsilonEqual(const dsVector4d* a, const dsVector4d* b, double epsilon);

bool dsVector4f_relativeEpsilonEqual(const dsVector4f* a, const dsVector4f* b, float epsilon);
bool dsVector4d_relativeEpsilonEqual(const dsVector4d* a, const dsVector4d* b, double epsilon);
bool dsVector4f_relativeEpsilonEqual(const dsVector4f* a, const dsVector4f* b, float absoluteEps,
float relativeEps);
bool dsVector4d_relativeEpsilonEqual(const dsVector4d* a, const dsVector4d* b, double absoluteEps,
double relativeEps);
Loading

0 comments on commit 563c0b2

Please sign in to comment.