This PR adds the code of Boost.Math as of version 1.89 into the third-party directory, as discussed in a recent RFC [1]. The goal is for this code to be used as a back-end for the C++17 Math Special Functions. As explained in third-paty/README.md, this code is cleared for usage inside libc++ for the Math Special functions, however the LLVM Foundation should be consulted before using this code anywhere else in the LLVM project, due to the fact that it is under the Boost Software License (as opposed to the usual LLVM license). See the RFC [1] for more details. [1]: https://discourse.llvm.org/t/rfc-libc-taking-a-dependency-on-boost-math-for-the-c-17-math-special-functions
103 lines
3.4 KiB
C++
103 lines
3.4 KiB
C++
// (C) Copyright John Maddock 2015.
|
|
// 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_SPECIAL_ULP_HPP
|
|
#define BOOST_MATH_SPECIAL_ULP_HPP
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma once
|
|
#endif
|
|
|
|
#include <boost/math/special_functions/math_fwd.hpp>
|
|
#include <boost/math/policies/error_handling.hpp>
|
|
#include <boost/math/special_functions/fpclassify.hpp>
|
|
#include <boost/math/special_functions/next.hpp>
|
|
#include <boost/math/tools/precision.hpp>
|
|
|
|
namespace boost{ namespace math{ namespace detail{
|
|
|
|
template <class T, class Policy>
|
|
T ulp_imp(const T& val, const std::true_type&, const Policy& pol)
|
|
{
|
|
BOOST_MATH_STD_USING
|
|
int expon;
|
|
static const char* function = "ulp<%1%>(%1%)";
|
|
|
|
int fpclass = (boost::math::fpclassify)(val);
|
|
|
|
if(fpclass == FP_NAN)
|
|
{
|
|
return policies::raise_domain_error<T>(function, "Argument must be finite, but got %1%", val, pol);
|
|
}
|
|
else if((fpclass == (int)FP_INFINITE) || (fabs(val) >= tools::max_value<T>()))
|
|
{
|
|
return (val < 0 ? -1 : 1) * policies::raise_overflow_error<T>(function, nullptr, pol);
|
|
}
|
|
else if(fpclass == FP_ZERO)
|
|
return detail::get_smallest_value<T>();
|
|
//
|
|
// This code is almost the same as that for float_next, except for negative integers,
|
|
// where we preserve the relation ulp(x) == ulp(-x) as does Java:
|
|
//
|
|
frexp(fabs(val), &expon);
|
|
T diff = ldexp(T(1), expon - tools::digits<T>());
|
|
if(diff == 0)
|
|
diff = detail::get_smallest_value<T>();
|
|
return diff;
|
|
}
|
|
// non-binary version:
|
|
template <class T, class Policy>
|
|
T ulp_imp(const T& val, const std::false_type&, const Policy& pol)
|
|
{
|
|
static_assert(std::numeric_limits<T>::is_specialized, "Type T must be specialized.");
|
|
static_assert(std::numeric_limits<T>::radix != 2, "Type T must be specialized.");
|
|
BOOST_MATH_STD_USING
|
|
int expon;
|
|
static const char* function = "ulp<%1%>(%1%)";
|
|
|
|
int fpclass = (boost::math::fpclassify)(val);
|
|
|
|
if(fpclass == FP_NAN)
|
|
{
|
|
return policies::raise_domain_error<T>(function,"Argument must be finite, but got %1%", val, pol);
|
|
}
|
|
else if((fpclass == FP_INFINITE) || (fabs(val) >= tools::max_value<T>()))
|
|
{
|
|
return (val < 0 ? -1 : 1) * policies::raise_overflow_error<T>(function, nullptr, pol);
|
|
}
|
|
else if(fpclass == FP_ZERO)
|
|
return detail::get_smallest_value<T>();
|
|
//
|
|
// This code is almost the same as that for float_next, except for negative integers,
|
|
// where we preserve the relation ulp(x) == ulp(-x) as does Java:
|
|
//
|
|
expon = 1 + ilogb(fabs(val));
|
|
T diff = scalbn(T(1), expon - std::numeric_limits<T>::digits);
|
|
if(diff == 0)
|
|
diff = detail::get_smallest_value<T>();
|
|
return diff; // LCOV_EXCL_LINE previous lines are covered so this one must be too.
|
|
}
|
|
|
|
}
|
|
|
|
template <class T, class Policy>
|
|
inline typename tools::promote_args<T>::type ulp(const T& val, const Policy& pol)
|
|
{
|
|
typedef typename tools::promote_args<T>::type result_type;
|
|
return detail::ulp_imp(static_cast<result_type>(val), std::integral_constant<bool, !std::numeric_limits<result_type>::is_specialized || (std::numeric_limits<result_type>::radix == 2)>(), pol);
|
|
}
|
|
|
|
template <class T>
|
|
inline typename tools::promote_args<T>::type ulp(const T& val)
|
|
{
|
|
return ulp(val, policies::policy<>());
|
|
}
|
|
|
|
|
|
}} // namespaces
|
|
|
|
#endif // BOOST_MATH_SPECIAL_ULP_HPP
|
|
|