diff --git a/src/commonutils.cpp b/src/commonutils.cpp index 412691ff7..e5581e991 100644 --- a/src/commonutils.cpp +++ b/src/commonutils.cpp @@ -16,6 +16,9 @@ limitations under the License. #include "commonutils.h" +#include +#include + #include "libcellml/component.h" #include "libcellml/model.h" @@ -40,6 +43,54 @@ libcellml::ComponentPtr owningComponent(const libcellml::ParentedEntityConstPtr return std::dynamic_pointer_cast(entity->parent()); } +uint64_t ulpsDistance(double a, double b) +{ + static const auto max = std::numeric_limits::max(); + + // Max distance for NaN. + if (std::isnan(a) || std::isnan(b)) { + return max; + } + + // If one's infinite and they're not equal, max distance. + if (std::isinf(a) != std::isinf(b)) { + return max; + } + + static const int SIZE_OF_DOUBLE = sizeof(double); + + uint64_t ia; + uint64_t ib; + memcpy(&ia, &a, SIZE_OF_DOUBLE); + memcpy(&ib, &b, SIZE_OF_DOUBLE); + + // Return the absolute value of the distance in ULPs. + uint64_t distance = max; + if (ia < ib) { + distance = ib + ~ia + 1; + } else { + distance = ia + ~ib + 1; + } + return distance; +} + +bool areNearlyEqual(double a, double b) +{ + static const double fixedEpsilon = std::numeric_limits::epsilon(); + static const ptrdiff_t ulpsEpsilon = 1; + + if (fabs(a - b) <= fixedEpsilon) { + return true; + } + + // If they are not the same sign then return false. + if ((a < 0.0) != (b < 0.0)) { + return false; + } + + return ulpsDistance(a, b) <= ulpsEpsilon; +} + #ifndef TEST_UTILS } // namespace libcellml #endif diff --git a/src/commonutils.h b/src/commonutils.h index dc5ad20c0..66fff07a0 100644 --- a/src/commonutils.h +++ b/src/commonutils.h @@ -45,6 +45,23 @@ libcellml::ModelPtr TEST_EXPORT owningModel(const libcellml::ParentedEntityConst */ libcellml::ComponentPtr TEST_EXPORT owningComponent(const libcellml::ParentedEntityConstPtr &entity); +/** + * @brief Decide if two doubles are nearly equal. + * + * Test two doubles to determine if they are close enough + * to be considered equal. + * + * Uses a modified form of comparing floats: + * + * https://bitbashing.io/comparing-floats.html + * + * @param a A @c double to test. + * @param b A @c double to test. + * + * @return @c true if the given doubles are considered close, @c false otherwise. + */ +bool TEST_EXPORT areNearlyEqual(double a, double b); + #ifndef TEST_UTILS } // namespace libcellml diff --git a/src/utilities.cpp b/src/utilities.cpp index 4fdc46fe4..7e5fc772e 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -268,54 +268,6 @@ bool areEqual(double a, double b) return convertToString(a + 0.0) == convertToString(b + 0.0); } -uint64_t ulpsDistance(double a, double b) -{ - static const auto max = std::numeric_limits::max(); - - // Max distance for NaN. - if (std::isnan(a) || std::isnan(b)) { - return max; - } - - // If one's infinite and they're not equal, max distance. - if (std::isinf(a) != std::isinf(b)) { - return max; - } - - static const int SIZE_OF_DOUBLE = sizeof(double); - - uint64_t ia; - uint64_t ib; - memcpy(&ia, &a, SIZE_OF_DOUBLE); - memcpy(&ib, &b, SIZE_OF_DOUBLE); - - // Return the absolute value of the distance in ULPs. - uint64_t distance = max; - if (ia < ib) { - distance = ib + ~ia + 1; - } else { - distance = ia + ~ib + 1; - } - return distance; -} - -bool areNearlyEqual(double a, double b) -{ - static const double fixedEpsilon = std::numeric_limits::epsilon(); - static const ptrdiff_t ulpsEpsilon = 1; - - if (fabs(a - b) <= fixedEpsilon) { - return true; - } - - // If they are not the same sign then return false. - if ((a < 0.0) != (b < 0.0)) { - return false; - } - - return ulpsDistance(a, b) <= ulpsEpsilon; -} - std::vector getImportedComponents(const ComponentEntityConstPtr &componentEntity) { std::vector importedComponents; diff --git a/src/utilities.h b/src/utilities.h index df5083fb6..00d06ccd6 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -333,23 +333,6 @@ bool isCellMLReal(const std::string &candidate); */ bool areEqual(double a, double b); -/** - * @brief Decide if two doubles are nearly equal. - * - * Test two doubles to determine if they are close enough - * to be considered equal. - * - * Uses a modified form of comparing floats: - * - * https://bitbashing.io/comparing-floats.html - * - * @param a A @c double to test. - * @param b A @c double to test. - * - * @return @c true if the given doubles are considered close, @c false otherwise. - */ -bool areNearlyEqual(double a, double b); - /** * @brief Compare strings to determine if they are equal. *