mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-08-03 14:07:48 +00:00
Added thirdparty: boost library
This commit is contained in:
+89
@@ -0,0 +1,89 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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)
|
||||
//
|
||||
// Constepxr implementation of abs (see c.math.abs secion 26.8.2 of the ISO standard)
|
||||
|
||||
#ifndef BOOST_MATH_CCMATH_ABS
|
||||
#define BOOST_MATH_CCMATH_ABS
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/abs.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/tools/assert.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
constexpr T abs_impl(T x) noexcept
|
||||
{
|
||||
if ((boost::math::ccmath::isnan)(x))
|
||||
{
|
||||
return std::numeric_limits<T>::quiet_NaN();
|
||||
}
|
||||
else if (x == static_cast<T>(-0))
|
||||
{
|
||||
return static_cast<T>(0);
|
||||
}
|
||||
|
||||
if constexpr (std::is_integral_v<T>)
|
||||
{
|
||||
BOOST_MATH_ASSERT(x != (std::numeric_limits<T>::min)());
|
||||
}
|
||||
|
||||
return x >= 0 ? x : -x;
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename T, std::enable_if_t<!std::is_unsigned_v<T>, bool> = true>
|
||||
constexpr T abs(T x) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
return detail::abs_impl<T>(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::abs;
|
||||
return abs(x);
|
||||
}
|
||||
}
|
||||
|
||||
// If abs() is called with an argument of type X for which is_unsigned_v<X> is true and if X
|
||||
// cannot be converted to int by integral promotion (7.3.7), the program is ill-formed.
|
||||
template <typename T, std::enable_if_t<std::is_unsigned_v<T>, bool> = true>
|
||||
constexpr T abs(T x) noexcept
|
||||
{
|
||||
if constexpr (std::is_convertible_v<T, int>)
|
||||
{
|
||||
return detail::abs_impl<int>(static_cast<int>(x));
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(sizeof(T) == 0, "Taking the absolute value of an unsigned value not convertible to int is UB.");
|
||||
return T(0); // Unreachable, but suppresses warnings
|
||||
}
|
||||
}
|
||||
|
||||
constexpr long int labs(long int j) noexcept
|
||||
{
|
||||
return boost::math::ccmath::abs(j);
|
||||
}
|
||||
|
||||
constexpr long long int llabs(long long int j) noexcept
|
||||
{
|
||||
return boost::math::ccmath::abs(j);
|
||||
}
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_ABS
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// (C) Copyright Matt Borland 2021 - 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_CCMATH_HPP
|
||||
#define BOOST_MATH_CCMATH_HPP
|
||||
|
||||
#include <boost/math/ccmath/sqrt.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/fabs.hpp>
|
||||
#include <boost/math/ccmath/isfinite.hpp>
|
||||
#include <boost/math/ccmath/isnormal.hpp>
|
||||
#include <boost/math/ccmath/fpclassify.hpp>
|
||||
#include <boost/math/ccmath/frexp.hpp>
|
||||
#include <boost/math/ccmath/div.hpp>
|
||||
#include <boost/math/ccmath/logb.hpp>
|
||||
#include <boost/math/ccmath/ilogb.hpp>
|
||||
#include <boost/math/ccmath/scalbn.hpp>
|
||||
#include <boost/math/ccmath/scalbln.hpp>
|
||||
#include <boost/math/ccmath/floor.hpp>
|
||||
#include <boost/math/ccmath/ceil.hpp>
|
||||
#include <boost/math/ccmath/trunc.hpp>
|
||||
#include <boost/math/ccmath/modf.hpp>
|
||||
#include <boost/math/ccmath/round.hpp>
|
||||
#include <boost/math/ccmath/fmod.hpp>
|
||||
#include <boost/math/ccmath/remainder.hpp>
|
||||
#include <boost/math/ccmath/copysign.hpp>
|
||||
#include <boost/math/ccmath/hypot.hpp>
|
||||
#include <boost/math/ccmath/fdim.hpp>
|
||||
#include <boost/math/ccmath/fmax.hpp>
|
||||
#include <boost/math/ccmath/fmin.hpp>
|
||||
#include <boost/math/ccmath/isgreater.hpp>
|
||||
#include <boost/math/ccmath/isgreaterequal.hpp>
|
||||
#include <boost/math/ccmath/isless.hpp>
|
||||
#include <boost/math/ccmath/islessequal.hpp>
|
||||
#include <boost/math/ccmath/isunordered.hpp>
|
||||
#include <boost/math/ccmath/fma.hpp>
|
||||
#include <boost/math/ccmath/next.hpp>
|
||||
#include <boost/math/ccmath/signbit.hpp>
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_HPP
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_CEIL_HPP
|
||||
#define BOOST_MATH_CCMATH_CEIL_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/ceil.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/floor.hpp>
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
inline constexpr T ceil_impl(T arg) noexcept
|
||||
{
|
||||
T result = boost::math::ccmath::floor(arg);
|
||||
|
||||
if(result == arg)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return result + 1;
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
inline constexpr Real ceil(Real arg) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
|
||||
{
|
||||
return boost::math::ccmath::abs(arg) == Real(0) ? arg :
|
||||
boost::math::ccmath::isinf(arg) ? arg :
|
||||
boost::math::ccmath::isnan(arg) ? arg :
|
||||
boost::math::ccmath::detail::ceil_impl(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::ceil;
|
||||
return ceil(arg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
inline constexpr double ceil(Z arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::ceil(static_cast<double>(arg));
|
||||
}
|
||||
|
||||
inline constexpr float ceilf(float arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::ceil(arg);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline constexpr long double ceill(long double arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::ceil(arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_CEIL_HPP
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_COPYSIGN_HPP
|
||||
#define BOOST_MATH_CCMATH_COPYSIGN_HPP
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <boost/math/tools/is_constant_evaluated.hpp>
|
||||
#include <boost/math/tools/promotion.hpp>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/signbit.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
constexpr T copysign_impl(const T mag, const T sgn) noexcept
|
||||
{
|
||||
if (boost::math::ccmath::signbit(sgn))
|
||||
{
|
||||
return -boost::math::ccmath::abs(mag);
|
||||
}
|
||||
else
|
||||
{
|
||||
return boost::math::ccmath::abs(mag);
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
constexpr Real copysign(Real mag, Real sgn) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(mag))
|
||||
{
|
||||
return boost::math::ccmath::detail::copysign_impl(mag, sgn);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::copysign;
|
||||
return copysign(mag, sgn);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
constexpr auto copysign(T1 mag, T2 sgn) noexcept
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(mag))
|
||||
{
|
||||
using promoted_type = boost::math::tools::promote_args_2_t<T1, T2>;
|
||||
return boost::math::ccmath::copysign(static_cast<promoted_type>(mag), static_cast<promoted_type>(sgn));
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::copysign;
|
||||
return copysign(mag, sgn);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr float copysignf(float mag, float sgn) noexcept
|
||||
{
|
||||
return boost::math::ccmath::copysign(mag, sgn);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
constexpr long double copysignl(long double mag, long double sgn) noexcept
|
||||
{
|
||||
return boost::math::ccmath::copysign(mag, sgn);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_COPYSIGN_HPP
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
// (C) Copyright John Maddock 2023.
|
||||
// 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)
|
||||
//
|
||||
// Core configuration for ccmath functions, basically will they work or not?
|
||||
|
||||
#ifndef BOOST_MATH_CCMATH_DETAIL_CONFIG
|
||||
#define BOOST_MATH_CCMATH_DETAIL_CONFIG
|
||||
|
||||
#include <cmath>
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
#include <boost/math/tools/is_constant_evaluated.hpp>
|
||||
#include <boost/math/tools/is_standalone.hpp>
|
||||
|
||||
#ifndef BOOST_MATH_STANDALONE
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_NO_CXX17_IF_CONSTEXPR
|
||||
# define BOOST_MATH_NO_CCMATH
|
||||
#endif
|
||||
|
||||
#else // BOOST_MATH_STANDALONE
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
#if defined(_MSVC_LANG) && (_MSVC_LANG < 201703)
|
||||
# define BOOST_MATH_NO_CCMATH
|
||||
#endif
|
||||
|
||||
#else // _MSC_VER
|
||||
|
||||
#if (__cplusplus < 201703)
|
||||
# define BOOST_MATH_NO_CCMATH
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
//
|
||||
// Don't check here for msvc as they didn't get std lib configuration macros at the same time as C++17 <type_traits>
|
||||
//
|
||||
#if (__cpp_lib_bool_constant < 201505L) && !defined(BOOST_MATH_NO_CCMATH)
|
||||
# define BOOST_MATH_NO_CCMATH
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_DETAIL_SWAP_HPP
|
||||
#define BOOST_MATH_CCMATH_DETAIL_SWAP_HPP
|
||||
|
||||
namespace boost::math::ccmath::detail {
|
||||
|
||||
template <typename T>
|
||||
inline constexpr void swap(T& x, T& y) noexcept
|
||||
{
|
||||
T temp = x;
|
||||
x = y;
|
||||
y = temp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_DETAIL_SWAP_HPP
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_DIV_HPP
|
||||
#define BOOST_MATH_CCMATH_DIV_HPP
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstdint>
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/div.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename ReturnType, typename Z>
|
||||
inline constexpr ReturnType div_impl(const Z x, const Z y) noexcept
|
||||
{
|
||||
// std::div_t/ldiv_t/lldiv_t/imaxdiv_t can be defined as either { Z quot; Z rem; }; or { Z rem; Z quot; };
|
||||
// so don't use braced initialization to guarantee compatibility
|
||||
ReturnType ans {0, 0};
|
||||
|
||||
ans.quot = x / y;
|
||||
ans.rem = x % y;
|
||||
|
||||
return ans;
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
// Used for types other than built-ins (e.g. boost multiprecision)
|
||||
template <typename Z>
|
||||
struct div_t
|
||||
{
|
||||
Z quot;
|
||||
Z rem;
|
||||
};
|
||||
|
||||
template <typename Z>
|
||||
inline constexpr auto div(Z x, Z y) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<Z, int>)
|
||||
{
|
||||
return detail::div_impl<std::div_t>(x, y);
|
||||
}
|
||||
else if constexpr (std::is_same_v<Z, long>)
|
||||
{
|
||||
return detail::div_impl<std::ldiv_t>(x, y);
|
||||
}
|
||||
else if constexpr (std::is_same_v<Z, long long>)
|
||||
{
|
||||
return detail::div_impl<std::lldiv_t>(x, y);
|
||||
}
|
||||
else if constexpr (std::is_same_v<Z, std::intmax_t>)
|
||||
{
|
||||
return detail::div_impl<std::imaxdiv_t>(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
return detail::div_impl<boost::math::ccmath::div_t<Z>>(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
inline constexpr std::ldiv_t ldiv(long x, long y) noexcept
|
||||
{
|
||||
return detail::div_impl<std::ldiv_t>(x, y);
|
||||
}
|
||||
|
||||
inline constexpr std::lldiv_t lldiv(long long x, long long y) noexcept
|
||||
{
|
||||
return detail::div_impl<std::lldiv_t>(x, y);
|
||||
}
|
||||
|
||||
inline constexpr std::imaxdiv_t imaxdiv(std::intmax_t x, std::intmax_t y) noexcept
|
||||
{
|
||||
return detail::div_impl<std::imaxdiv_t>(x, y);
|
||||
}
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_DIV_HPP
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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)
|
||||
//
|
||||
// Constepxr implementation of fabs (see c.math.abs secion 26.8.2 of the ISO standard)
|
||||
|
||||
#ifndef BOOST_MATH_CCMATH_FABS
|
||||
#define BOOST_MATH_CCMATH_FABS
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/fabs.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
template <typename T>
|
||||
inline constexpr auto fabs(T x) noexcept
|
||||
{
|
||||
return boost::math::ccmath::abs(x);
|
||||
}
|
||||
|
||||
inline constexpr float fabsf(float x) noexcept
|
||||
{
|
||||
return boost::math::ccmath::abs(x);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline constexpr long double fabsl(long double x) noexcept
|
||||
{
|
||||
return boost::math::ccmath::abs(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_FABS
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
// (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_CCMATH_FDIM_HPP
|
||||
#define BOOST_MATH_CCMATH_FDIM_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/fdim.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/tools/promotion.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
constexpr T fdim_impl(const T x, const T y) noexcept
|
||||
{
|
||||
if (x <= y)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if ((y < 0) && (x > (std::numeric_limits<T>::max)() + y))
|
||||
{
|
||||
return std::numeric_limits<T>::infinity();
|
||||
}
|
||||
else
|
||||
{
|
||||
return x - y;
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
constexpr Real fdim(Real x, Real y) noexcept
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
if (boost::math::ccmath::isnan(x))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(y))
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
return boost::math::ccmath::detail::fdim_impl(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::fdim;
|
||||
return fdim(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
constexpr auto fdim(T1 x, T2 y) noexcept
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
using promoted_type = boost::math::tools::promote_args_2_t<T1, T2>;
|
||||
return boost::math::ccmath::fdim(promoted_type(x), promoted_type(y));
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::fdim;
|
||||
return fdim(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr float fdimf(float x, float y) noexcept
|
||||
{
|
||||
return boost::math::ccmath::fdim(x, y);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
constexpr long double fdiml(long double x, long double y) noexcept
|
||||
{
|
||||
return boost::math::ccmath::fdim(x, y);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespace boost::math::ccmath
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_FDIM_HPP
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_FLOOR_HPP
|
||||
#define BOOST_MATH_CCMATH_FLOOR_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/floor.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
inline constexpr T floor_pos_impl(T arg) noexcept
|
||||
{
|
||||
T result = 1;
|
||||
|
||||
if(result < arg)
|
||||
{
|
||||
while(result < arg)
|
||||
{
|
||||
result *= 2;
|
||||
}
|
||||
while(result > arg)
|
||||
{
|
||||
--result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return T(0);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline constexpr T floor_neg_impl(T arg) noexcept
|
||||
{
|
||||
T result = -1;
|
||||
|
||||
if(result > arg)
|
||||
{
|
||||
while(result > arg)
|
||||
{
|
||||
result *= 2;
|
||||
}
|
||||
while(result < arg)
|
||||
{
|
||||
++result;
|
||||
}
|
||||
if(result != arg)
|
||||
{
|
||||
--result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline constexpr T floor_impl(T arg) noexcept
|
||||
{
|
||||
if(arg > 0)
|
||||
{
|
||||
return floor_pos_impl(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
return floor_neg_impl(arg);
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
inline constexpr Real floor(Real arg) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
|
||||
{
|
||||
return boost::math::ccmath::abs(arg) == Real(0) ? arg :
|
||||
boost::math::ccmath::isinf(arg) ? arg :
|
||||
boost::math::ccmath::isnan(arg) ? arg :
|
||||
boost::math::ccmath::detail::floor_impl(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::floor;
|
||||
return floor(arg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
inline constexpr double floor(Z arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::floor(static_cast<double>(arg));
|
||||
}
|
||||
|
||||
inline constexpr float floorf(float arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::floor(arg);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline constexpr long double floorl(long double arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::floor(arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_FLOOR_HPP
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
// (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_CCMATH_FMA_HPP
|
||||
#define BOOST_MATH_CCMATH_FMA_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/fma.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
constexpr T fma_imp(const T x, const T y, const T z) noexcept
|
||||
{
|
||||
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__INTEL_LLVM_COMPILER)
|
||||
if constexpr (std::is_same_v<T, float>)
|
||||
{
|
||||
return __builtin_fmaf(x, y, z);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, double>)
|
||||
{
|
||||
return __builtin_fma(x, y, z);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, long double>)
|
||||
{
|
||||
return __builtin_fmal(x, y, z);
|
||||
}
|
||||
#endif
|
||||
|
||||
// If we can't use compiler intrinsics hope that -fma flag optimizes this call to fma instruction
|
||||
return (x * y) + z;
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
constexpr Real fma(Real x, Real y, Real z) noexcept
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
if (x == 0 && boost::math::ccmath::isinf(y))
|
||||
{
|
||||
return std::numeric_limits<Real>::quiet_NaN();
|
||||
}
|
||||
else if (y == 0 && boost::math::ccmath::isinf(x))
|
||||
{
|
||||
return std::numeric_limits<Real>::quiet_NaN();
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(x))
|
||||
{
|
||||
return std::numeric_limits<Real>::quiet_NaN();
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(y))
|
||||
{
|
||||
return std::numeric_limits<Real>::quiet_NaN();
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(z))
|
||||
{
|
||||
return std::numeric_limits<Real>::quiet_NaN();
|
||||
}
|
||||
|
||||
return boost::math::ccmath::detail::fma_imp(x, y, z);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::fma;
|
||||
return fma(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
constexpr auto fma(T1 x, T2 y, T3 z) noexcept
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
// If the type is an integer (e.g. epsilon == 0) then set the epsilon value to 1 so that type is at a minimum
|
||||
// cast to double
|
||||
constexpr auto T1p = std::numeric_limits<T1>::epsilon() > 0 ? std::numeric_limits<T1>::epsilon() : 1;
|
||||
constexpr auto T2p = std::numeric_limits<T2>::epsilon() > 0 ? std::numeric_limits<T2>::epsilon() : 1;
|
||||
constexpr auto T3p = std::numeric_limits<T3>::epsilon() > 0 ? std::numeric_limits<T3>::epsilon() : 1;
|
||||
|
||||
using promoted_type =
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
std::conditional_t<T1p <= LDBL_EPSILON && T1p <= T2p, T1,
|
||||
std::conditional_t<T2p <= LDBL_EPSILON && T2p <= T1p, T2,
|
||||
std::conditional_t<T3p <= LDBL_EPSILON && T3p <= T2p, T3,
|
||||
#endif
|
||||
std::conditional_t<T1p <= DBL_EPSILON && T1p <= T2p, T1,
|
||||
std::conditional_t<T2p <= DBL_EPSILON && T2p <= T1p, T2,
|
||||
std::conditional_t<T3p <= DBL_EPSILON && T3p <= T2p, T3, double
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
>>>>>>;
|
||||
#else
|
||||
>>>;
|
||||
#endif
|
||||
|
||||
return boost::math::ccmath::fma(promoted_type(x), promoted_type(y), promoted_type(z));
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::fma;
|
||||
return fma(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr float fmaf(float x, float y, float z) noexcept
|
||||
{
|
||||
return boost::math::ccmath::fma(x, y, z);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
constexpr long double fmal(long double x, long double y, long double z) noexcept
|
||||
{
|
||||
return boost::math::ccmath::fma(x, y, z);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespace boost::math::ccmath
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_FMA_HPP
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
// (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_CCMATH_FMAX_HPP
|
||||
#define BOOST_MATH_CCMATH_FMAX_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/fmax.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/tools/promotion.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
constexpr T fmax_impl(const T x, const T y) noexcept
|
||||
{
|
||||
if (x > y)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
else
|
||||
{
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
constexpr Real fmax(Real x, Real y) noexcept
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
if (boost::math::ccmath::isnan(x))
|
||||
{
|
||||
return y;
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(y))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
return boost::math::ccmath::detail::fmax_impl(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::fmax;
|
||||
return fmax(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
constexpr auto fmax(T1 x, T2 y) noexcept
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
using promoted_type = boost::math::tools::promote_args_2_t<T1, T2>;
|
||||
return boost::math::ccmath::fmax(static_cast<promoted_type>(x), static_cast<promoted_type>(y));
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::fmax;
|
||||
return fmax(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr float fmaxf(float x, float y) noexcept
|
||||
{
|
||||
return boost::math::ccmath::fmax(x, y);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
constexpr long double fmaxl(long double x, long double y) noexcept
|
||||
{
|
||||
return boost::math::ccmath::fmax(x, y);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespace boost::math::ccmath
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_FMAX_HPP
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
// (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_CCMATH_FMIN_HPP
|
||||
#define BOOST_MATH_CCMATH_FMIN_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/fmin.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/tools/promotion.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
constexpr T fmin_impl(const T x, const T y) noexcept
|
||||
{
|
||||
if (x < y)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
else
|
||||
{
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
constexpr Real fmin(Real x, Real y) noexcept
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
if (boost::math::ccmath::isnan(x))
|
||||
{
|
||||
return y;
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(y))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
return boost::math::ccmath::detail::fmin_impl(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::fmin;
|
||||
return fmin(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
constexpr auto fmin(T1 x, T2 y) noexcept
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
using promoted_type = boost::math::tools::promote_args_2_t<T1, T2>;
|
||||
return boost::math::ccmath::fmin(static_cast<promoted_type>(x), static_cast<promoted_type>(y));
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::fmin;
|
||||
return fmin(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
float fminf(float x, float y) noexcept
|
||||
{
|
||||
return boost::math::ccmath::fmin(x, y);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
long double fminl(long double x, long double y) noexcept
|
||||
{
|
||||
return boost::math::ccmath::fmin(x, y);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespace boost::math::ccmath
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_FMIN_HPP
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
// (C) Copyright Matt Borland 2021 - 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_CCMATH_FMOD_HPP
|
||||
#define BOOST_MATH_CCMATH_FMOD_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/fmod.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <boost/math/tools/promotion.hpp>
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/isfinite.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
constexpr T fmod_impl(T x, T y)
|
||||
{
|
||||
if (x == y)
|
||||
{
|
||||
return static_cast<T>(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (x >= y)
|
||||
{
|
||||
x -= y;
|
||||
}
|
||||
|
||||
return static_cast<T>(x);
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
constexpr Real fmod(Real x, Real y)
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
if (boost::math::ccmath::abs(x) == static_cast<Real>(0) && y != static_cast<Real>(0))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
else if (boost::math::ccmath::isinf(x) && !boost::math::ccmath::isnan(y))
|
||||
{
|
||||
return std::numeric_limits<Real>::quiet_NaN();
|
||||
}
|
||||
else if (boost::math::ccmath::abs(y) == static_cast<Real>(0) && !boost::math::ccmath::isnan(x))
|
||||
{
|
||||
return std::numeric_limits<Real>::quiet_NaN();
|
||||
}
|
||||
else if (boost::math::ccmath::isinf(y) && boost::math::ccmath::isfinite(x))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(x))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(y))
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
return boost::math::ccmath::detail::fmod_impl<Real>(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::fmod;
|
||||
return fmod(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
constexpr auto fmod(T1 x, T2 y)
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
using promoted_type = boost::math::tools::promote_args_t<T1, T2>;
|
||||
return boost::math::ccmath::fmod(promoted_type(x), promoted_type(y));
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::fmod;
|
||||
return fmod(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr float fmodf(float x, float y)
|
||||
{
|
||||
return boost::math::ccmath::fmod(x, y);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
constexpr long double fmodl(long double x, long double y)
|
||||
{
|
||||
return boost::math::ccmath::fmod(x, y);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_FMOD_HPP
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_FPCLASSIFY
|
||||
#define BOOST_MATH_CCMATH_FPCLASSIFY
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/fpclassify.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/special_functions/fpclassify.hpp>
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/isfinite.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
template <typename T, std::enable_if_t<!std::is_integral_v<T>, bool> = true>
|
||||
inline constexpr int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION(T x)
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
return (boost::math::ccmath::isnan)(x) ? FP_NAN :
|
||||
(boost::math::ccmath::isinf)(x) ? FP_INFINITE :
|
||||
boost::math::ccmath::abs(x) == T(0) ? FP_ZERO :
|
||||
boost::math::ccmath::abs(x) > 0 && boost::math::ccmath::abs(x) < (std::numeric_limits<T>::min)() ? FP_SUBNORMAL : FP_NORMAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
using boost::math::fpclassify;
|
||||
return (fpclassify)(x);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
inline constexpr int fpclassify(Z x)
|
||||
{
|
||||
return boost::math::ccmath::fpclassify(static_cast<double>(x));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_FPCLASSIFY
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
// (C) Copyright Christopher Kormanyos 1999 - 2021.
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_FREXP_HPP
|
||||
#define BOOST_MATH_CCMATH_FREXP_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/frexp.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/isfinite.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename Real>
|
||||
inline constexpr Real frexp_zero_impl(Real arg, int* exp)
|
||||
{
|
||||
*exp = 0;
|
||||
return arg;
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
inline constexpr Real frexp_impl(Real arg, int* exp)
|
||||
{
|
||||
const bool negative_arg = (arg < Real(0));
|
||||
|
||||
Real f = negative_arg ? -arg : arg;
|
||||
int e2 = 0;
|
||||
constexpr Real two_pow_32 = Real(4294967296);
|
||||
|
||||
while (f >= two_pow_32)
|
||||
{
|
||||
f = f / two_pow_32;
|
||||
e2 += 32;
|
||||
}
|
||||
|
||||
while(f >= Real(1))
|
||||
{
|
||||
f = f / Real(2);
|
||||
++e2;
|
||||
}
|
||||
|
||||
if(exp != nullptr)
|
||||
{
|
||||
*exp = e2;
|
||||
}
|
||||
|
||||
return !negative_arg ? f : -f;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
inline constexpr Real frexp(Real arg, int* exp)
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
|
||||
{
|
||||
return arg == Real(0) ? detail::frexp_zero_impl(arg, exp) :
|
||||
arg == Real(-0) ? detail::frexp_zero_impl(arg, exp) :
|
||||
boost::math::ccmath::isinf(arg) ? detail::frexp_zero_impl(arg, exp) :
|
||||
boost::math::ccmath::isnan(arg) ? detail::frexp_zero_impl(arg, exp) :
|
||||
boost::math::ccmath::detail::frexp_impl(arg, exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::frexp;
|
||||
return frexp(arg, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
inline constexpr double frexp(Z arg, int* exp)
|
||||
{
|
||||
return boost::math::ccmath::frexp(static_cast<double>(arg), exp);
|
||||
}
|
||||
|
||||
inline constexpr float frexpf(float arg, int* exp)
|
||||
{
|
||||
return boost::math::ccmath::frexp(arg, exp);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline constexpr long double frexpl(long double arg, int* exp)
|
||||
{
|
||||
return boost::math::ccmath::frexp(arg, exp);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_FREXP_HPP
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
// (C) Copyright John Maddock 2005-2021.
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_HYPOT_HPP
|
||||
#define BOOST_MATH_CCMATH_HYPOT_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/hypot.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/tools/promotion.hpp>
|
||||
#include <boost/math/ccmath/sqrt.hpp>
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/detail/swap.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
constexpr T hypot_impl(T x, T y) noexcept
|
||||
{
|
||||
x = boost::math::ccmath::abs(x);
|
||||
y = boost::math::ccmath::abs(y);
|
||||
|
||||
if (y > x)
|
||||
{
|
||||
boost::math::ccmath::detail::swap(x, y);
|
||||
}
|
||||
|
||||
if(x * std::numeric_limits<T>::epsilon() >= y)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
T rat = y / x;
|
||||
return x * boost::math::ccmath::sqrt(1 + rat * rat);
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
constexpr Real hypot(Real x, Real y) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
if (boost::math::ccmath::abs(x) == static_cast<Real>(0))
|
||||
{
|
||||
return boost::math::ccmath::abs(y);
|
||||
}
|
||||
else if (boost::math::ccmath::abs(y) == static_cast<Real>(0))
|
||||
{
|
||||
return boost::math::ccmath::abs(x);
|
||||
}
|
||||
// Return +inf even if the other argument is NaN
|
||||
else if (boost::math::ccmath::isinf(x) || boost::math::ccmath::isinf(y))
|
||||
{
|
||||
return std::numeric_limits<Real>::infinity();
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(x))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(y))
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
return boost::math::ccmath::detail::hypot_impl(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::hypot;
|
||||
return hypot(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
constexpr auto hypot(T1 x, T2 y) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
using promoted_type = boost::math::tools::promote_args_2_t<T1, T2>;
|
||||
return boost::math::ccmath::hypot(static_cast<promoted_type>(x), static_cast<promoted_type>(y));
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::hypot;
|
||||
return hypot(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr float hypotf(float x, float y) noexcept
|
||||
{
|
||||
return boost::math::ccmath::hypot(x, y);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
constexpr long double hypotl(long double x, long double y) noexcept
|
||||
{
|
||||
return boost::math::ccmath::hypot(x, y);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_HYPOT_HPP
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_ILOGB_HPP
|
||||
#define BOOST_MATH_CCMATH_ILOGB_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/ilogb.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/logb.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
// If arg is not zero, infinite, or NaN, the value returned is exactly equivalent to static_cast<int>(std::logb(arg))
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
inline constexpr int ilogb(Real arg) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
|
||||
{
|
||||
return boost::math::ccmath::abs(arg) == Real(0) ? FP_ILOGB0 :
|
||||
boost::math::ccmath::isinf(arg) ? INT_MAX :
|
||||
boost::math::ccmath::isnan(arg) ? FP_ILOGBNAN :
|
||||
static_cast<int>(boost::math::ccmath::logb(arg));
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::ilogb;
|
||||
return ilogb(arg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
inline constexpr int ilogb(Z arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::ilogb(static_cast<double>(arg));
|
||||
}
|
||||
|
||||
inline constexpr int ilogbf(float arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::ilogb(arg);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline constexpr int ilogbl(long double arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::ilogb(arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_ILOGB_HPP
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_ISFINITE
|
||||
#define BOOST_MATH_CCMATH_ISFINITE
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/isfinite.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool isfinite(T x)
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
// bool isfinite (IntegralType arg) is a set of overloads accepting the arg argument of any integral type
|
||||
// equivalent to casting the integral argument arg to double (e.g. static_cast<double>(arg))
|
||||
if constexpr (std::is_integral_v<T>)
|
||||
{
|
||||
return !boost::math::ccmath::isinf(static_cast<double>(x)) && !boost::math::ccmath::isnan(static_cast<double>(x));
|
||||
}
|
||||
else
|
||||
{
|
||||
return !boost::math::ccmath::isinf(x) && !boost::math::ccmath::isnan(x);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::isfinite;
|
||||
|
||||
if constexpr (!std::is_integral_v<T>)
|
||||
{
|
||||
return isfinite(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
return isfinite(static_cast<double>(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_ISFINITE
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// (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_CCMATH_ISGREATER_HPP
|
||||
#define BOOST_MATH_CCMATH_ISGREATER_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/isgreater.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
template <typename T1, typename T2 = T1>
|
||||
inline constexpr bool isgreater(T1 x, T2 y) noexcept
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
if (boost::math::ccmath::isnan(x) || boost::math::ccmath::isnan(y))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return x > y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::isgreater;
|
||||
return isgreater(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_ISGREATER_HPP
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// (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_CCMATH_ISGREATEREQUAL_HPP
|
||||
#define BOOST_MATH_CCMATH_ISGREATEREQUAL_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/islessequal.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
template <typename T1, typename T2 = T1>
|
||||
inline constexpr bool isgreaterequal(T1 x, T2 y) noexcept
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
if (boost::math::ccmath::isnan(x) || boost::math::ccmath::isnan(y))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return x >= y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::isgreaterequal;
|
||||
return isgreaterequal(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_ISGREATEREQUAL_HPP
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_ISINF
|
||||
#define BOOST_MATH_CCMATH_ISINF
|
||||
|
||||
#include <boost/math/special_functions/fpclassify.hpp>
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/isinf.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
template <typename T>
|
||||
constexpr bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION(T x) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
if constexpr (std::numeric_limits<T>::is_signed)
|
||||
{
|
||||
return x == std::numeric_limits<T>::infinity() || -x == std::numeric_limits<T>::infinity();
|
||||
}
|
||||
else
|
||||
{
|
||||
return x == std::numeric_limits<T>::infinity();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using boost::math::isinf;
|
||||
|
||||
if constexpr (!std::is_integral_v<T>)
|
||||
{
|
||||
return (isinf)(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (isinf)(static_cast<double>(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_ISINF
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// (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_CCMATH_ISLESS_HPP
|
||||
#define BOOST_MATH_CCMATH_ISLESS_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/isless.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
template <typename T1, typename T2 = T1>
|
||||
inline constexpr bool isless(T1 x, T2 y) noexcept
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
if (boost::math::ccmath::isnan(x) || boost::math::ccmath::isnan(y))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return x < y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::isless;
|
||||
return isless(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_ISLESS_HPP
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// (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_CCMATH_ISLESSEQUAL_HPP
|
||||
#define BOOST_MATH_CCMATH_ISLESSEQUAL_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/islessequal.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
template <typename T1, typename T2 = T1>
|
||||
inline constexpr bool islessequal(T1 x, T2 y) noexcept
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
if (boost::math::ccmath::isnan(x) || boost::math::ccmath::isnan(y))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return x <= y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::islessequal;
|
||||
return islessequal(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_ISLESSEQUAL_HPP
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_ISNAN
|
||||
#define BOOST_MATH_CCMATH_ISNAN
|
||||
|
||||
#include <boost/math/special_functions/fpclassify.hpp>
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/isnan.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION(T x)
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
return x != x;
|
||||
}
|
||||
else
|
||||
{
|
||||
using boost::math::isnan;
|
||||
|
||||
if constexpr (!std::is_integral_v<T>)
|
||||
{
|
||||
return (isnan)(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (isnan)(static_cast<double>(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_ISNAN
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_ISNORMAL_HPP
|
||||
#define BOOST_MATH_ISNORMAL_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/isnormal.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool isnormal(T x)
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
return x == T(0) ? false :
|
||||
boost::math::ccmath::isinf(x) ? false :
|
||||
boost::math::ccmath::isnan(x) ? false :
|
||||
boost::math::ccmath::abs(x) < (std::numeric_limits<T>::min)() ? false : true;
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::isnormal;
|
||||
|
||||
if constexpr (!std::is_integral_v<T>)
|
||||
{
|
||||
return isnormal(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
return isnormal(static_cast<double>(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BOOST_MATH_ISNORMAL_HPP
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// (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_CCMATH_ISUNORDERED_HPP
|
||||
#define BOOST_MATH_CCMATH_ISUNORDERED_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/isunordered.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool isunordered(const T x, const T y) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
return boost::math::ccmath::isnan(x) || boost::math::ccmath::isnan(y);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::isunordered;
|
||||
return isunordered(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_ISUNORDERED_HPP
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// (C) Copyright John Maddock 2021.
|
||||
// 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_CCMATH_LDEXP_HPP
|
||||
#define BOOST_MATH_CCMATH_LDEXP_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/ldexp.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Real>
|
||||
inline constexpr Real ldexp_impl(Real arg, int exp) noexcept
|
||||
{
|
||||
while(exp > 0)
|
||||
{
|
||||
arg *= 2;
|
||||
--exp;
|
||||
}
|
||||
while(exp < 0)
|
||||
{
|
||||
arg /= 2;
|
||||
++exp;
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
inline constexpr Real ldexp(Real arg, int exp) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
|
||||
{
|
||||
return boost::math::ccmath::abs(arg) == Real(0) ? arg :
|
||||
(boost::math::ccmath::isinf)(arg) ? arg :
|
||||
(boost::math::ccmath::isnan)(arg) ? arg :
|
||||
boost::math::ccmath::detail::ldexp_impl(arg, exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::ldexp;
|
||||
return ldexp(arg, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
inline constexpr double ldexp(Z arg, int exp) noexcept
|
||||
{
|
||||
return boost::math::ccmath::ldexp(static_cast<double>(arg), exp);
|
||||
}
|
||||
|
||||
inline constexpr float ldexpf(float arg, int exp) noexcept
|
||||
{
|
||||
return boost::math::ccmath::ldexp(arg, exp);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline constexpr long double ldexpl(long double arg, int exp) noexcept
|
||||
{
|
||||
return boost::math::ccmath::ldexp(arg, exp);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_LDEXP_HPP
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_LOGB_HPP
|
||||
#define BOOST_MATH_CCMATH_LOGB_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/logb.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/frexp.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// The value of the exponent returned by std::logb is always 1 less than the exponent returned by
|
||||
// std::frexp because of the different normalization requirements: for the exponent e returned by std::logb,
|
||||
// |arg*r^-e| is between 1 and r (typically between 1 and 2), but for the exponent e returned by std::frexp,
|
||||
// |arg*2^-e| is between 0.5 and 1.
|
||||
template <typename T>
|
||||
constexpr T logb_impl(T arg) noexcept
|
||||
{
|
||||
int exp = 0;
|
||||
boost::math::ccmath::frexp(arg, &exp);
|
||||
|
||||
return static_cast<T>(exp - 1);
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
constexpr Real logb(Real arg) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
|
||||
{
|
||||
if (boost::math::ccmath::abs(arg) == Real(0))
|
||||
{
|
||||
return -std::numeric_limits<Real>::infinity();
|
||||
}
|
||||
else if (boost::math::ccmath::isinf(arg))
|
||||
{
|
||||
return std::numeric_limits<Real>::infinity();
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(arg))
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
|
||||
return boost::math::ccmath::detail::logb_impl(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::logb;
|
||||
return logb(arg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
constexpr double logb(Z arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::logb(static_cast<double>(arg));
|
||||
}
|
||||
|
||||
constexpr float logbf(float arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::logb(arg);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
constexpr long double logbl(long double arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::logb(arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_LOGB_HPP
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_MODF_HPP
|
||||
#define BOOST_MATH_CCMATH_MODF_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/modf.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/trunc.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Real>
|
||||
inline constexpr Real modf_error_impl(Real x, Real* iptr)
|
||||
{
|
||||
*iptr = x;
|
||||
return boost::math::ccmath::abs(x) == Real(0) ? x :
|
||||
x > Real(0) ? Real(0) : -Real(0);
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
inline constexpr Real modf_nan_impl(Real x, Real* iptr)
|
||||
{
|
||||
*iptr = x;
|
||||
return x;
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
inline constexpr Real modf_impl(Real x, Real* iptr)
|
||||
{
|
||||
*iptr = boost::math::ccmath::trunc(x);
|
||||
return (x - *iptr);
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real>
|
||||
inline constexpr Real modf(Real x, Real* iptr)
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
return boost::math::ccmath::abs(x) == Real(0) ? detail::modf_error_impl(x, iptr) :
|
||||
boost::math::ccmath::isinf(x) ? detail::modf_error_impl(x, iptr) :
|
||||
boost::math::ccmath::isnan(x) ? detail::modf_nan_impl(x, iptr) :
|
||||
boost::math::ccmath::detail::modf_impl(x, iptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::modf;
|
||||
return modf(x, iptr);
|
||||
}
|
||||
}
|
||||
|
||||
inline constexpr float modff(float x, float* iptr)
|
||||
{
|
||||
return boost::math::ccmath::modf(x, iptr);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline constexpr long double modfl(long double x, long double* iptr)
|
||||
{
|
||||
return boost::math::ccmath::modf(x, iptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_MODF_HPP
|
||||
+458
@@ -0,0 +1,458 @@
|
||||
// (C) Copyright John Maddock 2008 - 2022.
|
||||
// (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_CCMATH_NEXT_HPP
|
||||
#define BOOST_MATH_CCMATH_NEXT_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/next.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cfloat>
|
||||
#include <cstdint>
|
||||
#include <boost/math/policies/policy.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/math/tools/assert.hpp>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/tools/precision.hpp>
|
||||
#include <boost/math/tools/traits.hpp>
|
||||
#include <boost/math/tools/promotion.hpp>
|
||||
#include <boost/math/ccmath/ilogb.hpp>
|
||||
#include <boost/math/ccmath/ldexp.hpp>
|
||||
#include <boost/math/ccmath/scalbln.hpp>
|
||||
#include <boost/math/ccmath/round.hpp>
|
||||
#include <boost/math/ccmath/fabs.hpp>
|
||||
#include <boost/math/ccmath/fpclassify.hpp>
|
||||
#include <boost/math/ccmath/isfinite.hpp>
|
||||
#include <boost/math/ccmath/fmod.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Forward Declarations
|
||||
template <typename T, typename result_type = tools::promote_args_t<T>>
|
||||
constexpr result_type float_prior(const T& val);
|
||||
|
||||
template <typename T, typename result_type = tools::promote_args_t<T>>
|
||||
constexpr result_type float_next(const T& val);
|
||||
|
||||
template <typename T>
|
||||
struct has_hidden_guard_digits;
|
||||
template <>
|
||||
struct has_hidden_guard_digits<float> : public std::false_type {};
|
||||
template <>
|
||||
struct has_hidden_guard_digits<double> : public std::false_type {};
|
||||
template <>
|
||||
struct has_hidden_guard_digits<long double> : public std::false_type {};
|
||||
#ifdef BOOST_HAS_FLOAT128
|
||||
template <>
|
||||
struct has_hidden_guard_digits<__float128> : public std::false_type {};
|
||||
#endif
|
||||
|
||||
template <typename T, bool b>
|
||||
struct has_hidden_guard_digits_10 : public std::false_type {};
|
||||
template <typename T>
|
||||
struct has_hidden_guard_digits_10<T, true> : public std::integral_constant<bool, (std::numeric_limits<T>::digits10 != std::numeric_limits<T>::max_digits10)> {};
|
||||
|
||||
template <typename T>
|
||||
struct has_hidden_guard_digits
|
||||
: public has_hidden_guard_digits_10<T,
|
||||
std::numeric_limits<T>::is_specialized
|
||||
&& (std::numeric_limits<T>::radix == 10) >
|
||||
{};
|
||||
|
||||
template <typename T>
|
||||
constexpr T normalize_value(const T& val, const std::false_type&) { return val; }
|
||||
template <typename T>
|
||||
constexpr T normalize_value(const T& val, const std::true_type&)
|
||||
{
|
||||
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.");
|
||||
|
||||
std::intmax_t shift = static_cast<std::intmax_t>(std::numeric_limits<T>::digits) - static_cast<std::intmax_t>(boost::math::ccmath::ilogb(val)) - 1;
|
||||
T result = boost::math::ccmath::scalbn(val, shift);
|
||||
result = boost::math::ccmath::round(result);
|
||||
return boost::math::ccmath::scalbn(result, -shift);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr T get_smallest_value(const std::true_type&)
|
||||
{
|
||||
//
|
||||
// numeric_limits lies about denorms being present - particularly
|
||||
// when this can be turned on or off at runtime, as is the case
|
||||
// when using the SSE2 registers in DAZ or FTZ mode.
|
||||
//
|
||||
constexpr T m = std::numeric_limits<T>::denorm_min();
|
||||
return ((tools::min_value<T>() / 2) == 0) ? tools::min_value<T>() : m;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr T get_smallest_value(const std::false_type&)
|
||||
{
|
||||
return tools::min_value<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr T get_smallest_value()
|
||||
{
|
||||
return get_smallest_value<T>(std::integral_constant<bool, std::numeric_limits<T>::is_specialized>());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr T calc_min_shifted(const std::true_type&)
|
||||
{
|
||||
return boost::math::ccmath::ldexp(tools::min_value<T>(), tools::digits<T>() + 1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr T calc_min_shifted(const std::false_type&)
|
||||
{
|
||||
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.");
|
||||
|
||||
return boost::math::ccmath::scalbn(tools::min_value<T>(), std::numeric_limits<T>::digits + 1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr T get_min_shift_value()
|
||||
{
|
||||
const T val = calc_min_shifted<T>(std::integral_constant<bool, !std::numeric_limits<T>::is_specialized || std::numeric_limits<T>::radix == 2>());
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T, bool b = boost::math::tools::detail::has_backend_type_v<T>>
|
||||
struct exponent_type
|
||||
{
|
||||
using type = int;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct exponent_type<T, true>
|
||||
{
|
||||
using type = typename T::backend_type::exponent_type;
|
||||
};
|
||||
|
||||
template <typename T, bool b = boost::math::tools::detail::has_backend_type_v<T>>
|
||||
using exponent_type_t = typename exponent_type<T>::type;
|
||||
|
||||
template <typename T>
|
||||
constexpr T float_next_imp(const T& val, const std::true_type&)
|
||||
{
|
||||
using exponent_type = exponent_type_t<T>;
|
||||
|
||||
exponent_type expon {};
|
||||
|
||||
int fpclass = boost::math::ccmath::fpclassify(val);
|
||||
|
||||
if (fpclass == FP_NAN)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
else if (fpclass == FP_INFINITE)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
else if (val <= -tools::max_value<T>())
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
return detail::get_smallest_value<T>();
|
||||
}
|
||||
|
||||
if ((fpclass != FP_SUBNORMAL) && (fpclass != FP_ZERO)
|
||||
&& (boost::math::ccmath::fabs(val) < detail::get_min_shift_value<T>())
|
||||
&& (val != -tools::min_value<T>()))
|
||||
{
|
||||
//
|
||||
// Special case: if the value of the least significant bit is a denorm, and the result
|
||||
// would not be a denorm, then shift the input, increment, and shift back.
|
||||
// This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
|
||||
//
|
||||
return boost::math::ccmath::ldexp(boost::math::ccmath::detail::float_next(static_cast<T>(boost::math::ccmath::ldexp(val, 2 * tools::digits<T>()))), -2 * tools::digits<T>());
|
||||
}
|
||||
|
||||
if (-0.5f == boost::math::ccmath::frexp(val, &expon))
|
||||
{
|
||||
--expon; // reduce exponent when val is a power of two, and negative.
|
||||
}
|
||||
T diff = boost::math::ccmath::ldexp(static_cast<T>(1), expon - tools::digits<T>());
|
||||
if(diff == 0)
|
||||
{
|
||||
diff = detail::get_smallest_value<T>();
|
||||
}
|
||||
return val + diff;
|
||||
}
|
||||
|
||||
//
|
||||
// Special version for some base other than 2:
|
||||
//
|
||||
template <typename T>
|
||||
constexpr T float_next_imp(const T& val, const std::false_type&)
|
||||
{
|
||||
using exponent_type = exponent_type_t<T>;
|
||||
|
||||
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.");
|
||||
|
||||
exponent_type expon {};
|
||||
|
||||
int fpclass = boost::math::ccmath::fpclassify(val);
|
||||
|
||||
if (fpclass == FP_NAN)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
else if (fpclass == FP_INFINITE)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
else if (val <= -tools::max_value<T>())
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
return detail::get_smallest_value<T>();
|
||||
}
|
||||
|
||||
if ((fpclass != FP_SUBNORMAL) && (fpclass != FP_ZERO)
|
||||
&& (boost::math::ccmath::fabs(val) < detail::get_min_shift_value<T>())
|
||||
&& (val != -tools::min_value<T>()))
|
||||
{
|
||||
//
|
||||
// Special case: if the value of the least significant bit is a denorm, and the result
|
||||
// would not be a denorm, then shift the input, increment, and shift back.
|
||||
// This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
|
||||
//
|
||||
return boost::math::ccmath::scalbn(boost::math::ccmath::detail::float_next(static_cast<T>(boost::math::ccmath::scalbn(val, 2 * std::numeric_limits<T>::digits))), -2 * std::numeric_limits<T>::digits);
|
||||
}
|
||||
|
||||
expon = 1 + boost::math::ccmath::ilogb(val);
|
||||
if(-1 == boost::math::ccmath::scalbn(val, -expon) * std::numeric_limits<T>::radix)
|
||||
{
|
||||
--expon; // reduce exponent when val is a power of base, and negative.
|
||||
}
|
||||
|
||||
T diff = boost::math::ccmath::scalbn(static_cast<T>(1), expon - std::numeric_limits<T>::digits);
|
||||
if(diff == 0)
|
||||
{
|
||||
diff = detail::get_smallest_value<T>();
|
||||
}
|
||||
|
||||
return val + diff;
|
||||
}
|
||||
|
||||
template <typename T, typename result_type>
|
||||
constexpr result_type float_next(const T& val)
|
||||
{
|
||||
return detail::float_next_imp(detail::normalize_value(static_cast<result_type>(val), typename detail::has_hidden_guard_digits<result_type>::type()), std::integral_constant<bool, !std::numeric_limits<result_type>::is_specialized || (std::numeric_limits<result_type>::radix == 2)>());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr T float_prior_imp(const T& val, const std::true_type&)
|
||||
{
|
||||
using exponent_type = exponent_type_t<T>;
|
||||
|
||||
exponent_type expon {};
|
||||
|
||||
int fpclass = boost::math::ccmath::fpclassify(val);
|
||||
|
||||
if (fpclass == FP_NAN)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
else if (fpclass == FP_INFINITE)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
else if (val <= -tools::max_value<T>())
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
return -detail::get_smallest_value<T>();
|
||||
}
|
||||
|
||||
if ((fpclass != FP_SUBNORMAL) && (fpclass != FP_ZERO)
|
||||
&& (boost::math::ccmath::fabs(val) < detail::get_min_shift_value<T>())
|
||||
&& (val != tools::min_value<T>()))
|
||||
{
|
||||
//
|
||||
// Special case: if the value of the least significant bit is a denorm, and the result
|
||||
// would not be a denorm, then shift the input, increment, and shift back.
|
||||
// This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
|
||||
//
|
||||
return boost::math::ccmath::ldexp(boost::math::ccmath::detail::float_prior(static_cast<T>(boost::math::ccmath::ldexp(val, 2 * tools::digits<T>()))), -2 * tools::digits<T>());
|
||||
}
|
||||
|
||||
if(T remain = boost::math::ccmath::frexp(val, &expon); remain == 0.5f)
|
||||
{
|
||||
--expon; // when val is a power of two we must reduce the exponent
|
||||
}
|
||||
|
||||
T diff = boost::math::ccmath::ldexp(static_cast<T>(1), expon - tools::digits<T>());
|
||||
if(diff == 0)
|
||||
{
|
||||
diff = detail::get_smallest_value<T>();
|
||||
}
|
||||
|
||||
return val - diff;
|
||||
}
|
||||
|
||||
//
|
||||
// Special version for bases other than 2:
|
||||
//
|
||||
template <typename T>
|
||||
constexpr T float_prior_imp(const T& val, const std::false_type&)
|
||||
{
|
||||
using exponent_type = exponent_type_t<T>;
|
||||
|
||||
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.");
|
||||
|
||||
exponent_type expon {};
|
||||
|
||||
int fpclass = boost::math::ccmath::fpclassify(val);
|
||||
|
||||
if (fpclass == FP_NAN)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
else if (fpclass == FP_INFINITE)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
else if (val <= -tools::max_value<T>())
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
return -detail::get_smallest_value<T>();
|
||||
}
|
||||
|
||||
if ((fpclass != FP_SUBNORMAL) && (fpclass != FP_ZERO)
|
||||
&& (boost::math::ccmath::fabs(val) < detail::get_min_shift_value<T>())
|
||||
&& (val != tools::min_value<T>()))
|
||||
{
|
||||
//
|
||||
// Special case: if the value of the least significant bit is a denorm, and the result
|
||||
// would not be a denorm, then shift the input, increment, and shift back.
|
||||
// This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
|
||||
//
|
||||
return boost::math::ccmath::scalbn(boost::math::ccmath::detail::float_prior(static_cast<T>(boost::math::ccmath::scalbn(val, 2 * std::numeric_limits<T>::digits))), -2 * std::numeric_limits<T>::digits);
|
||||
}
|
||||
|
||||
expon = 1 + boost::math::ccmath::ilogb(val);
|
||||
|
||||
if (T remain = boost::math::ccmath::scalbn(val, -expon); remain * std::numeric_limits<T>::radix == 1)
|
||||
{
|
||||
--expon; // when val is a power of two we must reduce the exponent
|
||||
}
|
||||
|
||||
T diff = boost::math::ccmath::scalbn(static_cast<T>(1), expon - std::numeric_limits<T>::digits);
|
||||
if (diff == 0)
|
||||
{
|
||||
diff = detail::get_smallest_value<T>();
|
||||
}
|
||||
return val - diff;
|
||||
} // float_prior_imp
|
||||
|
||||
template <typename T, typename result_type>
|
||||
constexpr result_type float_prior(const T& val)
|
||||
{
|
||||
return detail::float_prior_imp(detail::normalize_value(static_cast<result_type>(val), typename detail::has_hidden_guard_digits<result_type>::type()), std::integral_constant<bool, !std::numeric_limits<result_type>::is_specialized || (std::numeric_limits<result_type>::radix == 2)>());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename U, typename result_type = tools::promote_args_t<T, U>>
|
||||
constexpr result_type nextafter(const T& val, const U& direction)
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(val))
|
||||
{
|
||||
if (boost::math::ccmath::isnan(val))
|
||||
{
|
||||
return val;
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(direction))
|
||||
{
|
||||
return direction;
|
||||
}
|
||||
else if (val < direction)
|
||||
{
|
||||
return boost::math::ccmath::detail::float_next(val);
|
||||
}
|
||||
else if (val == direction)
|
||||
{
|
||||
// IEC 60559 recommends that from is returned whenever from == to. These functions return to instead,
|
||||
// which makes the behavior around zero consistent: std::nextafter(-0.0, +0.0) returns +0.0 and
|
||||
// std::nextafter(+0.0, -0.0) returns -0.0.
|
||||
return direction;
|
||||
}
|
||||
|
||||
return boost::math::ccmath::detail::float_prior(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::nextafter;
|
||||
return nextafter(static_cast<result_type>(val), static_cast<result_type>(direction));
|
||||
}
|
||||
}
|
||||
|
||||
constexpr float nextafterf(float val, float direction)
|
||||
{
|
||||
return boost::math::ccmath::nextafter(val, direction);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
|
||||
constexpr long double nextafterl(long double val, long double direction)
|
||||
{
|
||||
return boost::math::ccmath::nextafter(val, direction);
|
||||
}
|
||||
|
||||
template <typename T, typename result_type = tools::promote_args_t<T, long double>, typename return_type = std::conditional_t<std::is_integral_v<T>, double, T>>
|
||||
constexpr return_type nexttoward(T val, long double direction)
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(val))
|
||||
{
|
||||
return static_cast<return_type>(boost::math::ccmath::nextafter(static_cast<result_type>(val), direction));
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::nexttoward;
|
||||
return nexttoward(val, direction);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr float nexttowardf(float val, long double direction)
|
||||
{
|
||||
return boost::math::ccmath::nexttoward(val, direction);
|
||||
}
|
||||
|
||||
constexpr long double nexttowardl(long double val, long double direction)
|
||||
{
|
||||
return boost::math::ccmath::nexttoward(val, direction);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_SPECIAL_NEXT_HPP
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
// (C) Copyright Matt Borland 2021 - 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_CCMATH_REMAINDER_HPP
|
||||
#define BOOST_MATH_CCMATH_REMAINDER_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/remainder.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <boost/math/tools/promotion.hpp>
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/isfinite.hpp>
|
||||
#include <boost/math/ccmath/modf.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
constexpr T remainder_impl(const T x, const T y)
|
||||
{
|
||||
T n = 0;
|
||||
|
||||
if (T fractional_part = boost::math::ccmath::modf((x / y), &n); fractional_part > static_cast<T>(1.0/2))
|
||||
{
|
||||
++n;
|
||||
}
|
||||
else if (fractional_part < static_cast<T>(-1.0/2))
|
||||
{
|
||||
--n;
|
||||
}
|
||||
|
||||
return x - n*y;
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
constexpr Real remainder(Real x, Real y)
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
if (boost::math::ccmath::isinf(x) && !boost::math::ccmath::isnan(y))
|
||||
{
|
||||
return std::numeric_limits<Real>::quiet_NaN();
|
||||
}
|
||||
else if (boost::math::ccmath::abs(y) == static_cast<Real>(0) && !boost::math::ccmath::isnan(x))
|
||||
{
|
||||
return std::numeric_limits<Real>::quiet_NaN();
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(x))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
else if (boost::math::ccmath::isnan(y))
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
return boost::math::ccmath::detail::remainder_impl(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::remainder;
|
||||
return remainder(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
constexpr auto remainder(T1 x, T2 y)
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
using promoted_type = boost::math::tools::promote_args_t<T1, T2>;
|
||||
return boost::math::ccmath::remainder(promoted_type(x), promoted_type(y));
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::remainder;
|
||||
return remainder(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr float remainderf(float x, float y)
|
||||
{
|
||||
return boost::math::ccmath::remainder(x, y);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
constexpr long double remainderl(long double x, long double y)
|
||||
{
|
||||
return boost::math::ccmath::remainder(x, y);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_REMAINDER_HPP
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_ROUND_HPP
|
||||
#define BOOST_MATH_CCMATH_ROUND_HPP
|
||||
|
||||
#include <stdexcept>
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/round.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/modf.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Computes the nearest integer value to arg (in floating-point format),
|
||||
// rounding halfway cases away from zero, regardless of the current rounding mode.
|
||||
template <typename T>
|
||||
inline constexpr T round_impl(T arg) noexcept
|
||||
{
|
||||
T iptr = 0;
|
||||
const T x = boost::math::ccmath::modf(arg, &iptr);
|
||||
constexpr T half = T(1)/2;
|
||||
|
||||
if(x >= half && iptr > 0)
|
||||
{
|
||||
return iptr + 1;
|
||||
}
|
||||
else if(boost::math::ccmath::abs(x) >= half && iptr < 0)
|
||||
{
|
||||
return iptr - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return iptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ReturnType, typename T>
|
||||
inline constexpr ReturnType int_round_impl(T arg)
|
||||
{
|
||||
const T rounded_arg = round_impl(arg);
|
||||
|
||||
if(rounded_arg > static_cast<T>((std::numeric_limits<ReturnType>::max)()))
|
||||
{
|
||||
if constexpr (std::is_same_v<ReturnType, long long>)
|
||||
{
|
||||
throw std::domain_error("Rounded value cannot be represented by a long long type without overflow");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::domain_error("Rounded value cannot be represented by a long type without overflow");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<ReturnType>(rounded_arg);
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
inline constexpr Real round(Real arg) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
|
||||
{
|
||||
return boost::math::ccmath::abs(arg) == Real(0) ? arg :
|
||||
boost::math::ccmath::isinf(arg) ? arg :
|
||||
boost::math::ccmath::isnan(arg) ? arg :
|
||||
boost::math::ccmath::detail::round_impl(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::round;
|
||||
return round(arg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
inline constexpr double round(Z arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::round(static_cast<double>(arg));
|
||||
}
|
||||
|
||||
inline constexpr float roundf(float arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::round(arg);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline constexpr long double roundl(long double arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::round(arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
inline constexpr long lround(Real arg)
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
|
||||
{
|
||||
return boost::math::ccmath::abs(arg) == Real(0) ? 0l :
|
||||
boost::math::ccmath::isinf(arg) ? 0l :
|
||||
boost::math::ccmath::isnan(arg) ? 0l :
|
||||
boost::math::ccmath::detail::int_round_impl<long>(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::lround;
|
||||
return lround(arg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
inline constexpr long lround(Z arg)
|
||||
{
|
||||
return boost::math::ccmath::lround(static_cast<double>(arg));
|
||||
}
|
||||
|
||||
inline constexpr long lroundf(float arg)
|
||||
{
|
||||
return boost::math::ccmath::lround(arg);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline constexpr long lroundl(long double arg)
|
||||
{
|
||||
return boost::math::ccmath::lround(arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
inline constexpr long long llround(Real arg)
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
|
||||
{
|
||||
return boost::math::ccmath::abs(arg) == Real(0) ? 0ll :
|
||||
boost::math::ccmath::isinf(arg) ? 0ll :
|
||||
boost::math::ccmath::isnan(arg) ? 0ll :
|
||||
boost::math::ccmath::detail::int_round_impl<long long>(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::llround;
|
||||
return llround(arg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
inline constexpr long llround(Z arg)
|
||||
{
|
||||
return boost::math::ccmath::llround(static_cast<double>(arg));
|
||||
}
|
||||
|
||||
inline constexpr long long llroundf(float arg)
|
||||
{
|
||||
return boost::math::ccmath::llround(arg);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline constexpr long long llroundl(long double arg)
|
||||
{
|
||||
return boost::math::ccmath::llround(arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_ROUND_HPP
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_SCALBLN_HPP
|
||||
#define BOOST_MATH_CCMATH_SCALBLN_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/scalbln.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <cfloat>
|
||||
#include <boost/math/ccmath/scalbn.hpp>
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
inline constexpr Real scalbln(Real arg, long exp) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
|
||||
{
|
||||
return boost::math::ccmath::abs(arg) == Real(0) ? arg :
|
||||
boost::math::ccmath::isinf(arg) ? arg :
|
||||
boost::math::ccmath::isnan(arg) ? arg :
|
||||
boost::math::ccmath::detail::scalbn_impl(arg, exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::scalbln;
|
||||
return scalbln(arg, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
inline constexpr double scalbln(Z arg, long exp) noexcept
|
||||
{
|
||||
return boost::math::ccmath::scalbln(static_cast<double>(arg), exp);
|
||||
}
|
||||
|
||||
inline constexpr float scalblnf(float arg, long exp) noexcept
|
||||
{
|
||||
return boost::math::ccmath::scalbln(arg, exp);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline constexpr long double scalblnl(long double arg, long exp) noexcept
|
||||
{
|
||||
return boost::math::ccmath::scalbln(arg, exp);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_SCALBLN_HPP
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// (C) Copyright John Maddock 2021.
|
||||
// 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_CCMATH_SCALBN_HPP
|
||||
#define BOOST_MATH_CCMATH_SCALBN_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/scalbn.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <cfloat>
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Real, typename Z>
|
||||
inline constexpr Real scalbn_impl(Real arg, Z exp) noexcept
|
||||
{
|
||||
while(exp > 0)
|
||||
{
|
||||
arg *= FLT_RADIX;
|
||||
--exp;
|
||||
}
|
||||
while(exp < 0)
|
||||
{
|
||||
arg /= FLT_RADIX;
|
||||
++exp;
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
inline constexpr Real scalbn(Real arg, int exp) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
|
||||
{
|
||||
return boost::math::ccmath::abs(arg) == Real(0) ? arg :
|
||||
boost::math::ccmath::isinf(arg) ? arg :
|
||||
boost::math::ccmath::isnan(arg) ? arg :
|
||||
boost::math::ccmath::detail::scalbn_impl(arg, exp);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::scalbn;
|
||||
return scalbn(arg, exp);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
inline constexpr double scalbn(Z arg, int exp) noexcept
|
||||
{
|
||||
return boost::math::ccmath::scalbn(static_cast<double>(arg), exp);
|
||||
}
|
||||
|
||||
inline constexpr float scalbnf(float arg, int exp) noexcept
|
||||
{
|
||||
return boost::math::ccmath::scalbn(arg, exp);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline constexpr long double scalbnl(long double arg, int exp) noexcept
|
||||
{
|
||||
return boost::math::ccmath::scalbn(arg, exp);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_SCALBN_HPP
|
||||
+219
@@ -0,0 +1,219 @@
|
||||
// (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_CCMATH_SIGNBIT_HPP
|
||||
#define BOOST_MATH_CCMATH_SIGNBIT_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/signbit.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <boost/math/tools/assert.hpp>
|
||||
#include <boost/math/special_functions/detail/fp_traits.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
|
||||
#ifdef __has_include
|
||||
# if __has_include(<bit>)
|
||||
# include <bit>
|
||||
# if __cpp_lib_bit_cast >= 201806L
|
||||
# define BOOST_MATH_BIT_CAST(T, x) std::bit_cast<T>(x)
|
||||
# endif
|
||||
# elif defined(__has_builtin)
|
||||
# if __has_builtin(__builtin_bit_cast)
|
||||
# define BOOST_MATH_BIT_CAST(T, x) __builtin_bit_cast(T, x)
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
The following error is given using Apple Clang version 13.1.6, and Clang 13, and 14 on Ubuntu 22.04.01
|
||||
TODO: Remove the following undef when Apple Clang supports
|
||||
|
||||
ccmath_signbit_test.cpp:32:19: error: static_assert expression is not an integral constant expression
|
||||
static_assert(boost::math::ccmath::signbit(T(-1)) == true);
|
||||
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
../../../boost/math/ccmath/signbit.hpp:62:24: note: constexpr bit_cast involving bit-field is not yet supported
|
||||
const auto u = BOOST_MATH_BIT_CAST(float_bits, arg);
|
||||
^
|
||||
../../../boost/math/ccmath/signbit.hpp:20:37: note: expanded from macro 'BOOST_MATH_BIT_CAST'
|
||||
# define BOOST_MATH_BIT_CAST(T, x) __builtin_bit_cast(T, x)
|
||||
^
|
||||
*/
|
||||
|
||||
#if defined(__clang__) && defined(BOOST_MATH_BIT_CAST)
|
||||
# undef BOOST_MATH_BIT_CAST
|
||||
#endif
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
#ifdef BOOST_MATH_BIT_CAST
|
||||
|
||||
struct IEEEf2bits
|
||||
{
|
||||
#if BOOST_MATH_ENDIAN_LITTLE_BYTE
|
||||
std::uint32_t mantissa : 23;
|
||||
std::uint32_t exponent : 8;
|
||||
std::uint32_t sign : 1;
|
||||
#else // Big endian
|
||||
std::uint32_t sign : 1;
|
||||
std::uint32_t exponent : 8;
|
||||
std::uint32_t mantissa : 23;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct IEEEd2bits
|
||||
{
|
||||
#if BOOST_MATH_ENDIAN_LITTLE_BYTE
|
||||
std::uint32_t mantissa_l : 32;
|
||||
std::uint32_t mantissa_h : 20;
|
||||
std::uint32_t exponent : 11;
|
||||
std::uint32_t sign : 1;
|
||||
#else // Big endian
|
||||
std::uint32_t sign : 1;
|
||||
std::uint32_t exponent : 11;
|
||||
std::uint32_t mantissa_h : 20;
|
||||
std::uint32_t mantissa_l : 32;
|
||||
#endif
|
||||
};
|
||||
|
||||
// 80 bit long double
|
||||
#if LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
|
||||
|
||||
struct IEEEl2bits
|
||||
{
|
||||
#if BOOST_MATH_ENDIAN_LITTLE_BYTE
|
||||
std::uint32_t mantissa_l : 32;
|
||||
std::uint32_t mantissa_h : 32;
|
||||
std::uint32_t exponent : 15;
|
||||
std::uint32_t sign : 1;
|
||||
std::uint32_t pad : 32;
|
||||
#else // Big endian
|
||||
std::uint32_t pad : 32;
|
||||
std::uint32_t sign : 1;
|
||||
std::uint32_t exponent : 15;
|
||||
std::uint32_t mantissa_h : 32;
|
||||
std::uint32_t mantissa_l : 32;
|
||||
#endif
|
||||
};
|
||||
|
||||
// 128 bit long double
|
||||
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
|
||||
|
||||
struct IEEEl2bits
|
||||
{
|
||||
#if BOOST_MATH_ENDIAN_LITTLE_BYTE
|
||||
std::uint64_t mantissa_l : 64;
|
||||
std::uint64_t mantissa_h : 48;
|
||||
std::uint32_t exponent : 15;
|
||||
std::uint32_t sign : 1;
|
||||
#else // Big endian
|
||||
std::uint32_t sign : 1;
|
||||
std::uint32_t exponent : 15;
|
||||
std::uint64_t mantissa_h : 48;
|
||||
std::uint64_t mantissa_l : 64;
|
||||
#endif
|
||||
};
|
||||
|
||||
// 64 bit long double (double == long double on ARM)
|
||||
#elif LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
|
||||
|
||||
struct IEEEl2bits
|
||||
{
|
||||
#if BOOST_MATH_ENDIAN_LITTLE_BYTE
|
||||
std::uint32_t mantissa_l : 32;
|
||||
std::uint32_t mantissa_h : 20;
|
||||
std::uint32_t exponent : 11;
|
||||
std::uint32_t sign : 1;
|
||||
#else // Big endian
|
||||
std::uint32_t sign : 1;
|
||||
std::uint32_t exponent : 11;
|
||||
std::uint32_t mantissa_h : 20;
|
||||
std::uint32_t mantissa_l : 32;
|
||||
#endif
|
||||
};
|
||||
|
||||
#else // Unsupported long double representation
|
||||
# define BOOST_MATH_UNSUPPORTED_LONG_DOUBLE
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
constexpr bool signbit_impl(T arg)
|
||||
{
|
||||
if constexpr (std::is_same_v<T, float>)
|
||||
{
|
||||
const auto u = BOOST_MATH_BIT_CAST(IEEEf2bits, arg);
|
||||
return u.sign;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, double>)
|
||||
{
|
||||
const auto u = BOOST_MATH_BIT_CAST(IEEEd2bits, arg);
|
||||
return u.sign;
|
||||
}
|
||||
#ifndef BOOST_MATH_UNSUPPORTED_LONG_DOUBLE
|
||||
else if constexpr (std::is_same_v<T, long double>)
|
||||
{
|
||||
const auto u = BOOST_MATH_BIT_CAST(IEEEl2bits, arg);
|
||||
return u.sign;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
BOOST_MATH_ASSERT_MSG(!boost::math::ccmath::isnan(arg), "NAN is not supported with this type or platform");
|
||||
BOOST_MATH_ASSERT_MSG(boost::math::ccmath::abs(arg) != 0, "Signed 0 is not support with this type or platform");
|
||||
|
||||
return arg < static_cast<T>(0);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Typical implementations of signbit involve type punning via union and manipulating
|
||||
// overflow (see libc++ or musl). Neither of these are allowed in constexpr contexts
|
||||
// (technically type punning via union in general is UB in c++ but well defined in C)
|
||||
// therefore we static assert these cases.
|
||||
|
||||
template <typename T>
|
||||
constexpr bool signbit_impl(T arg)
|
||||
{
|
||||
BOOST_MATH_ASSERT_MSG(!boost::math::ccmath::isnan(arg), "NAN is not supported without __builtin_bit_cast or std::bit_cast");
|
||||
BOOST_MATH_ASSERT_MSG(boost::math::ccmath::abs(arg) != 0, "Signed 0 is not support without __builtin_bit_cast or std::bit_cast");
|
||||
|
||||
return arg < static_cast<T>(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// Return value: true if arg is negative, false if arg is 0, NAN, or positive
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
constexpr bool signbit(Real arg)
|
||||
{
|
||||
if (BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
|
||||
{
|
||||
return boost::math::ccmath::detail::signbit_impl(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::signbit;
|
||||
return signbit(arg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
constexpr bool signbit(Z arg)
|
||||
{
|
||||
return boost::math::ccmath::signbit(static_cast<double>(arg));
|
||||
}
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_SIGNBIT_HPP
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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)
|
||||
//
|
||||
// Constexpr implementation of sqrt function
|
||||
|
||||
#ifndef BOOST_MATH_CCMATH_SQRT
|
||||
#define BOOST_MATH_CCMATH_SQRT
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/sqrt.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/tools/is_constant_evaluated.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Real>
|
||||
constexpr Real sqrt_impl_2(Real x, Real s, Real s2)
|
||||
{
|
||||
return !(s < s2) ? s2 : sqrt_impl_2(x, (x / s + s) / 2, s);
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
constexpr Real sqrt_impl_1(Real x, Real s)
|
||||
{
|
||||
return sqrt_impl_2(x, (x / s + s) / 2, s);
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
constexpr Real sqrt_impl(Real x)
|
||||
{
|
||||
return sqrt_impl_1(x, x > 1 ? x : Real(1));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
constexpr Real sqrt(Real x)
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
|
||||
{
|
||||
if (boost::math::ccmath::isnan(x) ||
|
||||
(boost::math::ccmath::isinf(x) && x > 0) ||
|
||||
boost::math::ccmath::abs(x) == Real(0))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
// Domain error is implementation defined so return NAN
|
||||
else if (boost::math::ccmath::isinf(x) && x < 0)
|
||||
{
|
||||
return std::numeric_limits<Real>::quiet_NaN();
|
||||
}
|
||||
|
||||
return detail::sqrt_impl<Real>(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::sqrt;
|
||||
return sqrt(x);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
constexpr double sqrt(Z x)
|
||||
{
|
||||
return detail::sqrt_impl<double>(static_cast<double>(x));
|
||||
}
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_SQRT
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
// (C) Copyright Matt Borland 2021.
|
||||
// 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_CCMATH_TRUNC_HPP
|
||||
#define BOOST_MATH_CCMATH_TRUNC_HPP
|
||||
|
||||
#include <boost/math/ccmath/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_MATH_NO_CCMATH
|
||||
#error "The header <boost/math/trunc.hpp> can only be used in C++17 and later."
|
||||
#endif
|
||||
|
||||
#include <boost/math/ccmath/abs.hpp>
|
||||
#include <boost/math/ccmath/isinf.hpp>
|
||||
#include <boost/math/ccmath/isnan.hpp>
|
||||
#include <boost/math/ccmath/floor.hpp>
|
||||
#include <boost/math/ccmath/ceil.hpp>
|
||||
|
||||
namespace boost::math::ccmath {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
inline constexpr T trunc_impl(T arg) noexcept
|
||||
{
|
||||
return (arg > 0) ? boost::math::ccmath::floor(arg) : boost::math::ccmath::ceil(arg);
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
|
||||
inline constexpr Real trunc(Real arg) noexcept
|
||||
{
|
||||
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
|
||||
{
|
||||
return boost::math::ccmath::abs(arg) == Real(0) ? arg :
|
||||
boost::math::ccmath::isinf(arg) ? arg :
|
||||
boost::math::ccmath::isnan(arg) ? arg :
|
||||
boost::math::ccmath::detail::trunc_impl(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::trunc;
|
||||
return trunc(arg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
|
||||
inline constexpr double trunc(Z arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::trunc(static_cast<double>(arg));
|
||||
}
|
||||
|
||||
inline constexpr float truncf(float arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::trunc(arg);
|
||||
}
|
||||
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline constexpr long double truncl(long double arg) noexcept
|
||||
{
|
||||
return boost::math::ccmath::trunc(arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // Namespaces
|
||||
|
||||
#endif // BOOST_MATH_CCMATH_TRUNC_HPP
|
||||
Reference in New Issue
Block a user