1 // (C) Copyright John Maddock 2019.
2 // Use, modification and distribution are subject to the
3 // Boost Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 #include <boost/math/constants/constants.hpp>
8 #ifdef BOOST_HAS_FLOAT128
9 #include <boost/multiprecision/float128.hpp>
15 inline constexpr T circumference(T radius)
17 return 2 * boost::math::constants::pi<T>() * radius;
21 inline constexpr T area(T radius)
23 return boost::math::constants::pi<T>() * radius * radius;
27 template <class T, unsigned Order>
28 struct const_polynomial
34 constexpr const_polynomial(T val = 0) : data{val} {}
35 constexpr const_polynomial(const std::initializer_list<T>& init) : data{}
37 if (init.size() > Order + 1)
38 throw std::range_error("Too many initializers in list");
39 for (unsigned i = 0; i < init.size(); ++i)
40 data[i] = init.begin()[i];
42 constexpr T& operator[](std::size_t N)
46 constexpr const T& operator[](std::size_t N) const
51 constexpr T operator()(U val)const
53 T result = data[Order];
54 for (unsigned i = Order; i > 0; --i)
57 result += data[i - 1];
61 constexpr const_polynomial<T, Order - 1> derivative() const
63 const_polynomial<T, Order - 1> result;
64 for (unsigned i = 1; i <= Order; ++i)
66 result[i - 1] = (*this)[i] * i;
70 constexpr const_polynomial operator-()
72 const_polynomial t(*this);
73 for (unsigned i = 0; i <= Order; ++i)
78 constexpr const_polynomial& operator*=(U val)
80 for (unsigned i = 0; i <= Order; ++i)
81 data[i] = data[i] * val;
85 constexpr const_polynomial& operator/=(U val)
87 for (unsigned i = 0; i <= Order; ++i)
88 data[i] = data[i] / val;
92 constexpr const_polynomial& operator+=(U val)
98 constexpr const_polynomial& operator-=(U val)
105 template <class T, unsigned Order1, unsigned Order2>
106 inline constexpr const_polynomial<T, (Order1 > Order2 ? Order1 : Order2)> operator+(const const_polynomial<T, Order1>& a, const const_polynomial<T, Order2>& b)
109 constexpr(Order1 > Order2)
111 const_polynomial<T, Order1> result(a);
112 for (unsigned i = 0; i <= Order2; ++i)
118 const_polynomial<T, Order2> result(b);
119 for (unsigned i = 0; i <= Order1; ++i)
124 template <class T, unsigned Order1, unsigned Order2>
125 inline constexpr const_polynomial<T, (Order1 > Order2 ? Order1 : Order2)> operator-(const const_polynomial<T, Order1>& a, const const_polynomial<T, Order2>& b)
128 constexpr(Order1 > Order2)
130 const_polynomial<T, Order1> result(a);
131 for (unsigned i = 0; i <= Order2; ++i)
137 const_polynomial<T, Order2> result(b);
138 for (unsigned i = 0; i <= Order1; ++i)
139 result[i] = a[i] - b[i];
143 template <class T, unsigned Order1, unsigned Order2>
144 inline constexpr const_polynomial<T, Order1 + Order2> operator*(const const_polynomial<T, Order1>& a, const const_polynomial<T, Order2>& b)
146 const_polynomial<T, Order1 + Order2> result;
147 for (unsigned i = 0; i <= Order1; ++i)
149 for (unsigned j = 0; j <= Order2; ++j)
151 result[i + j] += a[i] * b[j];
156 template <class T, unsigned Order, class U>
157 inline constexpr const_polynomial<T, Order> operator*(const const_polynomial<T, Order>& a, const U& b)
159 const_polynomial<T, Order> result(a);
160 for (unsigned i = 0; i <= Order; ++i)
166 template <class U, class T, unsigned Order>
167 inline constexpr const_polynomial<T, Order> operator*(const U& b, const const_polynomial<T, Order>& a)
169 const_polynomial<T, Order> result(a);
170 for (unsigned i = 0; i <= Order; ++i)
176 template <class T, unsigned Order, class U>
177 inline constexpr const_polynomial<T, Order> operator/(const const_polynomial<T, Order>& a, const U& b)
179 const_polynomial<T, Order> result;
180 for (unsigned i = 0; i <= Order; ++i)
188 template <class T, unsigned Order>
189 class hermite_polynomial
191 const_polynomial<T, Order> m_data;
194 constexpr hermite_polynomial() : m_data(hermite_polynomial<T, Order - 1>().data() * const_polynomial<T, 1>{0, 2} - hermite_polynomial<T, Order - 1>().data().derivative())
197 constexpr const const_polynomial<T, Order>& data() const
201 constexpr const T& operator[](std::size_t N)const
206 constexpr T operator()(U val)const
214 class hermite_polynomial<T, 0>
216 const_polynomial<T, 0> m_data;
219 constexpr hermite_polynomial() : m_data{1} {}
220 constexpr const const_polynomial<T, 0>& data() const
224 constexpr const T& operator[](std::size_t N) const
229 constexpr T operator()(U val)
236 class hermite_polynomial<T, 1>
238 const_polynomial<T, 1> m_data;
241 constexpr hermite_polynomial() : m_data{0, 2} {}
242 constexpr const const_polynomial<T, 1>& data() const
246 constexpr const T& operator[](std::size_t N) const
251 constexpr T operator()(U val)
260 constexpr double radius = 2.25;
261 constexpr double c = circumference(radius);
262 constexpr double a = area(radius);
264 std::cout << "Circumference = " << c << std::endl;
265 std::cout << "Area = " << a << std::endl;
267 constexpr const_polynomial<double, 2> pa = {3, 4};
268 constexpr const_polynomial<double, 2> pb = {5, 6};
269 static_assert(pa[0] == 3);
270 static_assert(pa[1] == 4);
271 constexpr auto pc = pa * 2;
272 static_assert(pc[0] == 6);
273 static_assert(pc[1] == 8);
274 constexpr auto pd = 3 * pa;
275 static_assert(pd[0] == 3 * 3);
276 static_assert(pd[1] == 4 * 3);
277 constexpr auto pe = pa + pb;
278 static_assert(pe[0] == 3 + 5);
279 static_assert(pe[1] == 4 + 6);
280 constexpr auto pf = pa - pb;
281 static_assert(pf[0] == 3 - 5);
282 static_assert(pf[1] == 4 - 6);
283 constexpr auto pg = pa * pb;
284 static_assert(pg[0] == 15);
285 static_assert(pg[1] == 38);
286 static_assert(pg[2] == 24);
288 constexpr hermite_polynomial<double, 2> h1;
289 static_assert(h1[0] == -2);
290 static_assert(h1[1] == 0);
291 static_assert(h1[2] == 4);
293 constexpr hermite_polynomial<double, 3> h3;
294 static_assert(h3[0] == 0);
295 static_assert(h3[1] == -12);
296 static_assert(h3[2] == 0);
297 static_assert(h3[3] == 8);
299 constexpr hermite_polynomial<double, 9> h9;
300 static_assert(h9[0] == 0);
301 static_assert(h9[1] == 30240);
302 static_assert(h9[2] == 0);
303 static_assert(h9[3] == -80640);
304 static_assert(h9[4] == 0);
305 static_assert(h9[5] == 48384);
306 static_assert(h9[6] == 0);
307 static_assert(h9[7] == -9216);
308 static_assert(h9[8] == 0);
309 static_assert(h9[9] == 512);
311 static_assert(h9(0.5) == 6481);
317 #ifdef BOOST_HAS_FLOAT128
318 //[constexpr_circle_usage
320 using boost::multiprecision::float128;
322 constexpr float128 radius = 2.25;
323 constexpr float128 c = circumference(radius);
324 constexpr float128 a = area(radius);
326 std::cout << "Circumference = " << c << std::endl;
327 std::cout << "Area = " << a << std::endl;
331 constexpr hermite_polynomial<float128, 2> h1;
332 static_assert(h1[0] == -2);
333 static_assert(h1[1] == 0);
334 static_assert(h1[2] == 4);
336 constexpr hermite_polynomial<float128, 3> h3;
337 static_assert(h3[0] == 0);
338 static_assert(h3[1] == -12);
339 static_assert(h3[2] == 0);
340 static_assert(h3[3] == 8);
343 constexpr hermite_polynomial<float128, 9> h9;
345 // Verify that the polynomial's coefficients match the known values:
347 static_assert(h9[0] == 0);
348 static_assert(h9[1] == 30240);
349 static_assert(h9[2] == 0);
350 static_assert(h9[3] == -80640);
351 static_assert(h9[4] == 0);
352 static_assert(h9[5] == 48384);
353 static_assert(h9[6] == 0);
354 static_assert(h9[7] == -9216);
355 static_assert(h9[8] == 0);
356 static_assert(h9[9] == 512);
358 // Define an abscissa value to evaluate at:
360 constexpr float128 abscissa(0.5);
362 // Evaluate H_9(0.5) using all constexpr arithmetic:
364 static_assert(h9(abscissa) == 6481);
373 std::cout << "Done!" << std::endl;