You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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