mirror of
https://github.com/boostorg/multiprecision.git
synced 2026-07-21 13:23:49 +00:00
Add more constexpr-ness
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
namespace boost { namespace multiprecision { namespace backends { namespace cpp_df_qf_detail { namespace ccmath {
|
||||
|
||||
template <class Real>
|
||||
constexpr auto fabs(Real x) -> Real
|
||||
constexpr auto fabs(Real x) noexcept -> Real
|
||||
{
|
||||
return (cpp_df_qf_detail::ccmath::isnan(x)) ? cpp_df_qf_detail::ccmath::numeric_limits<Real>::quiet_NaN()
|
||||
: (x == static_cast<Real>(-0)) ? static_cast<Real>(0)
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#ifndef BOOST_MP_CPP_DF_QF_DETAIL_CCMATH_FLOOR_2024_12_30_HPP
|
||||
#define BOOST_MP_CPP_DF_QF_DETAIL_CCMATH_FLOOR_2024_12_30_HPP
|
||||
|
||||
#include <boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -15,21 +17,98 @@ namespace boost { namespace multiprecision { namespace backends { namespace cpp_
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
constexpr auto floor_impl(T x) -> T
|
||||
// LCOV_EXCL_START
|
||||
template <typename Real>
|
||||
constexpr auto floor_pos_impl(Real arg) noexcept -> Real
|
||||
{
|
||||
// Default to the regular floor function.
|
||||
using std::floor;
|
||||
constexpr auto
|
||||
max_comp_val
|
||||
{
|
||||
Real(1) / ::boost::multiprecision::backends::cpp_df_qf_detail::ccmath::numeric_limits<Real>::epsilon()
|
||||
};
|
||||
|
||||
return floor(x);
|
||||
if (arg >= max_comp_val)
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
|
||||
Real result { 1 };
|
||||
|
||||
if(result <= arg)
|
||||
{
|
||||
while(result < arg)
|
||||
{
|
||||
result *= 2;
|
||||
}
|
||||
|
||||
while(result > arg)
|
||||
{
|
||||
--result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Real(0);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
constexpr auto floor_neg_impl(Real arg) noexcept -> Real
|
||||
{
|
||||
Real result { -1 };
|
||||
|
||||
if(result > arg)
|
||||
{
|
||||
while(result > arg)
|
||||
{
|
||||
result *= 2;
|
||||
}
|
||||
|
||||
while(result < arg)
|
||||
{
|
||||
++result;
|
||||
}
|
||||
|
||||
if(result != arg)
|
||||
{
|
||||
--result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
constexpr auto floor_impl(Real arg) noexcept -> Real
|
||||
{
|
||||
if(arg > 0)
|
||||
{
|
||||
return floor_pos_impl(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
return floor_neg_impl(arg);
|
||||
}
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename Real>
|
||||
constexpr auto floor(Real x) -> Real
|
||||
{
|
||||
return cpp_df_qf_detail::ccmath::detail::floor_impl<Real>(x);
|
||||
if (BOOST_MP_IS_CONST_EVALUATED(x))
|
||||
{
|
||||
return detail::floor_impl<Real>(x); // LCOV_EXCL_LINE
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::floor;
|
||||
|
||||
return floor(x);
|
||||
}
|
||||
}
|
||||
|
||||
} } } } } // namespace boost::multiprecision::backends::cpp_df_qf_detail::ccmath
|
||||
|
||||
@@ -17,41 +17,45 @@ namespace unsafe {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
constexpr auto fma_impl(T x, T y, T z) noexcept -> T
|
||||
// LCOV_EXCL_START
|
||||
template <typename Real>
|
||||
constexpr auto fma_impl(const Real x, const Real y, const Real z) noexcept -> Real
|
||||
{
|
||||
// Default to the written-out operations ...
|
||||
// ... and hope the compiler chooses FMA if available).
|
||||
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__INTEL_LLVM_COMPILER)
|
||||
BOOST_IF_CONSTEXPR (std::is_same<Real, float>::value)
|
||||
{
|
||||
return __builtin_fmaf(x, y, z);
|
||||
}
|
||||
else BOOST_IF_CONSTEXPR (std::is_same<Real, double>::value)
|
||||
{
|
||||
return __builtin_fma(x, y, z);
|
||||
}
|
||||
else BOOST_IF_CONSTEXPR (std::is_same<Real, long double>::value)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__INTEL_LLVM_COMPILER)
|
||||
template <>
|
||||
constexpr auto fma_impl<float>(float x, float y, float z) noexcept -> float
|
||||
{
|
||||
return __builtin_fmaf(x, y, z);
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr auto fma_impl<double>(double x, double y, double z) noexcept -> double
|
||||
{
|
||||
return __builtin_fma(x, y, z);
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr auto fma_impl<long double>(long double x, long double y, long double z) noexcept -> long double
|
||||
{
|
||||
return __builtin_fmal(x, y, z);
|
||||
}
|
||||
#endif
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename Real>
|
||||
constexpr auto fma(Real x, Real y, Real z) noexcept -> Real
|
||||
{
|
||||
return detail::fma_impl(x, y, z);
|
||||
if (BOOST_MP_IS_CONST_EVALUATED(x) && BOOST_MP_IS_CONST_EVALUATED(y) && BOOST_MP_IS_CONST_EVALUATED(z))
|
||||
{
|
||||
return detail::fma_impl(x, y, z); // LCOV_EXCL_LINE
|
||||
}
|
||||
else
|
||||
{
|
||||
using std::fma;
|
||||
|
||||
return fma(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace unsafe
|
||||
|
||||
@@ -11,13 +11,14 @@
|
||||
#include <boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_fabs.hpp>
|
||||
#include <boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isinf.hpp>
|
||||
#include <boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_isnan.hpp>
|
||||
#include <boost/multiprecision/cpp_df_qf/cpp_df_qf_detail_ccmath_limits.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace boost { namespace multiprecision { namespace backends { namespace cpp_df_qf_detail { namespace ccmath {
|
||||
|
||||
template <typename T>
|
||||
constexpr auto fpclassify(T x) -> int
|
||||
template <typename Real>
|
||||
constexpr auto fpclassify(Real x) noexcept -> int
|
||||
{
|
||||
if ((::boost::multiprecision::backends::cpp_df_qf_detail::ccmath::isnan)(x))
|
||||
{
|
||||
@@ -29,13 +30,13 @@ constexpr auto fpclassify(T x) -> int
|
||||
}
|
||||
else
|
||||
{
|
||||
const T fabs_x { ::boost::multiprecision::backends::cpp_df_qf_detail::ccmath::fabs(x) };
|
||||
const Real fabs_x { ::boost::multiprecision::backends::cpp_df_qf_detail::ccmath::fabs(x) };
|
||||
|
||||
if (fabs_x == T(0))
|
||||
if (fabs_x == Real(0))
|
||||
{
|
||||
return FP_ZERO;
|
||||
}
|
||||
else if ((fabs_x > 0) && (fabs_x < (::boost::multiprecision::backends::cpp_df_qf_detail::ccmath::numeric_limits<T>::min)()))
|
||||
else if ((fabs_x > 0) && (fabs_x < (::boost::multiprecision::backends::cpp_df_qf_detail::ccmath::numeric_limits<Real>::min)()))
|
||||
{
|
||||
return FP_SUBNORMAL;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
namespace boost { namespace multiprecision { namespace backends { namespace cpp_df_qf_detail { namespace ccmath {
|
||||
|
||||
template <class FloatingPointType>
|
||||
constexpr auto isnan(FloatingPointType x) -> bool
|
||||
constexpr auto isnan(FloatingPointType x) noexcept -> bool
|
||||
{
|
||||
return (x != x);
|
||||
}
|
||||
|
||||
@@ -66,12 +66,6 @@ constexpr auto ldexp(Real arg, int expval) noexcept -> Real
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
constexpr auto ldexp_constexpr(Real arg, int expval) -> Real
|
||||
{
|
||||
return detail::ldexp_impl<Real>(arg, expval);
|
||||
}
|
||||
|
||||
} } } } } // namespace boost::multiprecision::backends::cpp_df_qf_detail::ccmath
|
||||
|
||||
#endif // BOOST_MP_CPP_DF_QF_DETAIL_CCMATH_LDEXP_2023_01_07_HPP
|
||||
|
||||
@@ -1670,8 +1670,6 @@ constexpr auto eval_exp(cpp_double_fp_backend<FloatingPointType>& result, const
|
||||
using local_float_type = typename double_float_type::float_type;
|
||||
|
||||
// Get a local copy of the argument and force it to be positive.
|
||||
const bool b_neg { x.isneg_unchecked() };
|
||||
|
||||
const double_float_type xx { (!b_neg) ? x : -x };
|
||||
|
||||
// Check the range of the input.
|
||||
@@ -1796,8 +1794,6 @@ constexpr auto eval_exp(cpp_double_fp_backend<FloatingPointType>& result, const
|
||||
using local_float_type = typename double_float_type::float_type;
|
||||
|
||||
// Get a local copy of the argument and force it to be positive.
|
||||
const bool b_neg { x.isneg_unchecked() };
|
||||
|
||||
const double_float_type xx { (!b_neg) ? x : -x };
|
||||
|
||||
// Check the range of the input.
|
||||
|
||||
+35
-12
@@ -13,24 +13,47 @@
|
||||
|
||||
#include "test_arithmetic.hpp"
|
||||
|
||||
template<typename FloatType>
|
||||
auto test_constexpr_ness() noexcept -> void
|
||||
{
|
||||
using local_float_type = FloatType;
|
||||
|
||||
constexpr local_float_type one { 1 };
|
||||
|
||||
static_assert(static_cast<int>(one) == 1, "Error: constexpr local_float_type construction failed");
|
||||
|
||||
BOOST_CHECK(static_cast<int>(one) == 1);
|
||||
|
||||
constexpr local_float_type dd_a { 1.23 };
|
||||
constexpr local_float_type dd_b { 4.56 };
|
||||
constexpr local_float_type dd_c { dd_a * dd_b };
|
||||
|
||||
constexpr local_float_type dd_s { sqrt(dd_a) };
|
||||
constexpr local_float_type sqrt_hundred { sqrt(local_float_type(100)) };
|
||||
|
||||
static_assert(dd_c > 5, "Error in constexpr multiplication");
|
||||
static_assert(dd_s > 1, "Error in constexpr square root");
|
||||
static_assert(sqrt_hundred == 10, "Error in constexpr square root");
|
||||
|
||||
BOOST_CHECK(dd_c > 5);
|
||||
BOOST_CHECK(dd_s > 1);
|
||||
BOOST_CHECK(sqrt_hundred == 10);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using boost::multiprecision::cpp_double_float;
|
||||
using boost::multiprecision::cpp_double_double;
|
||||
using boost::multiprecision::cpp_double_long_double;
|
||||
::test_constexpr_ness<boost::multiprecision::cpp_double_float>();
|
||||
::test_constexpr_ness<boost::multiprecision::cpp_double_double>();
|
||||
::test_constexpr_ness<boost::multiprecision::cpp_double_long_double>();
|
||||
#ifdef BOOST_HAS_FLOAT128
|
||||
using boost::multiprecision::cpp_double_float128;
|
||||
::test_constexpr_ness<boost::multiprecision::cpp_double_float128>();
|
||||
#endif
|
||||
|
||||
constexpr cpp_double_double one { 1 };
|
||||
|
||||
static_assert(static_cast<int>(one) == 1, "Error:constexpr-ness of cpp_double_double constructor failed");
|
||||
|
||||
test<cpp_double_float>();
|
||||
test<cpp_double_double>();
|
||||
test<cpp_double_long_double>();
|
||||
test<boost::multiprecision::cpp_double_float>();
|
||||
test<boost::multiprecision::cpp_double_double>();
|
||||
test<boost::multiprecision::cpp_double_long_double>();
|
||||
#ifdef BOOST_HAS_FLOAT128
|
||||
test<cpp_double_float128>();
|
||||
test<boost::multiprecision::cpp_double_float128>();
|
||||
#endif
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user