Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

320 рядки
8.4 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 __REMEZ_SOLVER_H__
  11. #define __REMEZ_SOLVER_H__
  12. template<int ORDER> class RemezSolver
  13. {
  14. public:
  15. typedef real RealFunc(real const &x);
  16. RemezSolver()
  17. {
  18. }
  19. void Run(real a, real b, RealFunc *func, RealFunc *error, int steps)
  20. {
  21. m_func = func;
  22. m_error = error;
  23. m_k1 = (b + a) >> 1;
  24. m_k2 = (b - a) >> 1;
  25. m_invk2 = re(m_k2);
  26. m_invk1 = -m_k1 * m_invk2;
  27. Init();
  28. PrintPoly();
  29. for (int n = 0; n < steps; n++)
  30. {
  31. FindError();
  32. Step();
  33. PrintPoly();
  34. FindZeroes();
  35. }
  36. FindError();
  37. Step();
  38. PrintPoly();
  39. }
  40. real ChebyEval(real const &x)
  41. {
  42. real ret = 0.0, xn = 1.0;
  43. for (int i = 0; i < ORDER + 1; i++)
  44. {
  45. real mul = 0;
  46. for (int j = 0; j < ORDER + 1; j++)
  47. mul += coeff[j] * (real)Cheby(j, i);
  48. ret += mul * xn;
  49. xn *= x;
  50. }
  51. return ret;
  52. }
  53. void Init()
  54. {
  55. /* Pick up x_i where error will be 0 and compute f(x_i) */
  56. real fxn[ORDER + 1];
  57. for (int i = 0; i < ORDER + 1; i++)
  58. {
  59. zeroes[i] = (real)(2 * i - ORDER) / (real)(ORDER + 1);
  60. fxn[i] = Value(zeroes[i]);
  61. }
  62. /* We build a matrix of Chebishev evaluations: row i contains the
  63. * evaluations of x_i for polynomial order n = 0, 1, ... */
  64. Matrix<ORDER + 1> mat;
  65. for (int i = 0; i < ORDER + 1; i++)
  66. {
  67. /* Compute the powers of x_i */
  68. real powers[ORDER + 1];
  69. powers[0] = 1.0;
  70. for (int n = 1; n < ORDER + 1; n++)
  71. powers[n] = powers[n - 1] * zeroes[i];
  72. /* Compute the Chebishev evaluations at x_i */
  73. for (int n = 0; n < ORDER + 1; n++)
  74. {
  75. real sum = 0.0;
  76. for (int k = 0; k < ORDER + 1; k++)
  77. sum += (real)Cheby(n, k) * powers[k];
  78. mat.m[i][n] = sum;
  79. }
  80. }
  81. /* Solve the system */
  82. mat = mat.inv();
  83. /* Compute interpolation coefficients */
  84. for (int j = 0; j < ORDER + 1; j++)
  85. {
  86. coeff[j] = 0;
  87. for (int i = 0; i < ORDER + 1; i++)
  88. coeff[j] += mat.m[j][i] * fxn[i];
  89. }
  90. }
  91. void FindZeroes()
  92. {
  93. for (int i = 0; i < ORDER + 1; i++)
  94. {
  95. real a = control[i];
  96. real ea = ChebyEval(a) - Value(a);
  97. real b = control[i + 1];
  98. real eb = ChebyEval(b) - Value(b);
  99. while (fabs(a - b) > (real)1e-140)
  100. {
  101. real c = (a + b) * (real)0.5;
  102. real ec = ChebyEval(c) - Value(c);
  103. if ((ea < (real)0 && ec < (real)0)
  104. || (ea > (real)0 && ec > (real)0))
  105. {
  106. a = c;
  107. ea = ec;
  108. }
  109. else
  110. {
  111. b = c;
  112. eb = ec;
  113. }
  114. }
  115. zeroes[i] = a;
  116. }
  117. }
  118. void FindError()
  119. {
  120. real final = 0;
  121. for (int i = 0; i < ORDER + 2; i++)
  122. {
  123. real a = -1, b = 1;
  124. if (i > 0)
  125. a = zeroes[i - 1];
  126. if (i < ORDER + 1)
  127. b = zeroes[i];
  128. printf("Error for [%g..%g]: ", (double)a, (double)b);
  129. for (;;)
  130. {
  131. real c = a, delta = (b - a) / (real)10.0;
  132. real maxerror = 0;
  133. int best = -1;
  134. for (int k = 0; k <= 10; k++)
  135. {
  136. real e = fabs(ChebyEval(c) - Value(c));
  137. if (e > maxerror)
  138. {
  139. maxerror = e;
  140. best = k;
  141. }
  142. c += delta;
  143. }
  144. if (best == 0)
  145. best = 1;
  146. if (best == 10)
  147. best = 9;
  148. b = a + (real)(best + 1) * delta;
  149. a = a + (real)(best - 1) * delta;
  150. if (b - a < (real)1e-15)
  151. {
  152. if (maxerror > final)
  153. final = maxerror;
  154. control[i] = (a + b) * (real)0.5;
  155. printf("%g (at %g)\n", (double)maxerror, (double)control[i]);
  156. break;
  157. }
  158. }
  159. }
  160. printf("Final error: ");
  161. final.print(40);
  162. }
  163. void Step()
  164. {
  165. /* Pick up x_i where error will be 0 and compute f(x_i) */
  166. real fxn[ORDER + 2];
  167. for (int i = 0; i < ORDER + 2; i++)
  168. fxn[i] = Value(control[i]);
  169. /* We build a matrix of Chebishev evaluations: row i contains the
  170. * evaluations of x_i for polynomial order n = 0, 1, ... */
  171. Matrix<ORDER + 2> mat;
  172. for (int i = 0; i < ORDER + 2; i++)
  173. {
  174. /* Compute the powers of x_i */
  175. real powers[ORDER + 1];
  176. powers[0] = 1.0;
  177. for (int n = 1; n < ORDER + 1; n++)
  178. powers[n] = powers[n - 1] * control[i];
  179. /* Compute the Chebishev evaluations at x_i */
  180. for (int n = 0; n < ORDER + 1; n++)
  181. {
  182. real sum = 0.0;
  183. for (int k = 0; k < ORDER + 1; k++)
  184. sum += (real)Cheby(n, k) * powers[k];
  185. mat.m[i][n] = sum;
  186. }
  187. if (i & 1)
  188. mat.m[i][ORDER + 1] = fabs(Error(control[i]));
  189. else
  190. mat.m[i][ORDER + 1] = -fabs(Error(control[i]));
  191. }
  192. /* Solve the system */
  193. mat = mat.inv();
  194. /* Compute interpolation coefficients */
  195. for (int j = 0; j < ORDER + 1; j++)
  196. {
  197. coeff[j] = 0;
  198. for (int i = 0; i < ORDER + 2; i++)
  199. coeff[j] += mat.m[j][i] * fxn[i];
  200. }
  201. /* Compute the error */
  202. real error = 0;
  203. for (int i = 0; i < ORDER + 2; i++)
  204. error += mat.m[ORDER + 1][i] * fxn[i];
  205. }
  206. int Cheby(int n, int k)
  207. {
  208. if (k > n || k < 0)
  209. return 0;
  210. if (n <= 1)
  211. return (n ^ k ^ 1) & 1;
  212. return 2 * Cheby(n - 1, k - 1) - Cheby(n - 2, k);
  213. }
  214. int Comb(int n, int k)
  215. {
  216. if (k == 0 || k == n)
  217. return 1;
  218. return Comb(n - 1, k - 1) + Comb(n - 1, k);
  219. }
  220. void PrintPoly()
  221. {
  222. /* Transform Chebyshev polynomial weights into powers of X^i
  223. * in the [-1..1] range. */
  224. real bn[ORDER + 1];
  225. for (int i = 0; i < ORDER + 1; i++)
  226. {
  227. bn[i] = 0;
  228. for (int j = 0; j < ORDER + 1; j++)
  229. bn[i] += coeff[j] * (real)Cheby(j, i);
  230. }
  231. /* Transform a polynomial in the [-1..1] range into a polynomial
  232. * in the [a..b] range. */
  233. real k1p[ORDER + 1], k2p[ORDER + 1];
  234. real an[ORDER + 1];
  235. for (int i = 0; i < ORDER + 1; i++)
  236. {
  237. k1p[i] = i ? k1p[i - 1] * m_invk1 : real::R_1;
  238. k2p[i] = i ? k2p[i - 1] * m_invk2 : real::R_1;
  239. }
  240. for (int i = 0; i < ORDER + 1; i++)
  241. {
  242. an[i] = 0;
  243. for (int j = i; j < ORDER + 1; j++)
  244. an[i] += (real)Comb(j, i) * k1p[j - i] * bn[j];
  245. an[i] *= k2p[i];
  246. }
  247. for (int j = 0; j < ORDER + 1; j++)
  248. printf("%s%18.16gx^%i", j && (an[j] >= real::R_0) ? "+" : "", (double)an[j], j);
  249. printf("\n");
  250. }
  251. real Value(real const &x)
  252. {
  253. return m_func(x * m_k2 + m_k1);
  254. }
  255. real Error(real const &x)
  256. {
  257. return m_error(x * m_k2 + m_k1);
  258. }
  259. /* ORDER + 1 Chebyshev coefficients and 1 error value */
  260. real coeff[ORDER + 2];
  261. /* ORDER + 1 zeroes of the error function */
  262. real zeroes[ORDER + 1];
  263. /* ORDER + 2 control points */
  264. real control[ORDER + 2];
  265. private:
  266. RealFunc *m_func, *m_error;
  267. real m_k1, m_k2, m_invk1, m_invk2;
  268. };
  269. #endif /* __REMEZ_SOLVER_H__ */