fft_sines_table.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. // Use, modification and distribution are subject to the
  2. // Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt
  4. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. // Copyright Paul A. Bristow 2013.
  6. // Copyright Christopher Kormanyos 2012, 2013.
  7. // Copyright John Maddock 2013.
  8. // This file is written to be included from a Quickbook .qbk document.
  9. // It can be compiled by the C++ compiler, and run. Any output can
  10. // also be added here as comment or included or pasted in elsewhere.
  11. // Caution: this file contains Quickbook markup as well as code
  12. // and comments: don't change any of the special comment markups!
  13. #ifdef _MSC_VER
  14. # pragma warning (disable : 4996) // -D_SCL_SECURE_NO_WARNINGS.
  15. #endif
  16. //[fft_sines_table_example_1
  17. /*`[h5 Using Boost.Multiprecision to generate a high-precision array of sine coefficents for use with FFT.]
  18. The Boost.Multiprecision library can be used for computations requiring precision
  19. exceeding that of standard built-in types such as `float`, `double`
  20. and `long double`. For extended-precision calculations, Boost.Multiprecision
  21. supplies a template data type called `cpp_bin_float`. The number of decimal
  22. digits of precision is fixed at compile-time via a template parameter.
  23. One often needs to compute tables of numbers in mathematical software.
  24. To avoid the
  25. [@https://en.wikipedia.org/wiki/Rounding#Table-maker's_dilemma Table-maker's dilemma]
  26. it is necessary to use a higher precision type to compute the table values so that they have
  27. the nearest representable bit-pattern for the type, say `double`, of the table value.
  28. This example is a program `fft_since_table.cpp` that writes a header file `sines.hpp`
  29. containing an array of sine coefficients for use with a Fast Fourier Transform (FFT),
  30. that can be included by the FFT program.
  31. To use Boost.Multiprecision's high-precision floating-point types and constants, we need some includes:
  32. */
  33. #include <boost/math/constants/constants.hpp>
  34. // using boost::math::constants::pi;
  35. #include <boost/multiprecision/cpp_bin_float.hpp> // for
  36. // using boost::multiprecision::cpp_bin_float and
  37. // using boost::multiprecision::cpp_bin_float_50;
  38. // using boost::multiprecision::cpp_bin_float_quad;
  39. #include <boost/array.hpp> // or <array> for std::array
  40. #include <iostream>
  41. #include <limits>
  42. #include <vector>
  43. #include <algorithm>
  44. #include <iomanip>
  45. #include <iterator>
  46. #include <fstream>
  47. /*`First, this example defines a prolog text string which is a C++ comment with the program licence, copyright etc.
  48. (You would of course, tailor this to your needs, including *your* copyright claim).
  49. This will appear at the top of the written header file `sines.hpp`.
  50. */
  51. //] [fft_sines_table_example_1]
  52. static const char* prolog =
  53. {
  54. "// Use, modification and distribution are subject to the\n"
  55. "// Boost Software License, Version 1.0.\n"
  56. "// (See accompanying file LICENSE_1_0.txt\n"
  57. "// or copy at ""http://www.boost.org/LICENSE_1_0.txt)\n\n"
  58. "// Copyright A N Other, 2019.\n\n"
  59. };
  60. //[fft_sines_table_example_2
  61. using boost::multiprecision::cpp_bin_float_50;
  62. using boost::math::constants::pi;
  63. //] [fft_sines_table_example_2]
  64. // VS 2010 (wrongly) requires these at file scope, not local scope in `main`.
  65. // This program also requires `-std=c++11` option to compile using Clang and GCC.
  66. int main()
  67. {
  68. //[fft_sines_table_example_3
  69. /*`A fast Fourier transform (FFT), for example, may use a table of the values of
  70. sin(([pi]/2[super n]) in its implementation details. In order to maximize the precision in
  71. the FFT implementation, the precision of the tabulated trigonometric values
  72. should exceed that of the built-in floating-point type used in the FFT.
  73. The sample below computes a table of the values of sin([pi]/2[super n])
  74. in the range 1 <= n <= 31.
  75. This program makes use of, among other program elements, the data type
  76. `boost::multiprecision::cpp_bin_float_50`
  77. for a precision of 50 decimal digits from Boost.Multiprecision,
  78. the value of constant [pi] retrieved from Boost.Math,
  79. guaranteed to be initialized with the very last bit of precision for the type,
  80. here `cpp_bin_float_50`,
  81. and a C++11 lambda function combined with `std::for_each()`.
  82. */
  83. /*`define the number of values (32) in the array of sines.
  84. */
  85. std::size_t size = 32U;
  86. //cpp_bin_float_50 p = pi<cpp_bin_float_50>();
  87. cpp_bin_float_50 p = boost::math::constants::pi<cpp_bin_float_50>();
  88. std::vector <cpp_bin_float_50> sin_values (size);
  89. unsigned n = 1U;
  90. // Generate the sine values.
  91. std::for_each
  92. (
  93. sin_values.begin (),
  94. sin_values.end (),
  95. [&n](cpp_bin_float_50& y)
  96. {
  97. y = sin( pi<cpp_bin_float_50>() / pow(cpp_bin_float_50 (2), n));
  98. ++n;
  99. }
  100. );
  101. /*`Define the floating-point type for the generated file, either built-in
  102. `double, `float, or `long double`, or a user defined type like `cpp_bin_float_50`.
  103. */
  104. std::string fp_type = "double";
  105. std::cout << "Generating an `std::array` or `boost::array` for floating-point type: "
  106. << fp_type << ". " << std::endl;
  107. /*`By default, output would only show the standard 6 decimal digits,
  108. so set precision to show enough significant digits for the chosen floating-point type.
  109. For `cpp_bin_float_50` is 50. (50 decimal digits should be ample for most applications).
  110. */
  111. std::streamsize precision = std::numeric_limits<cpp_bin_float_50>::digits10;
  112. std::cout << "Sines table precision is " << precision << " decimal digits. " << std::endl;
  113. /*`Of course, one could also choose a lower precision for the table values, for example,
  114. `std::streamsize precision = std::numeric_limits<cpp_bin_float_quad>::max_digits10;`
  115. 128-bit 'quad' precision of 36 decimal digits would be sufficient
  116. for the most precise current `long double` implementations using 128-bit.
  117. In general, it should be a couple of decimal digits more (guard digits) than
  118. `std::numeric_limits<RealType>::max_digits10` for the target system floating-point type.
  119. (If the implementation does not provide `max_digits10`, the the Kahan formula
  120. `std::numeric_limits<RealType>::digits * 3010/10000 + 2` can be used instead).
  121. The compiler will read these values as decimal digits strings and
  122. use the nearest representation for the floating-point type.
  123. Now output all the sine table, to a file of your chosen name.
  124. */
  125. const char sines_name[] = "sines.hpp"; // Assuming in same directory as .exe
  126. std::ofstream fout(sines_name, std::ios_base::out); // Creates if no file exists,
  127. // & uses default overwrite/ ios::replace.
  128. if (fout.is_open() == false)
  129. { // failed to open OK!
  130. std::cout << "Open file " << sines_name << " failed!" << std::endl;
  131. return EXIT_FAILURE;
  132. }
  133. else
  134. { // Write prolog etc as a C++ comment.
  135. std::cout << "Open file " << sines_name << " for output OK." << std::endl;
  136. fout << prolog
  137. << "// Table of " << sin_values.size() << " values with "
  138. << precision << " decimal digits precision,\n"
  139. "// generated by program fft_sines_table.cpp.\n" << std::endl;
  140. fout << "#include <array> // std::array" << std::endl;
  141. // Write the table of sines as a C++ array.
  142. fout << "\nstatic const std::array<double, " << size << "> sines =\n"
  143. "{{\n"; // 2nd { needed for some old GCC compiler versions.
  144. fout.precision(precision);
  145. for (unsigned int i = 0U; ;)
  146. {
  147. fout << " " << sin_values[i];
  148. if (i == sin_values.size()-1)
  149. { // next is last value.
  150. fout << "\n}}; // array sines\n"; // 2nd } needed for some old GCC compiler versions.
  151. break;
  152. }
  153. else
  154. {
  155. fout << ",\n";
  156. i++;
  157. }
  158. } // for
  159. fout.close();
  160. std::cout << "Closed file " << sines_name << " for output." << std::endl;
  161. }
  162. //`The output file generated can be seen at [@../../example/sines.hpp]
  163. //] [/fft_sines_table_example_3]
  164. return EXIT_SUCCESS;
  165. } // int main()
  166. /*
  167. //[fft_sines_table_example_output
  168. The printed table is:
  169. 1
  170. 0.70710678118654752440084436210484903928483593768847
  171. 0.38268343236508977172845998403039886676134456248563
  172. 0.19509032201612826784828486847702224092769161775195
  173. 0.098017140329560601994195563888641845861136673167501
  174. 0.049067674327418014254954976942682658314745363025753
  175. 0.024541228522912288031734529459282925065466119239451
  176. 0.012271538285719926079408261951003212140372319591769
  177. 0.0061358846491544753596402345903725809170578863173913
  178. 0.003067956762965976270145365490919842518944610213452
  179. 0.0015339801862847656123036971502640790799548645752374
  180. 0.00076699031874270452693856835794857664314091945206328
  181. 0.00038349518757139558907246168118138126339502603496474
  182. 0.00019174759731070330743990956198900093346887403385916
  183. 9.5873799095977345870517210976476351187065612851145e-05
  184. 4.7936899603066884549003990494658872746866687685767e-05
  185. 2.3968449808418218729186577165021820094761474895673e-05
  186. 1.1984224905069706421521561596988984804731977538387e-05
  187. 5.9921124526424278428797118088908617299871778780951e-06
  188. 2.9960562263346607504548128083570598118251878683408e-06
  189. 1.4980281131690112288542788461553611206917585861527e-06
  190. 7.4901405658471572113049856673065563715595930217207e-07
  191. 3.7450702829238412390316917908463317739740476297248e-07
  192. 1.8725351414619534486882457659356361712045272098287e-07
  193. 9.3626757073098082799067286680885620193236507169473e-08
  194. 4.681337853654909269511551813854009695950362701667e-08
  195. 2.3406689268274552759505493419034844037886207223779e-08
  196. 1.1703344634137277181246213503238103798093456639976e-08
  197. 5.8516723170686386908097901008341396943900085051757e-09
  198. 2.9258361585343193579282304690689559020175857150074e-09
  199. 1.4629180792671596805295321618659637103742615227834e-09
  200. */
  201. //] [/fft_sines_table_example_output]
  202. //[fft_sines_table_example_check
  203. /*`
  204. The output can be copied as text and readily integrated into a given source
  205. code. Alternatively, the output can be written to a text or even be used
  206. within a self-written automatic code generator as this example.
  207. A computer algebra system can be used to verify the results obtained from
  208. Boost.Math and Boost.Multiprecision. For example, the __Mathematica
  209. computer algebra system can obtain a similar table with the command:
  210. Table[N[Sin[Pi / (2^n)], 50], {n, 1, 31, 1}]
  211. The __WolframAlpha computational knowledge engine can also be used to generate
  212. this table. The same command can be pasted into the compute box.
  213. */
  214. //] [/fft_sines_table_example_check]