From fb37db7c332f67dfa50c8d00743e3a65300c4b8d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 5 Aug 2022 12:26:24 -0700 Subject: [PATCH 01/10] Add specialized float distance for type float --- include/boost/math/special_functions/next.hpp | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/boost/math/special_functions/next.hpp b/include/boost/math/special_functions/next.hpp index 07c55e8d4a..307f47512f 100644 --- a/include/boost/math/special_functions/next.hpp +++ b/include/boost/math/special_functions/next.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #if !defined(_CRAYC) && !defined(__CUDACC__) && (!defined(__GNUC__) || (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ > 3))) @@ -717,6 +718,36 @@ typename tools::promote_args::type float_distance(const T& a, const U& b) return boost::math::float_distance(a, b, policies::policy<>()); } +// https://randomascii.wordpress.com/2012/01/23/stupid-float-tricks-2/ +inline std::int32_t float_distance(float a, float b) +{ + using std::abs; + constexpr float tol = 2 * (std::numeric_limits::min)(); + + // 0, very small, and large magnitude distances all need special handling + if (abs(a) == 0 || abs(b) == 0) + { + return static_cast(float_distance(a, b, policies::policy<>())); + } + else if (abs(a) < tol || abs(b) < tol) + { + return static_cast(float_distance(a, b, policies::policy<>())); + } + + static_assert(sizeof(float) == sizeof(std::int32_t), "float is incorrect size."); + + const auto ai = *reinterpret_cast(&a); + const auto bi = *reinterpret_cast(&b); + auto result = bi - ai; + + if (ai < 0 || bi < 0) + { + result = -result; + } + + return result; +} + namespace detail{ template From 5fddf08d07a0bdaaa6f9b787960092fb6cda7a39 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 5 Aug 2022 17:21:30 -0700 Subject: [PATCH 02/10] Reinterpret cast breaks strict aliasing rules use memcpy --- include/boost/math/special_functions/next.hpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/include/boost/math/special_functions/next.hpp b/include/boost/math/special_functions/next.hpp index 307f47512f..048c866ece 100644 --- a/include/boost/math/special_functions/next.hpp +++ b/include/boost/math/special_functions/next.hpp @@ -16,9 +16,11 @@ #include #include #include +#include #include #include #include +#include #if !defined(_CRAYC) && !defined(__CUDACC__) && (!defined(__GNUC__) || (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ > 3))) @@ -719,10 +721,11 @@ typename tools::promote_args::type float_distance(const T& a, const U& b) } // https://randomascii.wordpress.com/2012/01/23/stupid-float-tricks-2/ +// https://blog.regehr.org/archives/959 inline std::int32_t float_distance(float a, float b) { using std::abs; - constexpr float tol = 2 * (std::numeric_limits::min)(); + constexpr auto tol = 2 * (std::numeric_limits::min)(); // 0, very small, and large magnitude distances all need special handling if (abs(a) == 0 || abs(b) == 0) @@ -736,8 +739,10 @@ inline std::int32_t float_distance(float a, float b) static_assert(sizeof(float) == sizeof(std::int32_t), "float is incorrect size."); - const auto ai = *reinterpret_cast(&a); - const auto bi = *reinterpret_cast(&b); + std::int32_t ai; + std::int32_t bi; + std::memcpy(&ai, &a, sizeof(float)); + std::memcpy(&bi, &b, sizeof(float)); auto result = bi - ai; if (ai < 0 || bi < 0) From 4660844386acc0c11c553028bc5e073edfff7bcd Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 5 Aug 2022 17:21:56 -0700 Subject: [PATCH 03/10] Add specialized float distance for type double --- include/boost/math/special_functions/next.hpp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/include/boost/math/special_functions/next.hpp b/include/boost/math/special_functions/next.hpp index 048c866ece..0da7aca475 100644 --- a/include/boost/math/special_functions/next.hpp +++ b/include/boost/math/special_functions/next.hpp @@ -743,6 +743,39 @@ inline std::int32_t float_distance(float a, float b) std::int32_t bi; std::memcpy(&ai, &a, sizeof(float)); std::memcpy(&bi, &b, sizeof(float)); + + auto result = bi - ai; + + if (ai < 0 || bi < 0) + { + result = -result; + } + + return result; +} + +inline std::int64_t float_distance(double a, double b) +{ + using std::abs; + constexpr auto tol = 2 * (std::numeric_limits::min)(); + + // 0, very small, and large magnitude distances all need special handling + if (abs(a) == 0 || abs(b) == 0) + { + return static_cast(float_distance(a, b, policies::policy<>())); + } + else if (abs(a) < tol || abs(b) < tol) + { + return static_cast(float_distance(a, b, policies::policy<>())); + } + + static_assert(sizeof(double) == sizeof(std::int64_t), "double is incorrect size."); + + std::int64_t ai; + std::int64_t bi; + std::memcpy(&ai, &a, sizeof(double)); + std::memcpy(&bi, &b, sizeof(double)); + auto result = bi - ai; if (ai < 0 || bi < 0) From cc0d6e958185d58b0f525af1fdc4d89aad28edce Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Sat, 13 Aug 2022 17:20:07 -0700 Subject: [PATCH 04/10] Improve error handling --- include/boost/math/special_functions/next.hpp | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/boost/math/special_functions/next.hpp b/include/boost/math/special_functions/next.hpp index 0da7aca475..4336c07e0e 100644 --- a/include/boost/math/special_functions/next.hpp +++ b/include/boost/math/special_functions/next.hpp @@ -725,6 +725,7 @@ typename tools::promote_args::type float_distance(const T& a, const U& b) inline std::int32_t float_distance(float a, float b) { using std::abs; + using std::isfinite; constexpr auto tol = 2 * (std::numeric_limits::min)(); // 0, very small, and large magnitude distances all need special handling @@ -737,6 +738,20 @@ inline std::int32_t float_distance(float a, float b) return static_cast(float_distance(a, b, policies::policy<>())); } + static const char* function = "float_distance<%1%>(%1%, %1%)"; + if(!(boost::math::isfinite)(a)) + { + return policies::raise_domain_error( + function, + "Argument a must be finite, but got %1%", a, policies::policy<>()); + } + if(!(boost::math::isfinite)(b)) + { + return policies::raise_domain_error( + function, + "Argument b must be finite, but got %1%", b, policies::policy<>()); + } + static_assert(sizeof(float) == sizeof(std::int32_t), "float is incorrect size."); std::int32_t ai; @@ -757,6 +772,7 @@ inline std::int32_t float_distance(float a, float b) inline std::int64_t float_distance(double a, double b) { using std::abs; + using std::isfinite; constexpr auto tol = 2 * (std::numeric_limits::min)(); // 0, very small, and large magnitude distances all need special handling @@ -768,6 +784,21 @@ inline std::int64_t float_distance(double a, double b) { return static_cast(float_distance(a, b, policies::policy<>())); } + + static const char* function = "float_distance<%1%>(%1%, %1%)"; + if(!(boost::math::isfinite)(a)) + { + return policies::raise_domain_error( + function, + "Argument a must be finite, but got %1%", a, policies::policy<>()); + } + if(!(boost::math::isfinite)(b)) + { + return policies::raise_domain_error( + function, + "Argument b must be finite, but got %1%", b, policies::policy<>()); + } + static_assert(sizeof(double) == sizeof(std::int64_t), "double is incorrect size."); From 00d2875758e5dd352b120d4326ee2e114984e62c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Sun, 21 Aug 2022 19:54:55 -0700 Subject: [PATCH 05/10] Offer 128 bit support --- .../special_functions/fast_float_distance.hpp | 81 +++++++++++++++++++ include/boost/math/special_functions/next.hpp | 5 ++ test/Jamfile.v2 | 1 + test/test_fast_float_distance.cpp | 44 ++++++++++ 4 files changed, 131 insertions(+) create mode 100644 include/boost/math/special_functions/fast_float_distance.hpp create mode 100644 test/test_fast_float_distance.cpp diff --git a/include/boost/math/special_functions/fast_float_distance.hpp b/include/boost/math/special_functions/fast_float_distance.hpp new file mode 100644 index 0000000000..ad07a1d3f0 --- /dev/null +++ b/include/boost/math/special_functions/fast_float_distance.hpp @@ -0,0 +1,81 @@ +// (C) Copyright Matt Borland 2022. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SF_FAST_FLOAT_DISTANCE +#define BOOST_MATH_SF_FAST_FLOAT_DISTANCE + +#include +#include +#include + +#if defined(BOOST_MATH_USE_FLOAT128) && !defined(BOOST_MATH_STANDALONE) +#include +#include +#define BOOST_MATH_USE_FAST_FLOAT128 +#endif + +namespace boost { namespace math { + +// https://randomascii.wordpress.com/2012/01/23/stupid-float-tricks-2/ +// https://blog.regehr.org/archives/959 +inline std::int32_t fast_float_distance(float a, float b) +{ + return boost::math::float_distance(a, b); +} + +inline std::int64_t fast_float_distance(double a, double b) +{ + return boost::math::float_distance(a, b); +} + +#ifdef BOOST_MATH_USE_FAST_FLOAT128 +boost::multiprecision::int128_type fast_float_distance(boost::multiprecision::float128_type a, boost::multiprecision::float128_type b) +{ + using std::abs; + using std::isfinite; + + constexpr boost::multiprecision::float128_type tol = BOOST_MP_QUAD_MIN; + + // 0, very small, and large magnitude distances all need special handling + if (abs(a) == 0 || abs(b) == 0) + { + return 0; + } + else if (abs(a) < tol || abs(b) < tol) + { + BOOST_MATH_THROW_EXCEPTION(std::domain_error("special handling is required for tiny distances. Please use boost::math::float_distance for a slower but safe solution")); + } + + if (!(isfinite)(a)) + { + BOOST_MATH_THROW_EXCEPTION(std::domain_error("Both arguments to fast_float_distnace must be finite")); + } + else if (!(isfinite)(b)) + { + BOOST_MATH_THROW_EXCEPTION(std::domain_error("Both arguments to fast_float_distnace must be finite")); + } + + static_assert(sizeof(boost::multiprecision::int128_type) == sizeof(boost::multiprecision::float128_type)); + + boost::multiprecision::int128_type ai; + boost::multiprecision::int128_type bi; + std::memcpy(&ai, &a, sizeof(boost::multiprecision::float128_type)); + std::memcpy(&bi, &b, sizeof(boost::multiprecision::float128_type)); + + boost::multiprecision::int128_type result = bi - ai; + + if (ai < 0 || bi < 0) + { + result = -result; + } + + return result; +} + +#endif + +}} // Namespaces + +#endif diff --git a/include/boost/math/special_functions/next.hpp b/include/boost/math/special_functions/next.hpp index 4336c07e0e..91f58f594e 100644 --- a/include/boost/math/special_functions/next.hpp +++ b/include/boost/math/special_functions/next.hpp @@ -22,6 +22,11 @@ #include #include +#if defined(BOOST_MATH_USE_FLOAT128) && !defined(BOOST_MATH_STANDALONE) +#include +#include +#define BOOST_MATH_USE_FAST_FLOAT128 +#endif #if !defined(_CRAYC) && !defined(__CUDACC__) && (!defined(__GNUC__) || (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ > 3))) #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(__SSE2__) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 57295797ff..41bb93c4d0 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -527,6 +527,7 @@ test-suite special_fun : [ run test_ldouble_simple.cpp ../../test/build//boost_unit_test_framework ] # Needs to run in release mode, as it's rather slow: [ run test_next.cpp pch ../../test/build//boost_unit_test_framework : : : release ] + [ run test_fast_float_distance.cpp ../../test/build//boost_unit_test_framework : : : release [ check-target-builds ../config//has_float128 "GCC libquadmath and __float128 support" : "-Bstatic -lquadmath -Bdynamic" : no ] ] [ run test_next_decimal.cpp pch ../../test/build//boost_unit_test_framework : : : release ] [ run test_owens_t.cpp ../../test/build//boost_unit_test_framework ] [ run test_polygamma.cpp test_instances//test_instances pch_light ../../test/build//boost_unit_test_framework ] diff --git a/test/test_fast_float_distance.cpp b/test/test_fast_float_distance.cpp new file mode 100644 index 0000000000..b2820233dc --- /dev/null +++ b/test/test_fast_float_distance.cpp @@ -0,0 +1,44 @@ +// (C) Copyright John Maddock 2008. +// (C) Copyright Matt Borland 2022. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include + +#include "math_unit_test.hpp" + + +template +void test_value(const T& val) +{ + using namespace boost::math; + + assert(fast_float_distance(float_next(val), val) == -1); + assert(float_next(val) > val); + assert(float_next(float_prior(val)) == val); + + assert(fast_float_distance(float_advance(val, 4), val) == -4); + assert(fast_float_distance(float_advance(val, -4), val) == 4); + if(std::numeric_limits::is_specialized && (std::numeric_limits::has_denorm == std::denorm_present)) + { + assert(fast_float_distance(float_advance(float_next(float_next(val)), 4), float_next(float_next(val))) == -4); + assert(fast_float_distance(float_advance(float_next(float_next(val)), -4), float_next(float_next(val))) == 4); + } +} + +int main(void) +{ + test_value(1.0f); + test_value(1.0); + + #ifdef BOOST_MATH_USE_FAST_FLOAT128 + test_value(boost::multiprecision::float128_type(0)); + test_value(__float128(0)); + #endif +} From 0a333eb92d2342eb2bd4fd4057584c9ffe59a017 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Sun, 21 Aug 2022 20:33:42 -0700 Subject: [PATCH 06/10] Add standalone support --- .../special_functions/fast_float_distance.hpp | 53 ++++++++++++++++++- include/boost/math/special_functions/next.hpp | 6 --- test/test_fast_float_distance.cpp | 17 +++--- 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/include/boost/math/special_functions/fast_float_distance.hpp b/include/boost/math/special_functions/fast_float_distance.hpp index ad07a1d3f0..17ddbd3373 100644 --- a/include/boost/math/special_functions/fast_float_distance.hpp +++ b/include/boost/math/special_functions/fast_float_distance.hpp @@ -9,11 +9,17 @@ #include #include #include +#include #if defined(BOOST_MATH_USE_FLOAT128) && !defined(BOOST_MATH_STANDALONE) #include #include #define BOOST_MATH_USE_FAST_FLOAT128 +#elif defined(BOOST_MATH_USE_FLOAT128) && defined(BOOST_MATH_STANDALONE) +# if __has_include() +# include +# define BOOST_MATH_USE_FAST_STANDALONE_FLOAT128 +# endif #endif namespace boost { namespace math { @@ -36,7 +42,7 @@ boost::multiprecision::int128_type fast_float_distance(boost::multiprecision::fl using std::abs; using std::isfinite; - constexpr boost::multiprecision::float128_type tol = BOOST_MP_QUAD_MIN; + constexpr boost::multiprecision::float128_type tol = 2 * BOOST_MP_QUAD_MIN; // 0, very small, and large magnitude distances all need special handling if (abs(a) == 0 || abs(b) == 0) @@ -74,6 +80,51 @@ boost::multiprecision::int128_type fast_float_distance(boost::multiprecision::fl return result; } +#elif defined(BOOST_MATH_USE_FAST_STANDALONE_FLOAT128) +__int128 fast_float_distance(__float128 a, __float128 b) +{ + constexpr __float128 tol = 2 * static_cast(1) * static_cast(DBL_MIN) * static_cast(DBL_MIN) * + static_cast(DBL_MIN) * static_cast(DBL_MIN) * static_cast(DBL_MIN) * + static_cast(DBL_MIN) * static_cast(DBL_MIN) * static_cast(DBL_MIN) * + static_cast(DBL_MIN) * static_cast(DBL_MIN) * static_cast(DBL_MIN) * + static_cast(DBL_MIN) * static_cast(DBL_MIN) * static_cast(DBL_MIN) * + static_cast(DBL_MIN) * static_cast(DBL_MIN) / 1073741824; + + // 0, very small, and large magnitude distances all need special handling + if (::fabsq(a) == 0 || ::fabsq(b) == 0) + { + return 0; + } + else if (::fabsq(a) < tol || ::fabsq(b) < tol) + { + BOOST_MATH_THROW_EXCEPTION(std::domain_error("special handling is required for tiny distances. Please use boost::math::float_distance for a slower but safe solution")); + } + + if (!(::isinfq)(a) && !(::isnanq)(a)) + { + BOOST_MATH_THROW_EXCEPTION(std::domain_error("Both arguments to fast_float_distnace must be finite")); + } + else if (!(::isinfq)(b) && !(::isnanq)(b)) + { + BOOST_MATH_THROW_EXCEPTION(std::domain_error("Both arguments to fast_float_distnace must be finite")); + } + + static_assert(sizeof(__int128) == sizeof(__float128)); + + __int128 ai; + __int128 bi; + std::memcpy(&ai, &a, sizeof(__float128)); + std::memcpy(&bi, &b, sizeof(__float128)); + + __int128 result = bi - ai; + + if (ai < 0 || bi < 0) + { + result = -result; + } + + return result; +} #endif }} // Namespaces diff --git a/include/boost/math/special_functions/next.hpp b/include/boost/math/special_functions/next.hpp index 91f58f594e..193fef8573 100644 --- a/include/boost/math/special_functions/next.hpp +++ b/include/boost/math/special_functions/next.hpp @@ -22,12 +22,6 @@ #include #include -#if defined(BOOST_MATH_USE_FLOAT128) && !defined(BOOST_MATH_STANDALONE) -#include -#include -#define BOOST_MATH_USE_FAST_FLOAT128 -#endif - #if !defined(_CRAYC) && !defined(__CUDACC__) && (!defined(__GNUC__) || (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ > 3))) #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(__SSE2__) #include "xmmintrin.h" diff --git a/test/test_fast_float_distance.cpp b/test/test_fast_float_distance.cpp index b2820233dc..9d75715523 100644 --- a/test/test_fast_float_distance.cpp +++ b/test/test_fast_float_distance.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "math_unit_test.hpp" @@ -19,16 +20,16 @@ void test_value(const T& val) { using namespace boost::math; - assert(fast_float_distance(float_next(val), val) == -1); - assert(float_next(val) > val); - assert(float_next(float_prior(val)) == val); + BOOST_MATH_ASSERT(fast_float_distance(float_next(val), val) == -1); + BOOST_MATH_ASSERT(float_next(val) > val); + BOOST_MATH_ASSERT(float_next(float_prior(val)) == val); - assert(fast_float_distance(float_advance(val, 4), val) == -4); - assert(fast_float_distance(float_advance(val, -4), val) == 4); + BOOST_MATH_ASSERT(fast_float_distance(float_advance(val, 4), val) == -4); + BOOST_MATH_ASSERT(fast_float_distance(float_advance(val, -4), val) == 4); if(std::numeric_limits::is_specialized && (std::numeric_limits::has_denorm == std::denorm_present)) { - assert(fast_float_distance(float_advance(float_next(float_next(val)), 4), float_next(float_next(val))) == -4); - assert(fast_float_distance(float_advance(float_next(float_next(val)), -4), float_next(float_next(val))) == 4); + BOOST_MATH_ASSERT(fast_float_distance(float_advance(float_next(float_next(val)), 4), float_next(float_next(val))) == -4); + BOOST_MATH_ASSERT(fast_float_distance(float_advance(float_next(float_next(val)), -4), float_next(float_next(val))) == 4); } } @@ -40,5 +41,7 @@ int main(void) #ifdef BOOST_MATH_USE_FAST_FLOAT128 test_value(boost::multiprecision::float128_type(0)); test_value(__float128(0)); + #elif defined(BOOST_MATH_USE_FAST_STANDALONE_FLOAT128) + test_value(__float128(0)); #endif } From 0a6b08cfe0370874ae8cc158b170a2193358ffb7 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 22 Aug 2022 18:56:59 -0700 Subject: [PATCH 07/10] Fix GCC 5 error for static_assert without message --- include/boost/math/special_functions/fast_float_distance.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/math/special_functions/fast_float_distance.hpp b/include/boost/math/special_functions/fast_float_distance.hpp index 17ddbd3373..e350c8efd2 100644 --- a/include/boost/math/special_functions/fast_float_distance.hpp +++ b/include/boost/math/special_functions/fast_float_distance.hpp @@ -63,7 +63,7 @@ boost::multiprecision::int128_type fast_float_distance(boost::multiprecision::fl BOOST_MATH_THROW_EXCEPTION(std::domain_error("Both arguments to fast_float_distnace must be finite")); } - static_assert(sizeof(boost::multiprecision::int128_type) == sizeof(boost::multiprecision::float128_type)); + static_assert(sizeof(boost::multiprecision::int128_type) == sizeof(boost::multiprecision::float128_type), "float128 is the wrong size"); boost::multiprecision::int128_type ai; boost::multiprecision::int128_type bi; From a481675826a613168c8c85e76c16a5e485eab259 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 22 Aug 2022 21:02:53 -0700 Subject: [PATCH 08/10] Fix type used in standalone mode --- .../math/special_functions/fast_float_distance.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/boost/math/special_functions/fast_float_distance.hpp b/include/boost/math/special_functions/fast_float_distance.hpp index e350c8efd2..125334de8d 100644 --- a/include/boost/math/special_functions/fast_float_distance.hpp +++ b/include/boost/math/special_functions/fast_float_distance.hpp @@ -83,12 +83,12 @@ boost::multiprecision::int128_type fast_float_distance(boost::multiprecision::fl #elif defined(BOOST_MATH_USE_FAST_STANDALONE_FLOAT128) __int128 fast_float_distance(__float128 a, __float128 b) { - constexpr __float128 tol = 2 * static_cast(1) * static_cast(DBL_MIN) * static_cast(DBL_MIN) * - static_cast(DBL_MIN) * static_cast(DBL_MIN) * static_cast(DBL_MIN) * - static_cast(DBL_MIN) * static_cast(DBL_MIN) * static_cast(DBL_MIN) * - static_cast(DBL_MIN) * static_cast(DBL_MIN) * static_cast(DBL_MIN) * - static_cast(DBL_MIN) * static_cast(DBL_MIN) * static_cast(DBL_MIN) * - static_cast(DBL_MIN) * static_cast(DBL_MIN) / 1073741824; + constexpr __float128 tol = 2 * static_cast<__float128>(1) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * + static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * + static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * + static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * + static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * + static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) / 1073741824; // 0, very small, and large magnitude distances all need special handling if (::fabsq(a) == 0 || ::fabsq(b) == 0) From a1fe97330c70a511125fc3f49ba9ce3f2d85aa1a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Sat, 15 Oct 2022 15:33:36 -0700 Subject: [PATCH 09/10] Include performance file and results --- .../performance/new_next_performance.cpp | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 reporting/performance/new_next_performance.cpp diff --git a/reporting/performance/new_next_performance.cpp b/reporting/performance/new_next_performance.cpp new file mode 100644 index 0000000000..e8ca0ea03d --- /dev/null +++ b/reporting/performance/new_next_performance.cpp @@ -0,0 +1,126 @@ +// (C) Copyright Matt Borland 2022. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +template +void float_distance(benchmark::State& state) +{ + const auto difference = static_cast(state.range(0)); + T left = 2; + T right = boost::math::float_advance(left, difference); + + for (auto _ : state) + { + benchmark::DoNotOptimize(boost::math::float_distance(left, right)); + } + state.SetComplexityN(state.range(0)); +} + +BENCHMARK_TEMPLATE(float_distance, float)->RangeMultiplier(2)->Range(1 << 1, 1 << 14)->Complexity()->UseRealTime(); +BENCHMARK_TEMPLATE(float_distance, double)->RangeMultiplier(2)->Range(1 << 1, 1 << 14)->Complexity()->UseRealTime(); + +BENCHMARK_MAIN(); + +/* +Run on Apple M1 Pro Arch using Apple Clang 14.0.0 (15OCT22) + +Original performance (Boost 1.80.0): + +Unable to determine clock rate from sysctl: hw.cpufrequency: No such file or directory +This does not affect benchmark measurements, only the metadata output. +2022-10-15T15:24:07-07:00 +Running ./new_next_performance +Run on (10 X 24.0916 MHz CPU s) +CPU Caches: + L1 Data 64 KiB + L1 Instruction 128 KiB + L2 Unified 4096 KiB (x10) +Load Average: 1.86, 2.53, 5.83 +--------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +--------------------------------------------------------------------------------- +float_distance/2/real_time 61.4 ns 61.4 ns 9074469 +float_distance/4/real_time 61.7 ns 61.7 ns 11384150 +float_distance/8/real_time 61.4 ns 61.4 ns 10814604 +float_distance/16/real_time 61.7 ns 61.7 ns 11348376 +float_distance/32/real_time 61.4 ns 61.4 ns 11387167 +float_distance/64/real_time 61.6 ns 61.6 ns 11131932 +float_distance/128/real_time 61.4 ns 61.4 ns 11382029 +float_distance/256/real_time 61.4 ns 61.4 ns 11307649 +float_distance/512/real_time 61.4 ns 61.4 ns 11376048 +float_distance/1024/real_time 61.4 ns 61.4 ns 11355748 +float_distance/2048/real_time 61.8 ns 61.8 ns 11373776 +float_distance/4096/real_time 61.4 ns 61.4 ns 11382368 +float_distance/8192/real_time 61.4 ns 61.4 ns 11353453 +float_distance/16384/real_time 61.4 ns 61.4 ns 11378298 +float_distance/real_time_BigO 61.48 (1) 61.47 (1) +float_distance/real_time_RMS 0 % 0 % +float_distance/2/real_time 55.6 ns 55.6 ns 12580218 +float_distance/4/real_time 55.6 ns 55.6 ns 12577835 +float_distance/8/real_time 55.6 ns 55.6 ns 12564909 +float_distance/16/real_time 56.2 ns 56.2 ns 12554909 +float_distance/32/real_time 56.0 ns 56.0 ns 12544381 +float_distance/64/real_time 55.6 ns 55.6 ns 12566488 +float_distance/128/real_time 55.6 ns 55.6 ns 12499581 +float_distance/256/real_time 55.6 ns 55.6 ns 12565661 +float_distance/512/real_time 56.1 ns 56.1 ns 12550023 +float_distance/1024/real_time 55.8 ns 55.8 ns 12568603 +float_distance/2048/real_time 55.6 ns 55.6 ns 12546049 +float_distance/4096/real_time 55.6 ns 55.6 ns 12528525 +float_distance/8192/real_time 55.9 ns 55.9 ns 12563030 +float_distance/16384/real_time 56.0 ns 56.0 ns 12447644 +float_distance/real_time_BigO 55.78 (1) 55.78 (1) +float_distance/real_time_RMS 0 % 0 % + +New performance: + +Unable to determine clock rate from sysctl: hw.cpufrequency: No such file or directory +This does not affect benchmark measurements, only the metadata output. +2022-10-15T15:31:37-07:00 +Running ./new_next_performance +Run on (10 X 24.122 MHz CPU s) +CPU Caches: + L1 Data 64 KiB + L1 Instruction 128 KiB + L2 Unified 4096 KiB (x10) +Load Average: 2.12, 2.17, 4.26 +--------------------------------------------------------------------------------- +Benchmark Time CPU Iterations +--------------------------------------------------------------------------------- +float_distance/2/real_time 15.8 ns 15.8 ns 42162717 +float_distance/4/real_time 15.9 ns 15.9 ns 44213877 +float_distance/8/real_time 15.8 ns 15.8 ns 43972542 +float_distance/16/real_time 15.8 ns 15.8 ns 44209456 +float_distance/32/real_time 15.8 ns 15.8 ns 44200244 +float_distance/64/real_time 15.8 ns 15.8 ns 44239293 +float_distance/128/real_time 15.8 ns 15.8 ns 44171202 +float_distance/256/real_time 15.8 ns 15.8 ns 44241507 +float_distance/512/real_time 15.9 ns 15.8 ns 44230034 +float_distance/1024/real_time 15.8 ns 15.8 ns 44241554 +float_distance/2048/real_time 15.8 ns 15.8 ns 44220802 +float_distance/4096/real_time 15.8 ns 15.8 ns 44220441 +float_distance/8192/real_time 15.9 ns 15.9 ns 44213994 +float_distance/16384/real_time 15.8 ns 15.8 ns 44215413 +float_distance/real_time_BigO 15.83 (1) 15.83 (1) +float_distance/real_time_RMS 0 % 0 % +float_distance/2/real_time 15.5 ns 15.5 ns 45098165 +float_distance/4/real_time 15.6 ns 15.6 ns 45065465 +float_distance/8/real_time 15.5 ns 15.5 ns 45058733 +float_distance/16/real_time 15.8 ns 15.7 ns 45078404 +float_distance/32/real_time 15.5 ns 15.5 ns 44832734 +float_distance/64/real_time 15.5 ns 15.5 ns 45077303 +float_distance/128/real_time 15.5 ns 15.5 ns 45067255 +float_distance/256/real_time 15.5 ns 15.5 ns 45073844 +float_distance/512/real_time 15.6 ns 15.6 ns 45109342 +float_distance/1024/real_time 15.5 ns 15.5 ns 44845180 +float_distance/2048/real_time 15.5 ns 15.5 ns 45051846 +float_distance/4096/real_time 15.5 ns 15.5 ns 45064317 +float_distance/8192/real_time 15.5 ns 15.5 ns 45115653 +float_distance/16384/real_time 15.5 ns 15.5 ns 45067642 +float_distance/real_time_BigO 15.54 (1) 15.54 (1) +float_distance/real_time_RMS 0 % 0 % +*/ From 73bb192f7a39d1c886c97fd0b4cdda7be75273a7 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Sat, 31 Dec 2022 17:33:41 +0100 Subject: [PATCH 10/10] Update include/boost/math/special_functions/fast_float_distance.hpp Co-authored-by: Alexander Grund --- include/boost/math/special_functions/fast_float_distance.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/math/special_functions/fast_float_distance.hpp b/include/boost/math/special_functions/fast_float_distance.hpp index 125334de8d..848aec0b7b 100644 --- a/include/boost/math/special_functions/fast_float_distance.hpp +++ b/include/boost/math/special_functions/fast_float_distance.hpp @@ -56,7 +56,7 @@ boost::multiprecision::int128_type fast_float_distance(boost::multiprecision::fl if (!(isfinite)(a)) { - BOOST_MATH_THROW_EXCEPTION(std::domain_error("Both arguments to fast_float_distnace must be finite")); + BOOST_MATH_THROW_EXCEPTION(std::domain_error("Both arguments to fast_float_distance must be finite")); } else if (!(isfinite)(b)) {