186 Zeilen
4.6 KiB

  1. //
  2. // Lol Engine - Sample math program: Chebyshev polynomials
  3. //
  4. // Copyright: (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://sam.zoy.org/projects/COPYING.WTFPL for more details.
  9. //
  10. #if defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include <cstring>
  14. #include "core.h"
  15. using namespace lol;
  16. /* The order of the approximation we're looking for */
  17. static int const ORDER = 3;
  18. /* The function we want to approximate */
  19. double myfun(double x)
  20. {
  21. return exp(x);
  22. }
  23. real myfun(real const &x)
  24. {
  25. return exp(x);
  26. }
  27. /* Naive matrix inversion */
  28. template<int N> class Matrix
  29. {
  30. public:
  31. inline Matrix() {}
  32. Matrix(real x)
  33. {
  34. for (int j = 0; j < N; j++)
  35. for (int i = 0; i < N; i++)
  36. if (i == j)
  37. m[i][j] = x;
  38. else
  39. m[i][j] = 0;
  40. }
  41. Matrix<N> inv() const
  42. {
  43. Matrix a = *this, b(real(1.0));
  44. /* Inversion method: iterate through all columns and make sure
  45. * all the terms are zero except on the diagonal where it is one */
  46. for (int i = 0; i < N; i++)
  47. {
  48. /* If the expected coefficient is zero, add one of
  49. * the other lines. The first we meet will do. */
  50. if ((double)a.m[i][i] == 0.0)
  51. {
  52. for (int j = i + 1; j < N; j++)
  53. {
  54. if ((double)a.m[i][j] == 0.0)
  55. continue;
  56. /* Add row j to row i */
  57. for (int n = 0; n < N; n++)
  58. {
  59. a.m[n][i] += a.m[n][j];
  60. b.m[n][i] += b.m[n][j];
  61. }
  62. break;
  63. }
  64. }
  65. /* Now we know the diagonal term is non-zero. Get its inverse
  66. * and use that to nullify all other terms in the column */
  67. real x = fres(a.m[i][i]);
  68. for (int j = 0; j < N; j++)
  69. {
  70. if (j == i)
  71. continue;
  72. real mul = x * a.m[i][j];
  73. for (int n = 0; n < N; n++)
  74. {
  75. a.m[n][j] -= mul * a.m[n][i];
  76. b.m[n][j] -= mul * b.m[n][i];
  77. }
  78. }
  79. /* Finally, ensure the diagonal term is 1 */
  80. for (int n = 0; n < N; n++)
  81. {
  82. a.m[n][i] *= x;
  83. b.m[n][i] *= x;
  84. }
  85. }
  86. return b;
  87. }
  88. void print() const
  89. {
  90. for (int j = 0; j < N; j++)
  91. {
  92. for (int i = 0; i < N; i++)
  93. printf("%9.5f ", (double)m[j][i]);
  94. printf("\n");
  95. }
  96. }
  97. real m[N][N];
  98. };
  99. static int cheby[ORDER + 1][ORDER + 1];
  100. /* Fill the Chebyshev tables */
  101. static void make_table()
  102. {
  103. memset(cheby, 0, sizeof(cheby));
  104. cheby[0][0] = 1;
  105. cheby[1][1] = 1;
  106. for (int i = 2; i < ORDER + 1; i++)
  107. {
  108. cheby[i][0] = -cheby[i - 2][0];
  109. for (int j = 1; j < ORDER + 1; j++)
  110. cheby[i][j] = 2 * cheby[i - 1][j - 1] - cheby[i - 2][j];
  111. }
  112. }
  113. int main(int argc, char **argv)
  114. {
  115. make_table();
  116. /* We start with ORDER+1 points and their images through myfun() */
  117. real xn[ORDER + 1];
  118. real fxn[ORDER + 1];
  119. for (int i = 0; i < ORDER + 1; i++)
  120. {
  121. //xn[i] = real(2 * i - ORDER) / real(ORDER + 1);
  122. xn[i] = real(2 * i - ORDER + 1) / real(ORDER - 1);
  123. fxn[i] = myfun(xn[i]);
  124. }
  125. /* We build a matrix of Chebishev evaluations: one row per point
  126. * in our array, and column i is the evaluation of the ith order
  127. * polynomial. */
  128. Matrix<ORDER + 1> mat;
  129. for (int j = 0; j < ORDER + 1; j++)
  130. {
  131. /* Compute the powers of x_j */
  132. real powers[ORDER + 1];
  133. powers[0] = 1.0;
  134. for (int i = 1; i < ORDER + 1; i++)
  135. powers[i] = powers[i - 1] * xn[j];
  136. /* Compute the Chebishev evaluations at x_j */
  137. for (int i = 0; i < ORDER + 1; i++)
  138. {
  139. real sum = 0.0;
  140. for (int k = 0; k < ORDER + 1; k++)
  141. if (cheby[i][k])
  142. sum += real(cheby[i][k]) * powers[k];
  143. mat.m[j][i] = sum;
  144. }
  145. }
  146. /* Invert the matrix and build interpolation coefficients */
  147. mat = mat.inv();
  148. real an[ORDER + 1];
  149. for (int j = 0; j < ORDER + 1; j++)
  150. {
  151. an[j] = 0;
  152. for (int i = 0; i < ORDER + 1; i++)
  153. an[j] += mat.m[j][i] * fxn[i];
  154. an[j].print(10);
  155. }
  156. return EXIT_SUCCESS;
  157. }