Added thirdparty: boost library

This commit is contained in:
Viacheslav Demydiuk
2024-01-06 19:55:56 +02:00
parent bf49f439e1
commit bccd1e7051
15683 changed files with 3239840 additions and 0 deletions
+89
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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