Skip to content

Instantly share code, notes, and snippets.

@royvandam
Created October 30, 2020 07:40
Show Gist options
  • Save royvandam/fb479b646b037f32dadb6e9c2e9031fd to your computer and use it in GitHub Desktop.
Save royvandam/fb479b646b037f32dadb6e9c2e9031fd to your computer and use it in GitHub Desktop.
Float comparison
#pragma once
#include <cfloat>
#include <cmath>
#include <cstdlib>
/**
* @brief Math related utility functions
*/
namespace Math {
/**
* @brief Union type for getting the integer representation of a float.
* Used for calculating the ULP distance between to floats. More information on
* comparing floats:
* https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
*/
union Float {
int32_t i;
float f;
constexpr Float(float val = 0.0f) : f(val) {}
constexpr bool isNegative() const {
return i < 0;
}
};
/**
* @brief Compare two floats relatively to each other based on a max epsilon
* distance.
* @param lhs Left hand side value.
* @param rhs Right hand side value.
* @param epsilon Max epsilon distance.
*/
constexpr bool EqualRel(float lhs, float rhs, float epsilon = FLT_EPSILON) {
float diff = std::abs(lhs - rhs);
float largest = std::max(std::abs(lhs), std::abs(rhs));
return diff <= largest * epsilon;
}
/**
* Compare two floats to each other based on a max ULP distance.
* https://en.wikipedia.org/wiki/Unit_in_the_last_place
* @param lhs Left hand side value.
* @param rhs Right hand side value.
* @param epsilon Max epsilon distance.
*/
constexpr bool EqualULP(float lhs, float rhs, int max_ulp_diff = 1) {
Float _lhs(lhs);
Float _rhs(rhs);
// Compare signs, in case they are different the values do not match.
if (_lhs.isNegative() != _rhs.isNegative()) {
// Check to make sure +0==-0
return lhs == rhs;
}
// Get the ULP distance
int ulp_diff = std::abs(_lhs.i - _rhs.i);
return ulp_diff <= max_ulp_diff;
}
} // namespace Math
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment