Skip to content

Commit

Permalink
Moved areNearlyEqual() from utilties to commonutils.
Browse files Browse the repository at this point in the history
  • Loading branch information
agarny committed Oct 22, 2024
1 parent 52d0d44 commit 1f1b8c0
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 65 deletions.
51 changes: 51 additions & 0 deletions src/commonutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ limitations under the License.

#include "commonutils.h"

#include <cmath>
#include <cstring>

#include "libcellml/component.h"
#include "libcellml/model.h"

Expand All @@ -40,6 +43,54 @@ libcellml::ComponentPtr owningComponent(const libcellml::ParentedEntityConstPtr
return std::dynamic_pointer_cast<libcellml::Component>(entity->parent());
}

uint64_t ulpsDistance(double a, double b)
{
static const auto max = std::numeric_limits<uint64_t>::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<double>::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
17 changes: 17 additions & 0 deletions src/commonutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
48 changes: 0 additions & 48 deletions src/utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint64_t>::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<double>::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<ComponentPtr> getImportedComponents(const ComponentEntityConstPtr &componentEntity)
{
std::vector<ComponentPtr> importedComponents;
Expand Down
17 changes: 0 additions & 17 deletions src/utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down

0 comments on commit 1f1b8c0

Please sign in to comment.