constexpr_float_arithmetic_examples.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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)
  5. #include <iostream>
  6. #include <boost/math/constants/constants.hpp>
  7. #ifdef BOOST_HAS_FLOAT128
  8. #include <boost/multiprecision/float128.hpp>
  9. #endif
  10. //[constexpr_circle
  11. template <class T>
  12. inline constexpr T circumference(T radius)
  13. {
  14. return 2 * boost::math::constants::pi<T>() * radius;
  15. }
  16. template <class T>
  17. inline constexpr T area(T radius)
  18. {
  19. return boost::math::constants::pi<T>() * radius * radius;
  20. }
  21. //]
  22. template <class T, unsigned Order>
  23. struct const_polynomial
  24. {
  25. public:
  26. T data[Order + 1];
  27. public:
  28. constexpr const_polynomial(T val = 0) : data{val} {}
  29. constexpr const_polynomial(const std::initializer_list<T>& init) : data{}
  30. {
  31. if (init.size() > Order + 1)
  32. throw std::range_error("Too many initializers in list");
  33. for (unsigned i = 0; i < init.size(); ++i)
  34. data[i] = init.begin()[i];
  35. }
  36. constexpr T& operator[](std::size_t N)
  37. {
  38. return data[N];
  39. }
  40. constexpr const T& operator[](std::size_t N) const
  41. {
  42. return data[N];
  43. }
  44. template <class U>
  45. constexpr T operator()(U val)const
  46. {
  47. T result = data[Order];
  48. for (unsigned i = Order; i > 0; --i)
  49. {
  50. result *= val;
  51. result += data[i - 1];
  52. }
  53. return result;
  54. }
  55. constexpr const_polynomial<T, Order - 1> derivative() const
  56. {
  57. const_polynomial<T, Order - 1> result;
  58. for (unsigned i = 1; i <= Order; ++i)
  59. {
  60. result[i - 1] = (*this)[i] * i;
  61. }
  62. return result;
  63. }
  64. constexpr const_polynomial operator-()
  65. {
  66. const_polynomial t(*this);
  67. for (unsigned i = 0; i <= Order; ++i)
  68. t[i] = -t[i];
  69. return t;
  70. }
  71. template <class U>
  72. constexpr const_polynomial& operator*=(U val)
  73. {
  74. for (unsigned i = 0; i <= Order; ++i)
  75. data[i] = data[i] * val;
  76. return *this;
  77. }
  78. template <class U>
  79. constexpr const_polynomial& operator/=(U val)
  80. {
  81. for (unsigned i = 0; i <= Order; ++i)
  82. data[i] = data[i] / val;
  83. return *this;
  84. }
  85. template <class U>
  86. constexpr const_polynomial& operator+=(U val)
  87. {
  88. data[0] += val;
  89. return *this;
  90. }
  91. template <class U>
  92. constexpr const_polynomial& operator-=(U val)
  93. {
  94. data[0] -= val;
  95. return *this;
  96. }
  97. };
  98. template <class T, unsigned Order1, unsigned Order2>
  99. inline constexpr const_polynomial<T, (Order1 > Order2 ? Order1 : Order2)> operator+(const const_polynomial<T, Order1>& a, const const_polynomial<T, Order2>& b)
  100. {
  101. if
  102. constexpr(Order1 > Order2)
  103. {
  104. const_polynomial<T, Order1> result(a);
  105. for (unsigned i = 0; i <= Order2; ++i)
  106. result[i] += b[i];
  107. return result;
  108. }
  109. else
  110. {
  111. const_polynomial<T, Order2> result(b);
  112. for (unsigned i = 0; i <= Order1; ++i)
  113. result[i] += a[i];
  114. return result;
  115. }
  116. }
  117. template <class T, unsigned Order1, unsigned Order2>
  118. inline constexpr const_polynomial<T, (Order1 > Order2 ? Order1 : Order2)> operator-(const const_polynomial<T, Order1>& a, const const_polynomial<T, Order2>& b)
  119. {
  120. if
  121. constexpr(Order1 > Order2)
  122. {
  123. const_polynomial<T, Order1> result(a);
  124. for (unsigned i = 0; i <= Order2; ++i)
  125. result[i] -= b[i];
  126. return result;
  127. }
  128. else
  129. {
  130. const_polynomial<T, Order2> result(b);
  131. for (unsigned i = 0; i <= Order1; ++i)
  132. result[i] = a[i] - b[i];
  133. return result;
  134. }
  135. }
  136. template <class T, unsigned Order1, unsigned Order2>
  137. inline constexpr const_polynomial<T, Order1 + Order2> operator*(const const_polynomial<T, Order1>& a, const const_polynomial<T, Order2>& b)
  138. {
  139. const_polynomial<T, Order1 + Order2> result;
  140. for (unsigned i = 0; i <= Order1; ++i)
  141. {
  142. for (unsigned j = 0; j <= Order2; ++j)
  143. {
  144. result[i + j] += a[i] * b[j];
  145. }
  146. }
  147. return result;
  148. }
  149. template <class T, unsigned Order, class U>
  150. inline constexpr const_polynomial<T, Order> operator*(const const_polynomial<T, Order>& a, const U& b)
  151. {
  152. const_polynomial<T, Order> result(a);
  153. for (unsigned i = 0; i <= Order; ++i)
  154. {
  155. result[i] *= b;
  156. }
  157. return result;
  158. }
  159. template <class U, class T, unsigned Order>
  160. inline constexpr const_polynomial<T, Order> operator*(const U& b, const const_polynomial<T, Order>& a)
  161. {
  162. const_polynomial<T, Order> result(a);
  163. for (unsigned i = 0; i <= Order; ++i)
  164. {
  165. result[i] *= b;
  166. }
  167. return result;
  168. }
  169. template <class T, unsigned Order, class U>
  170. inline constexpr const_polynomial<T, Order> operator/(const const_polynomial<T, Order>& a, const U& b)
  171. {
  172. const_polynomial<T, Order> result;
  173. for (unsigned i = 0; i <= Order; ++i)
  174. {
  175. result[i] /= b;
  176. }
  177. return result;
  178. }
  179. //[hermite_example
  180. template <class T, unsigned Order>
  181. class hermite_polynomial
  182. {
  183. const_polynomial<T, Order> m_data;
  184. public:
  185. constexpr hermite_polynomial() : m_data(hermite_polynomial<T, Order - 1>().data() * const_polynomial<T, 1>{0, 2} - hermite_polynomial<T, Order - 1>().data().derivative())
  186. {
  187. }
  188. constexpr const const_polynomial<T, Order>& data() const
  189. {
  190. return m_data;
  191. }
  192. constexpr const T& operator[](std::size_t N)const
  193. {
  194. return m_data[N];
  195. }
  196. template <class U>
  197. constexpr T operator()(U val)const
  198. {
  199. return m_data(val);
  200. }
  201. };
  202. //]
  203. //[hermite_example2
  204. template <class T>
  205. class hermite_polynomial<T, 0>
  206. {
  207. const_polynomial<T, 0> m_data;
  208. public:
  209. constexpr hermite_polynomial() : m_data{1} {}
  210. constexpr const const_polynomial<T, 0>& data() const
  211. {
  212. return m_data;
  213. }
  214. constexpr const T& operator[](std::size_t N) const
  215. {
  216. return m_data[N];
  217. }
  218. template <class U>
  219. constexpr T operator()(U val)
  220. {
  221. return m_data(val);
  222. }
  223. };
  224. template <class T>
  225. class hermite_polynomial<T, 1>
  226. {
  227. const_polynomial<T, 1> m_data;
  228. public:
  229. constexpr hermite_polynomial() : m_data{0, 2} {}
  230. constexpr const const_polynomial<T, 1>& data() const
  231. {
  232. return m_data;
  233. }
  234. constexpr const T& operator[](std::size_t N) const
  235. {
  236. return m_data[N];
  237. }
  238. template <class U>
  239. constexpr T operator()(U val)
  240. {
  241. return m_data(val);
  242. }
  243. };
  244. //]
  245. void test_double()
  246. {
  247. constexpr double radius = 2.25;
  248. constexpr double c = circumference(radius);
  249. constexpr double a = area(radius);
  250. std::cout << "Circumference = " << c << std::endl;
  251. std::cout << "Area = " << a << std::endl;
  252. constexpr const_polynomial<double, 2> pa = {3, 4};
  253. constexpr const_polynomial<double, 2> pb = {5, 6};
  254. static_assert(pa[0] == 3);
  255. static_assert(pa[1] == 4);
  256. constexpr auto pc = pa * 2;
  257. static_assert(pc[0] == 6);
  258. static_assert(pc[1] == 8);
  259. constexpr auto pd = 3 * pa;
  260. static_assert(pd[0] == 3 * 3);
  261. static_assert(pd[1] == 4 * 3);
  262. constexpr auto pe = pa + pb;
  263. static_assert(pe[0] == 3 + 5);
  264. static_assert(pe[1] == 4 + 6);
  265. constexpr auto pf = pa - pb;
  266. static_assert(pf[0] == 3 - 5);
  267. static_assert(pf[1] == 4 - 6);
  268. constexpr auto pg = pa * pb;
  269. static_assert(pg[0] == 15);
  270. static_assert(pg[1] == 38);
  271. static_assert(pg[2] == 24);
  272. constexpr hermite_polynomial<double, 2> h1;
  273. static_assert(h1[0] == -2);
  274. static_assert(h1[1] == 0);
  275. static_assert(h1[2] == 4);
  276. constexpr hermite_polynomial<double, 3> h3;
  277. static_assert(h3[0] == 0);
  278. static_assert(h3[1] == -12);
  279. static_assert(h3[2] == 0);
  280. static_assert(h3[3] == 8);
  281. constexpr hermite_polynomial<double, 9> h9;
  282. static_assert(h9[0] == 0);
  283. static_assert(h9[1] == 30240);
  284. static_assert(h9[2] == 0);
  285. static_assert(h9[3] == -80640);
  286. static_assert(h9[4] == 0);
  287. static_assert(h9[5] == 48384);
  288. static_assert(h9[6] == 0);
  289. static_assert(h9[7] == -9216);
  290. static_assert(h9[8] == 0);
  291. static_assert(h9[9] == 512);
  292. static_assert(h9(0.5) == 6481);
  293. }
  294. void test_float128()
  295. {
  296. #ifdef BOOST_HAS_FLOAT128
  297. //[constexpr_circle_usage
  298. using boost::multiprecision::float128;
  299. constexpr float128 radius = 2.25;
  300. constexpr float128 c = circumference(radius);
  301. constexpr float128 a = area(radius);
  302. std::cout << "Circumference = " << c << std::endl;
  303. std::cout << "Area = " << a << std::endl;
  304. //]
  305. constexpr hermite_polynomial<float128, 2> h1;
  306. static_assert(h1[0] == -2);
  307. static_assert(h1[1] == 0);
  308. static_assert(h1[2] == 4);
  309. constexpr hermite_polynomial<float128, 3> h3;
  310. static_assert(h3[0] == 0);
  311. static_assert(h3[1] == -12);
  312. static_assert(h3[2] == 0);
  313. static_assert(h3[3] == 8);
  314. //[hermite_example3
  315. constexpr hermite_polynomial<float128, 9> h9;
  316. //
  317. // Verify that the polynomial's coefficients match the known values:
  318. //
  319. static_assert(h9[0] == 0);
  320. static_assert(h9[1] == 30240);
  321. static_assert(h9[2] == 0);
  322. static_assert(h9[3] == -80640);
  323. static_assert(h9[4] == 0);
  324. static_assert(h9[5] == 48384);
  325. static_assert(h9[6] == 0);
  326. static_assert(h9[7] == -9216);
  327. static_assert(h9[8] == 0);
  328. static_assert(h9[9] == 512);
  329. //
  330. // Define an abscissa value to evaluate at:
  331. //
  332. constexpr float128 abscissa(0.5);
  333. //
  334. // Evaluate H_9(0.5) using all constexpr arithmetic:
  335. //
  336. static_assert(h9(abscissa) == 6481);
  337. //]
  338. #endif
  339. }
  340. int main()
  341. {
  342. test_double();
  343. test_float128();
  344. std::cout << "Done!" << std::endl;
  345. }