From ee10b38879e6d184e0de45cf4bdfe974935a7ab3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 3 Feb 2023 20:15:54 -0800 Subject: [PATCH] Make real concept constexpr --- include/boost/math/concepts/real_concept.hpp | 116 +++++++++---------- test/Jamfile.v2 | 1 + test/test_constexpr_real_concept.cpp | 26 +++++ 3 files changed, 85 insertions(+), 58 deletions(-) create mode 100644 test/test_constexpr_real_concept.cpp diff --git a/include/boost/math/concepts/real_concept.hpp b/include/boost/math/concepts/real_concept.hpp index 446bfa8d5a..48afdd2f9b 100644 --- a/include/boost/math/concepts/real_concept.hpp +++ b/include/boost/math/concepts/real_concept.hpp @@ -60,62 +60,62 @@ class real_concept { public: // Constructors: - real_concept() : m_value(0){} - real_concept(char c) : m_value(c){} - real_concept(wchar_t c) : m_value(c){} - real_concept(unsigned char c) : m_value(c){} - real_concept(signed char c) : m_value(c){} - real_concept(unsigned short c) : m_value(c){} - real_concept(short c) : m_value(c){} - real_concept(unsigned int c) : m_value(c){} - real_concept(int c) : m_value(c){} - real_concept(unsigned long c) : m_value(c){} - real_concept(long c) : m_value(c){} - real_concept(unsigned long long c) : m_value(static_cast(c)){} - real_concept(long long c) : m_value(static_cast(c)){} - real_concept(float c) : m_value(c){} - real_concept(double c) : m_value(c){} - real_concept(long double c) : m_value(c){} + constexpr real_concept() : m_value(0){} + constexpr real_concept(char c) : m_value(c){} + constexpr real_concept(wchar_t c) : m_value(c){} + constexpr real_concept(unsigned char c) : m_value(c){} + constexpr real_concept(signed char c) : m_value(c){} + constexpr real_concept(unsigned short c) : m_value(c){} + constexpr real_concept(short c) : m_value(c){} + constexpr real_concept(unsigned int c) : m_value(c){} + constexpr real_concept(int c) : m_value(c){} + constexpr real_concept(unsigned long c) : m_value(c){} + constexpr real_concept(long c) : m_value(c){} + constexpr real_concept(unsigned long long c) : m_value(static_cast(c)){} + constexpr real_concept(long long c) : m_value(static_cast(c)){} + constexpr real_concept(float c) : m_value(c){} + constexpr real_concept(double c) : m_value(c){} + constexpr real_concept(long double c) : m_value(c){} #ifdef BOOST_MATH_USE_FLOAT128 - real_concept(BOOST_MATH_FLOAT128_TYPE c) : m_value(c){} + constexpr real_concept(BOOST_MATH_FLOAT128_TYPE c) : m_value(c){} #endif // Assignment: - real_concept& operator=(char c) { m_value = c; return *this; } - real_concept& operator=(unsigned char c) { m_value = c; return *this; } - real_concept& operator=(signed char c) { m_value = c; return *this; } - real_concept& operator=(wchar_t c) { m_value = c; return *this; } - real_concept& operator=(short c) { m_value = c; return *this; } - real_concept& operator=(unsigned short c) { m_value = c; return *this; } - real_concept& operator=(int c) { m_value = c; return *this; } - real_concept& operator=(unsigned int c) { m_value = c; return *this; } - real_concept& operator=(long c) { m_value = c; return *this; } - real_concept& operator=(unsigned long c) { m_value = c; return *this; } - real_concept& operator=(long long c) { m_value = static_cast(c); return *this; } - real_concept& operator=(unsigned long long c) { m_value = static_cast(c); return *this; } - real_concept& operator=(float c) { m_value = c; return *this; } - real_concept& operator=(double c) { m_value = c; return *this; } - real_concept& operator=(long double c) { m_value = c; return *this; } + constexpr real_concept& operator=(char c) { m_value = c; return *this; } + constexpr real_concept& operator=(unsigned char c) { m_value = c; return *this; } + constexpr real_concept& operator=(signed char c) { m_value = c; return *this; } + constexpr real_concept& operator=(wchar_t c) { m_value = c; return *this; } + constexpr real_concept& operator=(short c) { m_value = c; return *this; } + constexpr real_concept& operator=(unsigned short c) { m_value = c; return *this; } + constexpr real_concept& operator=(int c) { m_value = c; return *this; } + constexpr real_concept& operator=(unsigned int c) { m_value = c; return *this; } + constexpr real_concept& operator=(long c) { m_value = c; return *this; } + constexpr real_concept& operator=(unsigned long c) { m_value = c; return *this; } + constexpr real_concept& operator=(long long c) { m_value = static_cast(c); return *this; } + constexpr real_concept& operator=(unsigned long long c) { m_value = static_cast(c); return *this; } + constexpr real_concept& operator=(float c) { m_value = c; return *this; } + constexpr real_concept& operator=(double c) { m_value = c; return *this; } + constexpr real_concept& operator=(long double c) { m_value = c; return *this; } // Access: - real_concept_base_type value()const{ return m_value; } + constexpr real_concept_base_type value()const{ return m_value; } // Member arithmetic: - real_concept& operator+=(const real_concept& other) + constexpr real_concept& operator+=(const real_concept& other) { m_value += other.value(); return *this; } - real_concept& operator-=(const real_concept& other) + constexpr real_concept& operator-=(const real_concept& other) { m_value -= other.value(); return *this; } - real_concept& operator*=(const real_concept& other) + constexpr real_concept& operator*=(const real_concept& other) { m_value *= other.value(); return *this; } - real_concept& operator/=(const real_concept& other) + constexpr real_concept& operator/=(const real_concept& other) { m_value /= other.value(); return *this; } - real_concept operator-()const + constexpr real_concept operator-()const { return -m_value; } - real_concept const& operator+()const + constexpr real_concept const& operator+()const { return *this; } - real_concept& operator++() + constexpr real_concept& operator++() { ++m_value; return *this; } - real_concept& operator--() + constexpr real_concept& operator--() { --m_value; return *this; } private: @@ -123,25 +123,25 @@ class real_concept }; // Non-member arithmetic: -inline real_concept operator+(const real_concept& a, const real_concept& b) +constexpr real_concept operator+(const real_concept& a, const real_concept& b) { real_concept result(a); result += b; return result; } -inline real_concept operator-(const real_concept& a, const real_concept& b) +constexpr real_concept operator-(const real_concept& a, const real_concept& b) { real_concept result(a); result -= b; return result; } -inline real_concept operator*(const real_concept& a, const real_concept& b) +constexpr real_concept operator*(const real_concept& a, const real_concept& b) { real_concept result(a); result *= b; return result; } -inline real_concept operator/(const real_concept& a, const real_concept& b) +constexpr real_concept operator/(const real_concept& a, const real_concept& b) { real_concept result(a); result /= b; @@ -149,17 +149,17 @@ inline real_concept operator/(const real_concept& a, const real_concept& b) } // Comparison: -inline bool operator == (const real_concept& a, const real_concept& b) +constexpr bool operator == (const real_concept& a, const real_concept& b) { return a.value() == b.value(); } -inline bool operator != (const real_concept& a, const real_concept& b) +constexpr bool operator != (const real_concept& a, const real_concept& b) { return a.value() != b.value();} -inline bool operator < (const real_concept& a, const real_concept& b) +constexpr bool operator < (const real_concept& a, const real_concept& b) { return a.value() < b.value(); } -inline bool operator <= (const real_concept& a, const real_concept& b) +constexpr bool operator <= (const real_concept& a, const real_concept& b) { return a.value() <= b.value(); } -inline bool operator > (const real_concept& a, const real_concept& b) +constexpr bool operator > (const real_concept& a, const real_concept& b) { return a.value() > b.value(); } -inline bool operator >= (const real_concept& a, const real_concept& b) +constexpr bool operator >= (const real_concept& a, const real_concept& b) { return a.value() >= b.value(); } // Non-member functions: @@ -319,37 +319,37 @@ namespace tools { template <> -inline concepts::real_concept make_big_value(boost::math::tools::largest_float val, const char* , std::false_type const&, std::false_type const&) +constexpr concepts::real_concept make_big_value(boost::math::tools::largest_float val, const char* , std::false_type const&, std::false_type const&) { return val; // Can't use lexical_cast here, sometimes it fails.... } template <> -inline concepts::real_concept max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) +constexpr concepts::real_concept max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) { return max_value(); } template <> -inline concepts::real_concept min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) +constexpr concepts::real_concept min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) { return min_value(); } template <> -inline concepts::real_concept log_max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) +constexpr concepts::real_concept log_max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) { return log_max_value(); } template <> -inline concepts::real_concept log_min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) +constexpr concepts::real_concept log_min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) { return log_min_value(); } template <> -inline concepts::real_concept epsilon(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) +constexpr concepts::real_concept epsilon(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) { #ifdef __SUNPRO_CC return std::numeric_limits::epsilon(); @@ -359,7 +359,7 @@ inline concepts::real_concept epsilon(BOOST_MATH_EXPLICI } template <> -inline constexpr int digits(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) noexcept +constexpr int digits(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept)) noexcept { // Assume number of significand bits is same as real_concept_base_type, // unless std::numeric_limits::is_specialized to provide digits. diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4afae3bf74..c7b86b66b7 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1204,6 +1204,7 @@ test-suite misc : [ compile bernoulli_no_atomic_d.cpp ] [ compile bernoulli_no_atomic_mp.cpp ] [ compile-fail bernoulli_no_atomic_fail.cpp ] + [ run test_constexpr_real_concept.cpp ] ; test-suite interpolators : diff --git a/test/test_constexpr_real_concept.cpp b/test/test_constexpr_real_concept.cpp new file mode 100644 index 0000000000..21f0677466 --- /dev/null +++ b/test/test_constexpr_real_concept.cpp @@ -0,0 +1,26 @@ +// (C) Copyright Matt Borland 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) + +#include + +int main(void) +{ + using namespace boost::math::concepts; + + constexpr real_concept val1(1.0); + constexpr real_concept val2(2.0); + + // Member functions + static_assert(val1 < val2, "val1 should be less than val2"); + static_assert(val1 + val2 >= 2.999L, "Addition is 3"); + static_assert(val1 * val2 >= 1.999L, "Multiplication is 2"); + static_assert(val2 / val1 >= 1.999L, "Division is 2"); + + // Tools + static_assert(boost::math::tools::max_value() > 0, "max value"); + static_assert(boost::math::tools::min_value() > 0, "min value"); + static_assert(boost::math::tools::epsilon() > 0, "Epsilon"); + static_assert(boost::math::tools::digits() > 0, "Digits"); +}