Add more constexpr-ness

This commit is contained in:
ckormanyos
2025-09-01 13:36:08 +02:00
parent e7527eeb0c
commit 82da79c99d
8 changed files with 157 additions and 60 deletions
@@ -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
View File
@@ -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();
}