// (C) Copyright John Maddock 2019. // 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 #include #ifdef BOOST_HAS_FLOAT128 #include #endif //[constexpr_circle template inline constexpr T circumference(T radius) { return 2 * boost::math::constants::pi() * radius; } template inline constexpr T area(T radius) { return boost::math::constants::pi() * radius * radius; } //] template struct const_polynomial { public: T data[Order + 1]; public: constexpr const_polynomial(T val = 0) : data{val} {} constexpr const_polynomial(const std::initializer_list& init) : data{} { if (init.size() > Order + 1) throw std::range_error("Too many initializers in list"); for (unsigned i = 0; i < init.size(); ++i) data[i] = init.begin()[i]; } constexpr T& operator[](std::size_t N) { return data[N]; } constexpr const T& operator[](std::size_t N) const { return data[N]; } template constexpr T operator()(U val)const { T result = data[Order]; for (unsigned i = Order; i > 0; --i) { result *= val; result += data[i - 1]; } return result; } constexpr const_polynomial derivative() const { const_polynomial result; for (unsigned i = 1; i <= Order; ++i) { result[i - 1] = (*this)[i] * i; } return result; } constexpr const_polynomial operator-() { const_polynomial t(*this); for (unsigned i = 0; i <= Order; ++i) t[i] = -t[i]; return t; } template constexpr const_polynomial& operator*=(U val) { for (unsigned i = 0; i <= Order; ++i) data[i] = data[i] * val; return *this; } template constexpr const_polynomial& operator/=(U val) { for (unsigned i = 0; i <= Order; ++i) data[i] = data[i] / val; return *this; } template constexpr const_polynomial& operator+=(U val) { data[0] += val; return *this; } template constexpr const_polynomial& operator-=(U val) { data[0] -= val; return *this; } }; template inline constexpr const_polynomial Order2 ? Order1 : Order2)> operator+(const const_polynomial& a, const const_polynomial& b) { if constexpr(Order1 > Order2) { const_polynomial result(a); for (unsigned i = 0; i <= Order2; ++i) result[i] += b[i]; return result; } else { const_polynomial result(b); for (unsigned i = 0; i <= Order1; ++i) result[i] += a[i]; return result; } } template inline constexpr const_polynomial Order2 ? Order1 : Order2)> operator-(const const_polynomial& a, const const_polynomial& b) { if constexpr(Order1 > Order2) { const_polynomial result(a); for (unsigned i = 0; i <= Order2; ++i) result[i] -= b[i]; return result; } else { const_polynomial result(b); for (unsigned i = 0; i <= Order1; ++i) result[i] = a[i] - b[i]; return result; } } template inline constexpr const_polynomial operator*(const const_polynomial& a, const const_polynomial& b) { const_polynomial result; for (unsigned i = 0; i <= Order1; ++i) { for (unsigned j = 0; j <= Order2; ++j) { result[i + j] += a[i] * b[j]; } } return result; } template inline constexpr const_polynomial operator*(const const_polynomial& a, const U& b) { const_polynomial result(a); for (unsigned i = 0; i <= Order; ++i) { result[i] *= b; } return result; } template inline constexpr const_polynomial operator*(const U& b, const const_polynomial& a) { const_polynomial result(a); for (unsigned i = 0; i <= Order; ++i) { result[i] *= b; } return result; } template inline constexpr const_polynomial operator/(const const_polynomial& a, const U& b) { const_polynomial result; for (unsigned i = 0; i <= Order; ++i) { result[i] /= b; } return result; } //[hermite_example template class hermite_polynomial { const_polynomial m_data; public: constexpr hermite_polynomial() : m_data(hermite_polynomial().data() * const_polynomial{0, 2} - hermite_polynomial().data().derivative()) { } constexpr const const_polynomial& data() const { return m_data; } constexpr const T& operator[](std::size_t N)const { return m_data[N]; } template constexpr T operator()(U val)const { return m_data(val); } }; //] //[hermite_example2 template class hermite_polynomial { const_polynomial m_data; public: constexpr hermite_polynomial() : m_data{1} {} constexpr const const_polynomial& data() const { return m_data; } constexpr const T& operator[](std::size_t N) const { return m_data[N]; } template constexpr T operator()(U val) { return m_data(val); } }; template class hermite_polynomial { const_polynomial m_data; public: constexpr hermite_polynomial() : m_data{0, 2} {} constexpr const const_polynomial& data() const { return m_data; } constexpr const T& operator[](std::size_t N) const { return m_data[N]; } template constexpr T operator()(U val) { return m_data(val); } }; //] void test_double() { constexpr double radius = 2.25; constexpr double c = circumference(radius); constexpr double a = area(radius); std::cout << "Circumference = " << c << std::endl; std::cout << "Area = " << a << std::endl; constexpr const_polynomial pa = {3, 4}; constexpr const_polynomial pb = {5, 6}; static_assert(pa[0] == 3); static_assert(pa[1] == 4); constexpr auto pc = pa * 2; static_assert(pc[0] == 6); static_assert(pc[1] == 8); constexpr auto pd = 3 * pa; static_assert(pd[0] == 3 * 3); static_assert(pd[1] == 4 * 3); constexpr auto pe = pa + pb; static_assert(pe[0] == 3 + 5); static_assert(pe[1] == 4 + 6); constexpr auto pf = pa - pb; static_assert(pf[0] == 3 - 5); static_assert(pf[1] == 4 - 6); constexpr auto pg = pa * pb; static_assert(pg[0] == 15); static_assert(pg[1] == 38); static_assert(pg[2] == 24); constexpr hermite_polynomial h1; static_assert(h1[0] == -2); static_assert(h1[1] == 0); static_assert(h1[2] == 4); constexpr hermite_polynomial h3; static_assert(h3[0] == 0); static_assert(h3[1] == -12); static_assert(h3[2] == 0); static_assert(h3[3] == 8); constexpr hermite_polynomial h9; static_assert(h9[0] == 0); static_assert(h9[1] == 30240); static_assert(h9[2] == 0); static_assert(h9[3] == -80640); static_assert(h9[4] == 0); static_assert(h9[5] == 48384); static_assert(h9[6] == 0); static_assert(h9[7] == -9216); static_assert(h9[8] == 0); static_assert(h9[9] == 512); static_assert(h9(0.5) == 6481); } void test_float128() { #ifdef BOOST_HAS_FLOAT128 //[constexpr_circle_usage using boost::multiprecision::float128; constexpr float128 radius = 2.25; constexpr float128 c = circumference(radius); constexpr float128 a = area(radius); std::cout << "Circumference = " << c << std::endl; std::cout << "Area = " << a << std::endl; //] constexpr hermite_polynomial h1; static_assert(h1[0] == -2); static_assert(h1[1] == 0); static_assert(h1[2] == 4); constexpr hermite_polynomial h3; static_assert(h3[0] == 0); static_assert(h3[1] == -12); static_assert(h3[2] == 0); static_assert(h3[3] == 8); //[hermite_example3 constexpr hermite_polynomial h9; // // Verify that the polynomial's coefficients match the known values: // static_assert(h9[0] == 0); static_assert(h9[1] == 30240); static_assert(h9[2] == 0); static_assert(h9[3] == -80640); static_assert(h9[4] == 0); static_assert(h9[5] == 48384); static_assert(h9[6] == 0); static_assert(h9[7] == -9216); static_assert(h9[8] == 0); static_assert(h9[9] == 512); // // Define an abscissa value to evaluate at: // constexpr float128 abscissa(0.5); // // Evaluate H_9(0.5) using all constexpr arithmetic: // static_assert(h9(abscissa) == 6481); //] #endif } int main() { test_double(); test_float128(); std::cout << "Done!" << std::endl; }