cardinal_trigonometric_detail.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. // (C) Copyright Nick Thompson 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. #ifndef BOOST_MATH_INTERPOLATORS_DETAIL_CARDINAL_TRIGONOMETRIC_HPP
  6. #define BOOST_MATH_INTERPOLATORS_DETAIL_CARDINAL_TRIGONOMETRIC_HPP
  7. #include <cstddef>
  8. #include <cmath>
  9. #include <stdexcept>
  10. #include <boost/math/constants/constants.hpp>
  11. #ifdef BOOST_HAS_FLOAT128
  12. #include <quadmath.h>
  13. #endif
  14. #ifdef __has_include
  15. # if __has_include(<fftw3.h>)
  16. # include <fftw3.h>
  17. # else
  18. # error "This feature is unavailable without fftw3 installed"
  19. #endif
  20. #endif
  21. namespace boost { namespace math { namespace interpolators { namespace detail {
  22. template<typename Real>
  23. class cardinal_trigonometric_detail {
  24. public:
  25. cardinal_trigonometric_detail(const Real* data, size_t length, Real t0, Real h)
  26. {
  27. m_data = data;
  28. m_length = length;
  29. m_t0 = t0;
  30. m_h = h;
  31. throw std::domain_error("Not implemented.");
  32. }
  33. private:
  34. size_t m_length;
  35. Real m_t0;
  36. Real m_h;
  37. Real* m_data;
  38. };
  39. template<>
  40. class cardinal_trigonometric_detail<float> {
  41. public:
  42. cardinal_trigonometric_detail(const float* data, size_t length, float t0, float h) : m_t0{t0}, m_h{h}
  43. {
  44. if (length == 0)
  45. {
  46. throw std::logic_error("At least one sample is required.");
  47. }
  48. if (h <= 0)
  49. {
  50. throw std::logic_error("The step size must be > 0");
  51. }
  52. // The period sadly must be stored, since the complex vector has length that cannot be used to recover the period:
  53. m_T = m_h*length;
  54. m_complex_vector_size = length/2 + 1;
  55. m_gamma = fftwf_alloc_complex(m_complex_vector_size);
  56. // The const_cast is legitimate: FFTW does not change the data as long as FFTW_ESTIMATE is provided.
  57. fftwf_plan plan = fftwf_plan_dft_r2c_1d(length, const_cast<float*>(data), m_gamma, FFTW_ESTIMATE);
  58. // FFTW says a null plan is impossible with the basic interface we are using, and I have no reason to doubt them.
  59. // But it just feels weird not to check this:
  60. if (!plan)
  61. {
  62. throw std::logic_error("A null fftw plan was created.");
  63. }
  64. fftwf_execute(plan);
  65. fftwf_destroy_plan(plan);
  66. float denom = length;
  67. for (size_t k = 0; k < m_complex_vector_size; ++k)
  68. {
  69. m_gamma[k][0] /= denom;
  70. m_gamma[k][1] /= denom;
  71. }
  72. if (length % 2 == 0)
  73. {
  74. m_gamma[m_complex_vector_size -1][0] /= 2;
  75. // numerically, m_gamma[m_complex_vector_size -1][1] should be zero . . .
  76. // I believe, but need to check, that FFTW guarantees that it is identically zero.
  77. }
  78. }
  79. cardinal_trigonometric_detail(const cardinal_trigonometric_detail& old) = delete;
  80. cardinal_trigonometric_detail& operator=(const cardinal_trigonometric_detail&) = delete;
  81. cardinal_trigonometric_detail(cardinal_trigonometric_detail &&) = delete;
  82. float operator()(float t) const
  83. {
  84. using std::sin;
  85. using std::cos;
  86. using boost::math::constants::two_pi;
  87. using std::exp;
  88. float s = m_gamma[0][0];
  89. float x = two_pi<float>()*(t - m_t0)/m_T;
  90. fftwf_complex z;
  91. // boost::math::cos_pi with a redefinition of x? Not now . . .
  92. z[0] = cos(x);
  93. z[1] = sin(x);
  94. fftwf_complex b{0, 0};
  95. // u = b*z
  96. fftwf_complex u;
  97. for (size_t k = m_complex_vector_size - 1; k >= 1; --k) {
  98. u[0] = b[0]*z[0] - b[1]*z[1];
  99. u[1] = b[0]*z[1] + b[1]*z[0];
  100. b[0] = m_gamma[k][0] + u[0];
  101. b[1] = m_gamma[k][1] + u[1];
  102. }
  103. s += 2*(b[0]*z[0] - b[1]*z[1]);
  104. return s;
  105. }
  106. float prime(float t) const
  107. {
  108. using std::sin;
  109. using std::cos;
  110. using boost::math::constants::two_pi;
  111. using std::exp;
  112. float x = two_pi<float>()*(t - m_t0)/m_T;
  113. fftwf_complex z;
  114. z[0] = cos(x);
  115. z[1] = sin(x);
  116. fftwf_complex b{0, 0};
  117. // u = b*z
  118. fftwf_complex u;
  119. for (size_t k = m_complex_vector_size - 1; k >= 1; --k)
  120. {
  121. u[0] = b[0]*z[0] - b[1]*z[1];
  122. u[1] = b[0]*z[1] + b[1]*z[0];
  123. b[0] = k*m_gamma[k][0] + u[0];
  124. b[1] = k*m_gamma[k][1] + u[1];
  125. }
  126. // b*z = (b[0]*z[0] - b[1]*z[1]) + i(b[1]*z[0] + b[0]*z[1])
  127. return -2*two_pi<float>()*(b[1]*z[0] + b[0]*z[1])/m_T;
  128. }
  129. float double_prime(float t) const
  130. {
  131. using std::sin;
  132. using std::cos;
  133. using boost::math::constants::two_pi;
  134. using std::exp;
  135. float x = two_pi<float>()*(t - m_t0)/m_T;
  136. fftwf_complex z;
  137. z[0] = cos(x);
  138. z[1] = sin(x);
  139. fftwf_complex b{0, 0};
  140. // u = b*z
  141. fftwf_complex u;
  142. for (size_t k = m_complex_vector_size - 1; k >= 1; --k)
  143. {
  144. u[0] = b[0]*z[0] - b[1]*z[1];
  145. u[1] = b[0]*z[1] + b[1]*z[0];
  146. b[0] = k*k*m_gamma[k][0] + u[0];
  147. b[1] = k*k*m_gamma[k][1] + u[1];
  148. }
  149. // b*z = (b[0]*z[0] - b[1]*z[1]) + i(b[1]*z[0] + b[0]*z[1])
  150. return -2*two_pi<float>()*two_pi<float>()*(b[0]*z[0] - b[1]*z[1])/(m_T*m_T);
  151. }
  152. float period() const
  153. {
  154. return m_T;
  155. }
  156. float integrate() const
  157. {
  158. return m_T*m_gamma[0][0];
  159. }
  160. float squared_l2() const
  161. {
  162. float s = 0;
  163. // Always add smallest to largest for accuracy.
  164. for (size_t i = m_complex_vector_size - 1; i >= 1; --i)
  165. {
  166. s += (m_gamma[i][0]*m_gamma[i][0] + m_gamma[i][1]*m_gamma[i][1]);
  167. }
  168. s *= 2;
  169. s += m_gamma[0][0]*m_gamma[0][0];
  170. return s*m_T;
  171. }
  172. ~cardinal_trigonometric_detail()
  173. {
  174. if (m_gamma)
  175. {
  176. fftwf_free(m_gamma);
  177. m_gamma = nullptr;
  178. }
  179. }
  180. private:
  181. float m_t0;
  182. float m_h;
  183. float m_T;
  184. fftwf_complex* m_gamma;
  185. size_t m_complex_vector_size;
  186. };
  187. template<>
  188. class cardinal_trigonometric_detail<double> {
  189. public:
  190. cardinal_trigonometric_detail(const double* data, size_t length, double t0, double h) : m_t0{t0}, m_h{h}
  191. {
  192. if (length == 0)
  193. {
  194. throw std::logic_error("At least one sample is required.");
  195. }
  196. if (h <= 0)
  197. {
  198. throw std::logic_error("The step size must be > 0");
  199. }
  200. m_T = m_h*length;
  201. m_complex_vector_size = length/2 + 1;
  202. m_gamma = fftw_alloc_complex(m_complex_vector_size);
  203. fftw_plan plan = fftw_plan_dft_r2c_1d(length, const_cast<double*>(data), m_gamma, FFTW_ESTIMATE);
  204. if (!plan)
  205. {
  206. throw std::logic_error("A null fftw plan was created.");
  207. }
  208. fftw_execute(plan);
  209. fftw_destroy_plan(plan);
  210. double denom = length;
  211. for (size_t k = 0; k < m_complex_vector_size; ++k)
  212. {
  213. m_gamma[k][0] /= denom;
  214. m_gamma[k][1] /= denom;
  215. }
  216. if (length % 2 == 0)
  217. {
  218. m_gamma[m_complex_vector_size -1][0] /= 2;
  219. }
  220. }
  221. cardinal_trigonometric_detail(const cardinal_trigonometric_detail& old) = delete;
  222. cardinal_trigonometric_detail& operator=(const cardinal_trigonometric_detail&) = delete;
  223. cardinal_trigonometric_detail(cardinal_trigonometric_detail &&) = delete;
  224. double operator()(double t) const
  225. {
  226. using std::sin;
  227. using std::cos;
  228. using boost::math::constants::two_pi;
  229. using std::exp;
  230. double s = m_gamma[0][0];
  231. double x = two_pi<double>()*(t - m_t0)/m_T;
  232. fftw_complex z;
  233. z[0] = cos(x);
  234. z[1] = sin(x);
  235. fftw_complex b{0, 0};
  236. // u = b*z
  237. fftw_complex u;
  238. for (size_t k = m_complex_vector_size - 1; k >= 1; --k)
  239. {
  240. u[0] = b[0]*z[0] - b[1]*z[1];
  241. u[1] = b[0]*z[1] + b[1]*z[0];
  242. b[0] = m_gamma[k][0] + u[0];
  243. b[1] = m_gamma[k][1] + u[1];
  244. }
  245. s += 2*(b[0]*z[0] - b[1]*z[1]);
  246. return s;
  247. }
  248. double prime(double t) const
  249. {
  250. using std::sin;
  251. using std::cos;
  252. using boost::math::constants::two_pi;
  253. using std::exp;
  254. double x = two_pi<double>()*(t - m_t0)/m_T;
  255. fftw_complex z;
  256. z[0] = cos(x);
  257. z[1] = sin(x);
  258. fftw_complex b{0, 0};
  259. // u = b*z
  260. fftw_complex u;
  261. for (size_t k = m_complex_vector_size - 1; k >= 1; --k)
  262. {
  263. u[0] = b[0]*z[0] - b[1]*z[1];
  264. u[1] = b[0]*z[1] + b[1]*z[0];
  265. b[0] = k*m_gamma[k][0] + u[0];
  266. b[1] = k*m_gamma[k][1] + u[1];
  267. }
  268. // b*z = (b[0]*z[0] - b[1]*z[1]) + i(b[1]*z[0] + b[0]*z[1])
  269. return -2*two_pi<double>()*(b[1]*z[0] + b[0]*z[1])/m_T;
  270. }
  271. double double_prime(double t) const
  272. {
  273. using std::sin;
  274. using std::cos;
  275. using boost::math::constants::two_pi;
  276. using std::exp;
  277. double x = two_pi<double>()*(t - m_t0)/m_T;
  278. fftw_complex z;
  279. z[0] = cos(x);
  280. z[1] = sin(x);
  281. fftw_complex b{0, 0};
  282. // u = b*z
  283. fftw_complex u;
  284. for (size_t k = m_complex_vector_size - 1; k >= 1; --k)
  285. {
  286. u[0] = b[0]*z[0] - b[1]*z[1];
  287. u[1] = b[0]*z[1] + b[1]*z[0];
  288. b[0] = k*k*m_gamma[k][0] + u[0];
  289. b[1] = k*k*m_gamma[k][1] + u[1];
  290. }
  291. // b*z = (b[0]*z[0] - b[1]*z[1]) + i(b[1]*z[0] + b[0]*z[1])
  292. return -2*two_pi<double>()*two_pi<double>()*(b[0]*z[0] - b[1]*z[1])/(m_T*m_T);
  293. }
  294. double period() const
  295. {
  296. return m_T;
  297. }
  298. double integrate() const
  299. {
  300. return m_T*m_gamma[0][0];
  301. }
  302. double squared_l2() const
  303. {
  304. double s = 0;
  305. for (size_t i = m_complex_vector_size - 1; i >= 1; --i)
  306. {
  307. s += (m_gamma[i][0]*m_gamma[i][0] + m_gamma[i][1]*m_gamma[i][1]);
  308. }
  309. s *= 2;
  310. s += m_gamma[0][0]*m_gamma[0][0];
  311. return s*m_T;
  312. }
  313. ~cardinal_trigonometric_detail()
  314. {
  315. if (m_gamma)
  316. {
  317. fftw_free(m_gamma);
  318. m_gamma = nullptr;
  319. }
  320. }
  321. private:
  322. double m_t0;
  323. double m_h;
  324. double m_T;
  325. fftw_complex* m_gamma;
  326. size_t m_complex_vector_size;
  327. };
  328. template<>
  329. class cardinal_trigonometric_detail<long double> {
  330. public:
  331. cardinal_trigonometric_detail(const long double* data, size_t length, long double t0, long double h) : m_t0{t0}, m_h{h}
  332. {
  333. if (length == 0)
  334. {
  335. throw std::logic_error("At least one sample is required.");
  336. }
  337. if (h <= 0)
  338. {
  339. throw std::logic_error("The step size must be > 0");
  340. }
  341. m_T = m_h*length;
  342. m_complex_vector_size = length/2 + 1;
  343. m_gamma = fftwl_alloc_complex(m_complex_vector_size);
  344. fftwl_plan plan = fftwl_plan_dft_r2c_1d(length, const_cast<long double*>(data), m_gamma, FFTW_ESTIMATE);
  345. if (!plan)
  346. {
  347. throw std::logic_error("A null fftw plan was created.");
  348. }
  349. fftwl_execute(plan);
  350. fftwl_destroy_plan(plan);
  351. long double denom = length;
  352. for (size_t k = 0; k < m_complex_vector_size; ++k)
  353. {
  354. m_gamma[k][0] /= denom;
  355. m_gamma[k][1] /= denom;
  356. }
  357. if (length % 2 == 0) {
  358. m_gamma[m_complex_vector_size -1][0] /= 2;
  359. }
  360. }
  361. cardinal_trigonometric_detail(const cardinal_trigonometric_detail& old) = delete;
  362. cardinal_trigonometric_detail& operator=(const cardinal_trigonometric_detail&) = delete;
  363. cardinal_trigonometric_detail(cardinal_trigonometric_detail &&) = delete;
  364. long double operator()(long double t) const
  365. {
  366. using std::sin;
  367. using std::cos;
  368. using boost::math::constants::two_pi;
  369. using std::exp;
  370. long double s = m_gamma[0][0];
  371. long double x = two_pi<long double>()*(t - m_t0)/m_T;
  372. fftwl_complex z;
  373. z[0] = cos(x);
  374. z[1] = sin(x);
  375. fftwl_complex b{0, 0};
  376. fftwl_complex u;
  377. for (size_t k = m_complex_vector_size - 1; k >= 1; --k)
  378. {
  379. u[0] = b[0]*z[0] - b[1]*z[1];
  380. u[1] = b[0]*z[1] + b[1]*z[0];
  381. b[0] = m_gamma[k][0] + u[0];
  382. b[1] = m_gamma[k][1] + u[1];
  383. }
  384. s += 2*(b[0]*z[0] - b[1]*z[1]);
  385. return s;
  386. }
  387. long double prime(long double t) const
  388. {
  389. using std::sin;
  390. using std::cos;
  391. using boost::math::constants::two_pi;
  392. using std::exp;
  393. long double x = two_pi<long double>()*(t - m_t0)/m_T;
  394. fftwl_complex z;
  395. z[0] = cos(x);
  396. z[1] = sin(x);
  397. fftwl_complex b{0, 0};
  398. // u = b*z
  399. fftwl_complex u;
  400. for (size_t k = m_complex_vector_size - 1; k >= 1; --k)
  401. {
  402. u[0] = b[0]*z[0] - b[1]*z[1];
  403. u[1] = b[0]*z[1] + b[1]*z[0];
  404. b[0] = k*m_gamma[k][0] + u[0];
  405. b[1] = k*m_gamma[k][1] + u[1];
  406. }
  407. // b*z = (b[0]*z[0] - b[1]*z[1]) + i(b[1]*z[0] + b[0]*z[1])
  408. return -2*two_pi<long double>()*(b[1]*z[0] + b[0]*z[1])/m_T;
  409. }
  410. long double double_prime(long double t) const
  411. {
  412. using std::sin;
  413. using std::cos;
  414. using boost::math::constants::two_pi;
  415. using std::exp;
  416. long double x = two_pi<long double>()*(t - m_t0)/m_T;
  417. fftwl_complex z;
  418. z[0] = cos(x);
  419. z[1] = sin(x);
  420. fftwl_complex b{0, 0};
  421. // u = b*z
  422. fftwl_complex u;
  423. for (size_t k = m_complex_vector_size - 1; k >= 1; --k)
  424. {
  425. u[0] = b[0]*z[0] - b[1]*z[1];
  426. u[1] = b[0]*z[1] + b[1]*z[0];
  427. b[0] = k*k*m_gamma[k][0] + u[0];
  428. b[1] = k*k*m_gamma[k][1] + u[1];
  429. }
  430. // b*z = (b[0]*z[0] - b[1]*z[1]) + i(b[1]*z[0] + b[0]*z[1])
  431. return -2*two_pi<long double>()*two_pi<long double>()*(b[0]*z[0] - b[1]*z[1])/(m_T*m_T);
  432. }
  433. long double period() const
  434. {
  435. return m_T;
  436. }
  437. long double integrate() const
  438. {
  439. return m_T*m_gamma[0][0];
  440. }
  441. long double squared_l2() const
  442. {
  443. long double s = 0;
  444. for (size_t i = m_complex_vector_size - 1; i >= 1; --i)
  445. {
  446. s += (m_gamma[i][0]*m_gamma[i][0] + m_gamma[i][1]*m_gamma[i][1]);
  447. }
  448. s *= 2;
  449. s += m_gamma[0][0]*m_gamma[0][0];
  450. return s*m_T;
  451. }
  452. ~cardinal_trigonometric_detail()
  453. {
  454. if (m_gamma)
  455. {
  456. fftwl_free(m_gamma);
  457. m_gamma = nullptr;
  458. }
  459. }
  460. private:
  461. long double m_t0;
  462. long double m_h;
  463. long double m_T;
  464. fftwl_complex* m_gamma;
  465. size_t m_complex_vector_size;
  466. };
  467. #ifdef BOOST_HAS_FLOAT128
  468. template<>
  469. class cardinal_trigonometric_detail<__float128> {
  470. public:
  471. cardinal_trigonometric_detail(const __float128* data, size_t length, __float128 t0, __float128 h) : m_t0{t0}, m_h{h}
  472. {
  473. if (length == 0)
  474. {
  475. throw std::logic_error("At least one sample is required.");
  476. }
  477. if (h <= 0)
  478. {
  479. throw std::logic_error("The step size must be > 0");
  480. }
  481. m_T = m_h*length;
  482. m_complex_vector_size = length/2 + 1;
  483. m_gamma = fftwq_alloc_complex(m_complex_vector_size);
  484. fftwq_plan plan = fftwq_plan_dft_r2c_1d(length, reinterpret_cast<__float128*>(const_cast<__float128*>(data)), m_gamma, FFTW_ESTIMATE);
  485. if (!plan)
  486. {
  487. throw std::logic_error("A null fftw plan was created.");
  488. }
  489. fftwq_execute(plan);
  490. fftwq_destroy_plan(plan);
  491. __float128 denom = length;
  492. for (size_t k = 0; k < m_complex_vector_size; ++k)
  493. {
  494. m_gamma[k][0] /= denom;
  495. m_gamma[k][1] /= denom;
  496. }
  497. if (length % 2 == 0)
  498. {
  499. m_gamma[m_complex_vector_size -1][0] /= 2;
  500. }
  501. }
  502. cardinal_trigonometric_detail(const cardinal_trigonometric_detail& old) = delete;
  503. cardinal_trigonometric_detail& operator=(const cardinal_trigonometric_detail&) = delete;
  504. cardinal_trigonometric_detail(cardinal_trigonometric_detail &&) = delete;
  505. __float128 operator()(__float128 t) const
  506. {
  507. using std::sin;
  508. using std::cos;
  509. using boost::math::constants::two_pi;
  510. using std::exp;
  511. __float128 s = m_gamma[0][0];
  512. __float128 x = two_pi<__float128>()*(t - m_t0)/m_T;
  513. fftwq_complex z;
  514. z[0] = cosq(x);
  515. z[1] = sinq(x);
  516. fftwq_complex b{0, 0};
  517. fftwq_complex u;
  518. for (size_t k = m_complex_vector_size - 1; k >= 1; --k)
  519. {
  520. u[0] = b[0]*z[0] - b[1]*z[1];
  521. u[1] = b[0]*z[1] + b[1]*z[0];
  522. b[0] = m_gamma[k][0] + u[0];
  523. b[1] = m_gamma[k][1] + u[1];
  524. }
  525. s += 2*(b[0]*z[0] - b[1]*z[1]);
  526. return s;
  527. }
  528. __float128 prime(__float128 t) const
  529. {
  530. using std::sin;
  531. using std::cos;
  532. using boost::math::constants::two_pi;
  533. using std::exp;
  534. __float128 x = two_pi<__float128>()*(t - m_t0)/m_T;
  535. fftwq_complex z;
  536. z[0] = cosq(x);
  537. z[1] = sinq(x);
  538. fftwq_complex b{0, 0};
  539. // u = b*z
  540. fftwq_complex u;
  541. for (size_t k = m_complex_vector_size - 1; k >= 1; --k)
  542. {
  543. u[0] = b[0]*z[0] - b[1]*z[1];
  544. u[1] = b[0]*z[1] + b[1]*z[0];
  545. b[0] = k*m_gamma[k][0] + u[0];
  546. b[1] = k*m_gamma[k][1] + u[1];
  547. }
  548. // b*z = (b[0]*z[0] - b[1]*z[1]) + i(b[1]*z[0] + b[0]*z[1])
  549. return -2*two_pi<__float128>()*(b[1]*z[0] + b[0]*z[1])/m_T;
  550. }
  551. __float128 double_prime(__float128 t) const
  552. {
  553. using std::sin;
  554. using std::cos;
  555. using boost::math::constants::two_pi;
  556. using std::exp;
  557. __float128 x = two_pi<__float128>()*(t - m_t0)/m_T;
  558. fftwq_complex z;
  559. z[0] = cosq(x);
  560. z[1] = sinq(x);
  561. fftwq_complex b{0, 0};
  562. // u = b*z
  563. fftwq_complex u;
  564. for (size_t k = m_complex_vector_size - 1; k >= 1; --k)
  565. {
  566. u[0] = b[0]*z[0] - b[1]*z[1];
  567. u[1] = b[0]*z[1] + b[1]*z[0];
  568. b[0] = k*k*m_gamma[k][0] + u[0];
  569. b[1] = k*k*m_gamma[k][1] + u[1];
  570. }
  571. // b*z = (b[0]*z[0] - b[1]*z[1]) + i(b[1]*z[0] + b[0]*z[1])
  572. return -2*two_pi<__float128>()*two_pi<__float128>()*(b[0]*z[0] - b[1]*z[1])/(m_T*m_T);
  573. }
  574. __float128 period() const
  575. {
  576. return m_T;
  577. }
  578. __float128 integrate() const
  579. {
  580. return m_T*m_gamma[0][0];
  581. }
  582. __float128 squared_l2() const
  583. {
  584. __float128 s = 0;
  585. for (size_t i = m_complex_vector_size - 1; i >= 1; --i)
  586. {
  587. s += (m_gamma[i][0]*m_gamma[i][0] + m_gamma[i][1]*m_gamma[i][1]);
  588. }
  589. s *= 2;
  590. s += m_gamma[0][0]*m_gamma[0][0];
  591. return s*m_T;
  592. }
  593. ~cardinal_trigonometric_detail()
  594. {
  595. if (m_gamma)
  596. {
  597. fftwq_free(m_gamma);
  598. m_gamma = nullptr;
  599. }
  600. }
  601. private:
  602. __float128 m_t0;
  603. __float128 m_h;
  604. __float128 m_T;
  605. fftwq_complex* m_gamma;
  606. size_t m_complex_vector_size;
  607. };
  608. #endif
  609. }}}}
  610. #endif