Skip to content

Commit 08d2c34

Browse files
committed
Offer 128 bit support
1 parent b847b23 commit 08d2c34

File tree

4 files changed

+131
-0
lines changed

4 files changed

+131
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// (C) Copyright Matt Borland 2022.
2+
// Use, modification and distribution are subject to the
3+
// Boost Software License, Version 1.0. (See accompanying file
4+
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5+
6+
#ifndef BOOST_MATH_SF_FAST_FLOAT_DISTANCE
7+
#define BOOST_MATH_SF_FAST_FLOAT_DISTANCE
8+
9+
#include <boost/math/special_functions/next.hpp>
10+
#include <boost/math/tools/throw_exception.hpp>
11+
#include <stdexcept>
12+
13+
#if defined(BOOST_MATH_USE_FLOAT128) && !defined(BOOST_MATH_STANDALONE)
14+
#include <boost/multiprecision/float128.hpp>
15+
#include <boost/multiprecision/detail/standalone_config.hpp>
16+
#define BOOST_MATH_USE_FAST_FLOAT128
17+
#endif
18+
19+
namespace boost { namespace math {
20+
21+
// https://randomascii.wordpress.com/2012/01/23/stupid-float-tricks-2/
22+
// https://blog.regehr.org/archives/959
23+
inline std::int32_t fast_float_distance(float a, float b)
24+
{
25+
return boost::math::float_distance(a, b);
26+
}
27+
28+
inline std::int64_t fast_float_distance(double a, double b)
29+
{
30+
return boost::math::float_distance(a, b);
31+
}
32+
33+
#ifdef BOOST_MATH_USE_FAST_FLOAT128
34+
boost::multiprecision::int128_type fast_float_distance(boost::multiprecision::float128_type a, boost::multiprecision::float128_type b)
35+
{
36+
using std::abs;
37+
using std::isfinite;
38+
39+
constexpr boost::multiprecision::float128_type tol = BOOST_MP_QUAD_MIN;
40+
41+
// 0, very small, and large magnitude distances all need special handling
42+
if (abs(a) == 0 || abs(b) == 0)
43+
{
44+
return 0;
45+
}
46+
else if (abs(a) < tol || abs(b) < tol)
47+
{
48+
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"));
49+
}
50+
51+
if (!(isfinite)(a))
52+
{
53+
BOOST_MATH_THROW_EXCEPTION(std::domain_error("Both arguments to fast_float_distnace must be finite"));
54+
}
55+
else if (!(isfinite)(b))
56+
{
57+
BOOST_MATH_THROW_EXCEPTION(std::domain_error("Both arguments to fast_float_distnace must be finite"));
58+
}
59+
60+
static_assert(sizeof(boost::multiprecision::int128_type) == sizeof(boost::multiprecision::float128_type));
61+
62+
boost::multiprecision::int128_type ai;
63+
boost::multiprecision::int128_type bi;
64+
std::memcpy(&ai, &a, sizeof(boost::multiprecision::float128_type));
65+
std::memcpy(&bi, &b, sizeof(boost::multiprecision::float128_type));
66+
67+
boost::multiprecision::int128_type result = bi - ai;
68+
69+
if (ai < 0 || bi < 0)
70+
{
71+
result = -result;
72+
}
73+
74+
return result;
75+
}
76+
77+
#endif
78+
79+
}} // Namespaces
80+
81+
#endif

include/boost/math/special_functions/next.hpp

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
#include <cstdint>
2323
#include <cstring>
2424

25+
#if defined(BOOST_MATH_USE_FLOAT128) && !defined(BOOST_MATH_STANDALONE)
26+
#include <boost/multiprecision/float128.hpp>
27+
#include <boost/multiprecision/detail/standalone_config.hpp>
28+
#define BOOST_MATH_USE_FAST_FLOAT128
29+
#endif
2530

2631
#if !defined(_CRAYC) && !defined(__CUDACC__) && (!defined(__GNUC__) || (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ > 3)))
2732
#if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(__SSE2__)

test/Jamfile.v2

+1
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ test-suite special_fun :
526526
[ run test_ldouble_simple.cpp ../../test/build//boost_unit_test_framework ]
527527
# Needs to run in release mode, as it's rather slow:
528528
[ run test_next.cpp pch ../../test/build//boost_unit_test_framework : : : release ]
529+
[ run test_fast_float_distance.cpp ../../test/build//boost_unit_test_framework : : : release [ check-target-builds ../config//has_float128 "GCC libquadmath and __float128 support" : <linkflags>"-Bstatic -lquadmath -Bdynamic" : <build>no ] ]
529530
[ run test_next_decimal.cpp pch ../../test/build//boost_unit_test_framework : : : release ]
530531
[ run test_owens_t.cpp ../../test/build//boost_unit_test_framework ]
531532
[ run test_polygamma.cpp test_instances//test_instances pch_light ../../test/build//boost_unit_test_framework ]

test/test_fast_float_distance.cpp

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// (C) Copyright John Maddock 2008.
2+
// (C) Copyright Matt Borland 2022.
3+
// Use, modification and distribution are subject to the
4+
// Boost Software License, Version 1.0. (See accompanying file
5+
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#include <boost/math/concepts/real_concept.hpp>
8+
#include <boost/test/tools/floating_point_comparison.hpp>
9+
#include <boost/math/special_functions/next.hpp>
10+
#include <boost/math/special_functions/ulp.hpp>
11+
#include <boost/math/special_functions/fast_float_distance.hpp>
12+
#include <boost/multiprecision/float128.hpp>
13+
14+
#include "math_unit_test.hpp"
15+
16+
17+
template <class T>
18+
void test_value(const T& val)
19+
{
20+
using namespace boost::math;
21+
22+
assert(fast_float_distance(float_next(val), val) == -1);
23+
assert(float_next(val) > val);
24+
assert(float_next(float_prior(val)) == val);
25+
26+
assert(fast_float_distance(float_advance(val, 4), val) == -4);
27+
assert(fast_float_distance(float_advance(val, -4), val) == 4);
28+
if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present))
29+
{
30+
assert(fast_float_distance(float_advance(float_next(float_next(val)), 4), float_next(float_next(val))) == -4);
31+
assert(fast_float_distance(float_advance(float_next(float_next(val)), -4), float_next(float_next(val))) == 4);
32+
}
33+
}
34+
35+
int main(void)
36+
{
37+
test_value(1.0f);
38+
test_value(1.0);
39+
40+
#ifdef BOOST_MATH_USE_FAST_FLOAT128
41+
test_value(boost::multiprecision::float128_type(0));
42+
test_value(__float128(0));
43+
#endif
44+
}

0 commit comments

Comments
 (0)