-
Notifications
You must be signed in to change notification settings - Fork 226
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
131 additions
and
0 deletions.
There are no files selected for viewing
81 changes: 81 additions & 0 deletions
81
include/boost/math/special_functions/fast_float_distance.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <boost/math/special_functions/next.hpp> | ||
#include <boost/math/tools/throw_exception.hpp> | ||
#include <stdexcept> | ||
|
||
#if defined(BOOST_MATH_USE_FLOAT128) && !defined(BOOST_MATH_STANDALONE) | ||
#include <boost/multiprecision/float128.hpp> | ||
#include <boost/multiprecision/detail/standalone_config.hpp> | ||
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <boost/math/concepts/real_concept.hpp> | ||
#include <boost/test/tools/floating_point_comparison.hpp> | ||
#include <boost/math/special_functions/next.hpp> | ||
#include <boost/math/special_functions/ulp.hpp> | ||
#include <boost/math/special_functions/fast_float_distance.hpp> | ||
#include <boost/multiprecision/float128.hpp> | ||
|
||
#include "math_unit_test.hpp" | ||
|
||
|
||
template <class T> | ||
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<T>::is_specialized && (std::numeric_limits<T>::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 | ||
} |