diff options
author | Sven Gothel <[email protected]> | 2020-12-23 13:40:23 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-12-23 13:40:23 +0100 |
commit | a3098623819455cf918dcfb425b1f6baab1ba408 (patch) | |
tree | 70447bc5dfa51bc7b4c5896b15e68bddd6f276ad /include | |
parent | c71c4166aeb11ca32b888b42bd79d408bb328f49 (diff) |
Add float_math.hpp for epsilon comparison; Test cleanup
Diffstat (limited to 'include')
-rw-r--r-- | include/jau/basic_algos.hpp | 1 | ||||
-rw-r--r-- | include/jau/float_math.hpp | 111 | ||||
-rw-r--r-- | include/jau/int_math.hpp | 1 | ||||
-rw-r--r-- | include/jau/test/catch2_ext.hpp | 8 |
4 files changed, 119 insertions, 2 deletions
diff --git a/include/jau/basic_algos.hpp b/include/jau/basic_algos.hpp index b901789..1585781 100644 --- a/include/jau/basic_algos.hpp +++ b/include/jau/basic_algos.hpp @@ -27,7 +27,6 @@ #define JAU_BASIC_ALGOS_HPP_ #include <mutex> -#include <cmath> namespace jau { /** diff --git a/include/jau/float_math.hpp b/include/jau/float_math.hpp new file mode 100644 index 0000000..4cac53c --- /dev/null +++ b/include/jau/float_math.hpp @@ -0,0 +1,111 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef JAU_BASIC_FLOAT_MATH_HPP_ +#define JAU_BASIC_FLOAT_MATH_HPP_ + +#include <cmath> +#include <type_traits> +#include <algorithm> + +namespace jau { + /** + // ************************************************* + // ************************************************* + // ************************************************* + */ + + /** + * Returns true, if both integer point values differ less than the given delta. + * @tparam T an integral type + * @param a value to compare + * @param b value to compare + * @param delta the maximum difference both values may differ + */ + template<class T> + bool in_range(const T& a, const T& b, const T& delta) + { + const T diff = std::fabs(a-b); + return diff <= delta || + diff < std::numeric_limits<T>::min(); // subnormal limit + } + + /** + * Calculates the smallest floating point value approximation + * the given type T can represent, the machine epsilon of T. + * @tparam T a non integer float type + * @return machine epsilon of T + */ + template<class T> + typename std::enable_if<!std::numeric_limits<T>::is_integer, T>::type + machineEpsilon() { + const T one(1); + const T two(2); + T x = one, res; + do { + res = x; + } while (one + (x /= two) > one); + return res; + } + + /** + * Returns true, if both floating point values are equal + * in the sense that their potential difference is less or equal <code>epsilon * ulp</code>. + * @tparam T a non integer float type + * @param a value to compare + * @param b value to compare + * @param ulp desired precision in ULPs (units in the last place), defaults to 1 + * @param epsilon the machine epsilon of type T, defaults to <code>std::numeric_limits<T>::epsilon()</code> + */ + template<class T> + typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type + machine_equal(const T& a, const T& b, int ulp=1, const T& epsilon=std::numeric_limits<T>::epsilon()) + { + const T diff = std::fabs(a-b); + return diff <= epsilon * ulp || + diff < std::numeric_limits<T>::min(); // subnormal limit + } + + /** + * Returns true, if both floating point values are equal + * in the sense that their potential difference is less or equal <code>epsilon * |a+b| * ulp</code>, + * where <code>|a+b|</code> scales epsilon to the magnitude of used values. + * @tparam T a non integer float type + * @param a value to compare + * @param b value to compare + * @param ulp desired precision in ULPs (units in the last place), defaults to 1 + * @param epsilon the machine epsilon of type T, defaults to <code>std::numeric_limits<T>::epsilon()</code> + */ + template<class T> + typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type + almost_equal(const T& a, const T& b, int ulp=1, const T& epsilon=std::numeric_limits<T>::epsilon()) + { + const T diff = std::fabs(a-b); + return diff <= epsilon * std::fabs(a+b) * ulp || + diff < std::numeric_limits<T>::min(); // subnormal limit + } + +} // namespace jau + +#endif /* JAU_BASIC_FLOAT_MATH_HPP_ */ diff --git a/include/jau/int_math.hpp b/include/jau/int_math.hpp index 92bacd7..cd37795 100644 --- a/include/jau/int_math.hpp +++ b/include/jau/int_math.hpp @@ -26,7 +26,6 @@ #ifndef JAU_BASIC_INT_MATH_HPP_ #define JAU_BASIC_INT_MATH_HPP_ -#include <mutex> #include <cmath> namespace jau { diff --git a/include/jau/test/catch2_ext.hpp b/include/jau/test/catch2_ext.hpp index 03a5d15..a7b9c6f 100644 --- a/include/jau/test/catch2_ext.hpp +++ b/include/jau/test/catch2_ext.hpp @@ -12,6 +12,7 @@ #define CATCH2_EXT_H #include <catch2/catch_amalgamated.hpp> +#include <jau/float_math.hpp> // namespace Catch { /////////////////////////////////////////////////////////////////////////////// @@ -34,6 +35,13 @@ #define REQUIRE_MSG(MSG, ... ) INTERNAL_CATCH_TEST_M( MSG, "REQUIRE: ", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define INFO_STR( msg ) INTERNAL_CATCH_INFO( "INFO", static_cast<std::string>(msg) ) + + #define REQUIRE_EPSI(a,b) INTERNAL_CATCH_TEST( "REQUIRE: ", Catch::ResultDisposition::Normal, jau::machine_equal(a, b)) + #define REQUIRE_EPSI_MSG(m,a,b) INTERNAL_CATCH_TEST_M( m, "REQUIRE: ", Catch::ResultDisposition::Normal, jau::machine_equal(a, b)) + + #define REQUIRE_DIFF(a,b,d) INTERNAL_CATCH_TEST( "REQUIRE: ", Catch::ResultDisposition::Normal, jau::machine_equal(a, b, 1, d)) + #define REQUIRE_DIFF_MSG(m,a,b,d) INTERNAL_CATCH_TEST_M( m, "REQUIRE: ", Catch::ResultDisposition::Normal, jau::machine_equal(a, b, 1, d)) + // } #endif // CATCH2_EXT_H |