| @@ -16,7 +16,7 @@ pi_CPPFLAGS = @LOL_CFLAGS@ @PIPI_CFLAGS@ | |||
| pi_LDFLAGS = $(top_builddir)/src/liblol.a @LOL_LIBS@ @PIPI_LIBS@ | |||
| pi_DEPENDENCIES = $(top_builddir)/src/liblol.a | |||
| remez_SOURCES = remez.cpp | |||
| remez_SOURCES = remez.cpp remez-matrix.h remez-solver.h | |||
| remez_CPPFLAGS = @LOL_CFLAGS@ @PIPI_CFLAGS@ | |||
| remez_LDFLAGS = $(top_builddir)/src/liblol.a @LOL_LIBS@ @PIPI_LIBS@ | |||
| remez_DEPENDENCIES = $(top_builddir)/src/liblol.a | |||
| @@ -0,0 +1,95 @@ | |||
| // | |||
| // Lol Engine - Sample math program: Chebyshev polynomials | |||
| // | |||
| // Copyright: (c) 2005-2011 Sam Hocevar <sam@hocevar.net> | |||
| // This program is free software; you can redistribute it and/or | |||
| // modify it under the terms of the Do What The Fuck You Want To | |||
| // Public License, Version 2, as published by Sam Hocevar. See | |||
| // http://sam.zoy.org/projects/COPYING.WTFPL for more details. | |||
| // | |||
| #if !defined __REMEZ_MATRIX_H__ | |||
| #define __REMEZ_MATRIX_H__ | |||
| template<int N> struct Matrix | |||
| { | |||
| inline Matrix() {} | |||
| Matrix(real x) | |||
| { | |||
| for (int j = 0; j < N; j++) | |||
| for (int i = 0; i < N; i++) | |||
| if (i == j) | |||
| m[i][j] = x; | |||
| else | |||
| m[i][j] = 0; | |||
| } | |||
| /* Naive matrix inversion */ | |||
| Matrix<N> inv() const | |||
| { | |||
| Matrix a = *this, b((real)1.0); | |||
| /* Inversion method: iterate through all columns and make sure | |||
| * all the terms are 1 on the diagonal and 0 everywhere else */ | |||
| for (int i = 0; i < N; i++) | |||
| { | |||
| /* If the expected coefficient is zero, add one of | |||
| * the other lines. The first we meet will do. */ | |||
| if ((double)a.m[i][i] == 0.0) | |||
| { | |||
| for (int j = i + 1; j < N; j++) | |||
| { | |||
| if ((double)a.m[i][j] == 0.0) | |||
| continue; | |||
| /* Add row j to row i */ | |||
| for (int n = 0; n < N; n++) | |||
| { | |||
| a.m[n][i] += a.m[n][j]; | |||
| b.m[n][i] += b.m[n][j]; | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| /* Now we know the diagonal term is non-zero. Get its inverse | |||
| * and use that to nullify all other terms in the column */ | |||
| real x = (real)1.0 / a.m[i][i]; | |||
| for (int j = 0; j < N; j++) | |||
| { | |||
| if (j == i) | |||
| continue; | |||
| real mul = x * a.m[i][j]; | |||
| for (int n = 0; n < N; n++) | |||
| { | |||
| a.m[n][j] -= mul * a.m[n][i]; | |||
| b.m[n][j] -= mul * b.m[n][i]; | |||
| } | |||
| } | |||
| /* Finally, ensure the diagonal term is 1 */ | |||
| for (int n = 0; n < N; n++) | |||
| { | |||
| a.m[n][i] *= x; | |||
| b.m[n][i] *= x; | |||
| } | |||
| } | |||
| return b; | |||
| } | |||
| void print() const | |||
| { | |||
| for (int j = 0; j < N; j++) | |||
| { | |||
| for (int i = 0; i < N; i++) | |||
| printf("%9.5f ", (double)m[j][i]); | |||
| printf("\n"); | |||
| } | |||
| } | |||
| real m[N][N]; | |||
| }; | |||
| #endif /* __REMEZ_MATRIX_H__ */ | |||
| @@ -0,0 +1,295 @@ | |||
| // | |||
| // Lol Engine - Sample math program: Chebyshev polynomials | |||
| // | |||
| // Copyright: (c) 2005-2011 Sam Hocevar <sam@hocevar.net> | |||
| // This program is free software; you can redistribute it and/or | |||
| // modify it under the terms of the Do What The Fuck You Want To | |||
| // Public License, Version 2, as published by Sam Hocevar. See | |||
| // http://sam.zoy.org/projects/COPYING.WTFPL for more details. | |||
| // | |||
| #if !defined __REMEZ_SOLVER_H__ | |||
| #define __REMEZ_SOLVER_H__ | |||
| template<int ORDER> class RemezSolver | |||
| { | |||
| public: | |||
| typedef real RealFunc(real const &x); | |||
| RemezSolver() | |||
| { | |||
| ChebyInit(); | |||
| } | |||
| void Run(RealFunc *func, RealFunc *error, int steps) | |||
| { | |||
| m_func = func; | |||
| m_error = error; | |||
| Init(); | |||
| ChebyCoeff(); | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| printf("%s%14.12gx^%i", j && (bn[j] >= real::R_0) ? "+" : "", (double)bn[j], j); | |||
| printf("\n"); | |||
| for (int n = 0; n < steps; n++) | |||
| { | |||
| FindError(); | |||
| Step(); | |||
| ChebyCoeff(); | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| printf("%s%14.12gx^%i", j && (bn[j] >= real::R_0) ? "+" : "", (double)bn[j], j); | |||
| printf("\n"); | |||
| FindZeroes(); | |||
| } | |||
| FindError(); | |||
| Step(); | |||
| ChebyCoeff(); | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| printf("%s%14.12gx^%i", j && (bn[j] >= real::R_0) ? "+" : "", (double)bn[j], j); | |||
| printf("\n"); | |||
| } | |||
| /* Fill the Chebyshev tables */ | |||
| void ChebyInit() | |||
| { | |||
| memset(cheby, 0, sizeof(cheby)); | |||
| cheby[0][0] = 1; | |||
| cheby[1][1] = 1; | |||
| for (int i = 2; i < ORDER + 1; i++) | |||
| { | |||
| cheby[i][0] = -cheby[i - 2][0]; | |||
| for (int j = 1; j < ORDER + 1; j++) | |||
| cheby[i][j] = 2 * cheby[i - 1][j - 1] - cheby[i - 2][j]; | |||
| } | |||
| } | |||
| void ChebyCoeff() | |||
| { | |||
| for (int i = 0; i < ORDER + 1; i++) | |||
| { | |||
| bn[i] = 0; | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| if (cheby[j][i]) | |||
| bn[i] += coeff[j] * (real)cheby[j][i]; | |||
| } | |||
| } | |||
| real ChebyEval(real const &x) | |||
| { | |||
| real ret = 0.0, xn = 1.0; | |||
| for (int i = 0; i < ORDER + 1; i++) | |||
| { | |||
| real mul = 0; | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| if (cheby[j][i]) | |||
| mul += coeff[j] * (real)cheby[j][i]; | |||
| ret += mul * xn; | |||
| xn *= x; | |||
| } | |||
| return ret; | |||
| } | |||
| void Init() | |||
| { | |||
| /* Pick up x_i where error will be 0 and compute f(x_i) */ | |||
| real fxn[ORDER + 1]; | |||
| for (int i = 0; i < ORDER + 1; i++) | |||
| { | |||
| zeroes[i] = (real)(2 * i - ORDER) / (real)(ORDER + 1); | |||
| fxn[i] = m_func(zeroes[i]); | |||
| } | |||
| /* We build a matrix of Chebishev evaluations: row i contains the | |||
| * evaluations of x_i for polynomial order n = 0, 1, ... */ | |||
| Matrix<ORDER + 1> mat; | |||
| for (int i = 0; i < ORDER + 1; i++) | |||
| { | |||
| /* Compute the powers of x_i */ | |||
| real powers[ORDER + 1]; | |||
| powers[0] = 1.0; | |||
| for (int n = 1; n < ORDER + 1; n++) | |||
| powers[n] = powers[n - 1] * zeroes[i]; | |||
| /* Compute the Chebishev evaluations at x_i */ | |||
| for (int n = 0; n < ORDER + 1; n++) | |||
| { | |||
| real sum = 0.0; | |||
| for (int k = 0; k < ORDER + 1; k++) | |||
| if (cheby[n][k]) | |||
| sum += (real)cheby[n][k] * powers[k]; | |||
| mat.m[i][n] = sum; | |||
| } | |||
| } | |||
| /* Solve the system */ | |||
| mat = mat.inv(); | |||
| /* Compute interpolation coefficients */ | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| { | |||
| coeff[j] = 0; | |||
| for (int i = 0; i < ORDER + 1; i++) | |||
| coeff[j] += mat.m[j][i] * fxn[i]; | |||
| } | |||
| } | |||
| void FindZeroes() | |||
| { | |||
| for (int i = 0; i < ORDER + 1; i++) | |||
| { | |||
| real a = control[i]; | |||
| real ea = ChebyEval(a) - m_func(a); | |||
| real b = control[i + 1]; | |||
| real eb = ChebyEval(b) - m_func(b); | |||
| while (fabs(a - b) > (real)1e-140) | |||
| { | |||
| real c = (a + b) * (real)0.5; | |||
| real ec = ChebyEval(c) - m_func(c); | |||
| if ((ea < (real)0 && ec < (real)0) | |||
| || (ea > (real)0 && ec > (real)0)) | |||
| { | |||
| a = c; | |||
| ea = ec; | |||
| } | |||
| else | |||
| { | |||
| b = c; | |||
| eb = ec; | |||
| } | |||
| } | |||
| zeroes[i] = a; | |||
| } | |||
| } | |||
| void FindError() | |||
| { | |||
| real final = 0; | |||
| for (int i = 0; i < ORDER + 2; i++) | |||
| { | |||
| real a = -1, b = 1; | |||
| if (i > 0) | |||
| a = zeroes[i - 1]; | |||
| if (i < ORDER + 1) | |||
| b = zeroes[i]; | |||
| printf("Error for [%g..%g]: ", (double)a, (double)b); | |||
| for (;;) | |||
| { | |||
| real c = a, delta = (b - a) / (real)10.0; | |||
| real maxerror = 0; | |||
| int best = -1; | |||
| for (int k = 0; k <= 10; k++) | |||
| { | |||
| real e = fabs(ChebyEval(c) - m_func(c)); | |||
| if (e > maxerror) | |||
| { | |||
| maxerror = e; | |||
| best = k; | |||
| } | |||
| c += delta; | |||
| } | |||
| if (best == 0) | |||
| best = 1; | |||
| if (best == 10) | |||
| best = 9; | |||
| b = a + (real)(best + 1) * delta; | |||
| a = a + (real)(best - 1) * delta; | |||
| if (b - a < (real)1e-15) | |||
| { | |||
| if (maxerror > final) | |||
| final = maxerror; | |||
| control[i] = (a + b) * (real)0.5; | |||
| printf("%g (at %g)\n", (double)maxerror, (double)control[i]); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| printf("Final error: %g\n", (double)final); | |||
| } | |||
| void Step() | |||
| { | |||
| /* Pick up x_i where error will be 0 and compute f(x_i) */ | |||
| real fxn[ORDER + 2]; | |||
| for (int i = 0; i < ORDER + 2; i++) | |||
| fxn[i] = m_func(control[i]); | |||
| /* We build a matrix of Chebishev evaluations: row i contains the | |||
| * evaluations of x_i for polynomial order n = 0, 1, ... */ | |||
| Matrix<ORDER + 2> mat; | |||
| for (int i = 0; i < ORDER + 2; i++) | |||
| { | |||
| /* Compute the powers of x_i */ | |||
| real powers[ORDER + 1]; | |||
| powers[0] = 1.0; | |||
| for (int n = 1; n < ORDER + 1; n++) | |||
| powers[n] = powers[n - 1] * control[i]; | |||
| /* Compute the Chebishev evaluations at x_i */ | |||
| for (int n = 0; n < ORDER + 1; n++) | |||
| { | |||
| real sum = 0.0; | |||
| for (int k = 0; k < ORDER + 1; k++) | |||
| if (cheby[n][k]) | |||
| sum += (real)cheby[n][k] * powers[k]; | |||
| mat.m[i][n] = sum; | |||
| } | |||
| if (i & 1) | |||
| mat.m[i][ORDER + 1] = fabs(m_error(control[i])); | |||
| else | |||
| mat.m[i][ORDER + 1] = -fabs(m_error(control[i])); | |||
| } | |||
| /* Solve the system */ | |||
| mat = mat.inv(); | |||
| /* Compute interpolation coefficients */ | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| { | |||
| coeff[j] = 0; | |||
| for (int i = 0; i < ORDER + 2; i++) | |||
| coeff[j] += mat.m[j][i] * fxn[i]; | |||
| } | |||
| /* Compute the error */ | |||
| real error = 0; | |||
| for (int i = 0; i < ORDER + 2; i++) | |||
| error += mat.m[ORDER + 1][i] * fxn[i]; | |||
| } | |||
| int cheby[ORDER + 1][ORDER + 1]; | |||
| /* ORDER + 1 chebyshev coefficients and 1 error value */ | |||
| real coeff[ORDER + 2]; | |||
| /* ORDER + 1 zeroes of the error function */ | |||
| real zeroes[ORDER + 1]; | |||
| /* ORDER + 2 control points */ | |||
| real control[ORDER + 2]; | |||
| real bn[ORDER + 1]; | |||
| private: | |||
| RealFunc *m_func; | |||
| RealFunc *m_error; | |||
| }; | |||
| #endif /* __REMEZ_SOLVER_H__ */ | |||
| @@ -20,367 +20,25 @@ | |||
| using namespace lol; | |||
| using namespace std; | |||
| /* The order of the approximation we're looking for */ | |||
| static int const ORDER = 4; | |||
| #include "remez-matrix.h" | |||
| #include "remez-solver.h" | |||
| /* The function we want to approximate */ | |||
| static real myfun(real const &x) | |||
| { | |||
| return exp(x); | |||
| //if (!x) | |||
| // return real::R_PI_2; | |||
| //return sin(x * real::R_PI_2) / x; | |||
| } | |||
| static real myerror(real const &x) | |||
| { | |||
| return myfun(x); | |||
| //return real::R_1; | |||
| } | |||
| /* Naive matrix inversion */ | |||
| template<int N> struct Matrix | |||
| { | |||
| inline Matrix() {} | |||
| Matrix(real x) | |||
| { | |||
| for (int j = 0; j < N; j++) | |||
| for (int i = 0; i < N; i++) | |||
| if (i == j) | |||
| m[i][j] = x; | |||
| else | |||
| m[i][j] = 0; | |||
| } | |||
| Matrix<N> inv() const | |||
| { | |||
| Matrix a = *this, b((real)1.0); | |||
| /* Inversion method: iterate through all columns and make sure | |||
| * all the terms are 1 on the diagonal and 0 everywhere else */ | |||
| for (int i = 0; i < N; i++) | |||
| { | |||
| /* If the expected coefficient is zero, add one of | |||
| * the other lines. The first we meet will do. */ | |||
| if ((double)a.m[i][i] == 0.0) | |||
| { | |||
| for (int j = i + 1; j < N; j++) | |||
| { | |||
| if ((double)a.m[i][j] == 0.0) | |||
| continue; | |||
| /* Add row j to row i */ | |||
| for (int n = 0; n < N; n++) | |||
| { | |||
| a.m[n][i] += a.m[n][j]; | |||
| b.m[n][i] += b.m[n][j]; | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| /* Now we know the diagonal term is non-zero. Get its inverse | |||
| * and use that to nullify all other terms in the column */ | |||
| real x = (real)1.0 / a.m[i][i]; | |||
| for (int j = 0; j < N; j++) | |||
| { | |||
| if (j == i) | |||
| continue; | |||
| real mul = x * a.m[i][j]; | |||
| for (int n = 0; n < N; n++) | |||
| { | |||
| a.m[n][j] -= mul * a.m[n][i]; | |||
| b.m[n][j] -= mul * b.m[n][i]; | |||
| } | |||
| } | |||
| /* Finally, ensure the diagonal term is 1 */ | |||
| for (int n = 0; n < N; n++) | |||
| { | |||
| a.m[n][i] *= x; | |||
| b.m[n][i] *= x; | |||
| } | |||
| } | |||
| return b; | |||
| } | |||
| void print() const | |||
| { | |||
| for (int j = 0; j < N; j++) | |||
| { | |||
| for (int i = 0; i < N; i++) | |||
| printf("%9.5f ", (double)m[j][i]); | |||
| printf("\n"); | |||
| } | |||
| } | |||
| real m[N][N]; | |||
| }; | |||
| static int cheby[ORDER + 1][ORDER + 1]; | |||
| /* Fill the Chebyshev tables */ | |||
| static void cheby_init() | |||
| { | |||
| memset(cheby, 0, sizeof(cheby)); | |||
| cheby[0][0] = 1; | |||
| cheby[1][1] = 1; | |||
| for (int i = 2; i < ORDER + 1; i++) | |||
| { | |||
| cheby[i][0] = -cheby[i - 2][0]; | |||
| for (int j = 1; j < ORDER + 1; j++) | |||
| cheby[i][j] = 2 * cheby[i - 1][j - 1] - cheby[i - 2][j]; | |||
| } | |||
| } | |||
| static void cheby_coeff(real *coeff, real *bn) | |||
| { | |||
| for (int i = 0; i < ORDER + 1; i++) | |||
| { | |||
| bn[i] = 0; | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| if (cheby[j][i]) | |||
| bn[i] += coeff[j] * (real)cheby[j][i]; | |||
| } | |||
| } | |||
| static real cheby_eval(real *coeff, real const &x) | |||
| { | |||
| real ret = 0.0, xn = 1.0; | |||
| for (int i = 0; i < ORDER + 1; i++) | |||
| { | |||
| real mul = 0; | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| if (cheby[j][i]) | |||
| mul += coeff[j] * (real)cheby[j][i]; | |||
| ret += mul * xn; | |||
| xn *= x; | |||
| } | |||
| return ret; | |||
| } | |||
| static void remez_init(real *coeff, real *zeroes) | |||
| { | |||
| /* Pick up x_i where error will be 0 and compute f(x_i) */ | |||
| real fxn[ORDER + 1]; | |||
| for (int i = 0; i < ORDER + 1; i++) | |||
| { | |||
| zeroes[i] = (real)(2 * i - ORDER) / (real)(ORDER + 1); | |||
| fxn[i] = myfun(zeroes[i]); | |||
| } | |||
| /* We build a matrix of Chebishev evaluations: row i contains the | |||
| * evaluations of x_i for polynomial order n = 0, 1, ... */ | |||
| Matrix<ORDER + 1> mat; | |||
| for (int i = 0; i < ORDER + 1; i++) | |||
| { | |||
| /* Compute the powers of x_i */ | |||
| real powers[ORDER + 1]; | |||
| powers[0] = 1.0; | |||
| for (int n = 1; n < ORDER + 1; n++) | |||
| powers[n] = powers[n - 1] * zeroes[i]; | |||
| /* Compute the Chebishev evaluations at x_i */ | |||
| for (int n = 0; n < ORDER + 1; n++) | |||
| { | |||
| real sum = 0.0; | |||
| for (int k = 0; k < ORDER + 1; k++) | |||
| if (cheby[n][k]) | |||
| sum += (real)cheby[n][k] * powers[k]; | |||
| mat.m[i][n] = sum; | |||
| } | |||
| } | |||
| /* Solve the system */ | |||
| mat = mat.inv(); | |||
| /* Compute interpolation coefficients */ | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| { | |||
| coeff[j] = 0; | |||
| for (int i = 0; i < ORDER + 1; i++) | |||
| coeff[j] += mat.m[j][i] * fxn[i]; | |||
| } | |||
| } | |||
| static void remez_findzeroes(real *coeff, real *zeroes, real *control) | |||
| { | |||
| for (int i = 0; i < ORDER + 1; i++) | |||
| { | |||
| real a = control[i]; | |||
| real ea = cheby_eval(coeff, a) - myfun(a); | |||
| real b = control[i + 1]; | |||
| real eb = cheby_eval(coeff, b) - myfun(b); | |||
| while (fabs(a - b) > (real)1e-140) | |||
| { | |||
| real c = (a + b) * (real)0.5; | |||
| real ec = cheby_eval(coeff, c) - myfun(c); | |||
| if ((ea < (real)0 && ec < (real)0) | |||
| || (ea > (real)0 && ec > (real)0)) | |||
| { | |||
| a = c; | |||
| ea = ec; | |||
| } | |||
| else | |||
| { | |||
| b = c; | |||
| eb = ec; | |||
| } | |||
| } | |||
| zeroes[i] = a; | |||
| } | |||
| } | |||
| static void remez_finderror(real *coeff, real *zeroes, real *control) | |||
| { | |||
| real final = 0; | |||
| for (int i = 0; i < ORDER + 2; i++) | |||
| { | |||
| real a = -1, b = 1; | |||
| if (i > 0) | |||
| a = zeroes[i - 1]; | |||
| if (i < ORDER + 1) | |||
| b = zeroes[i]; | |||
| printf("Error for [%g..%g]: ", (double)a, (double)b); | |||
| for (;;) | |||
| { | |||
| real c = a, delta = (b - a) / (real)10.0; | |||
| real maxerror = 0; | |||
| int best = -1; | |||
| for (int k = 0; k <= 10; k++) | |||
| { | |||
| real e = fabs(cheby_eval(coeff, c) - myfun(c)); | |||
| if (e > maxerror) | |||
| { | |||
| maxerror = e; | |||
| best = k; | |||
| } | |||
| c += delta; | |||
| } | |||
| if (best == 0) | |||
| best = 1; | |||
| if (best == 10) | |||
| best = 9; | |||
| b = a + (real)(best + 1) * delta; | |||
| a = a + (real)(best - 1) * delta; | |||
| if (b - a < (real)1e-15) | |||
| { | |||
| if (maxerror > final) | |||
| final = maxerror; | |||
| control[i] = (a + b) * (real)0.5; | |||
| printf("%g (at %g)\n", (double)maxerror, (double)control[i]); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| printf("Final error: %g\n", (double)final); | |||
| } | |||
| static void remez_step(real *coeff, real *control) | |||
| { | |||
| /* Pick up x_i where error will be 0 and compute f(x_i) */ | |||
| real fxn[ORDER + 2]; | |||
| for (int i = 0; i < ORDER + 2; i++) | |||
| fxn[i] = myfun(control[i]); | |||
| /* We build a matrix of Chebishev evaluations: row i contains the | |||
| * evaluations of x_i for polynomial order n = 0, 1, ... */ | |||
| Matrix<ORDER + 2> mat; | |||
| for (int i = 0; i < ORDER + 2; i++) | |||
| { | |||
| /* Compute the powers of x_i */ | |||
| real powers[ORDER + 1]; | |||
| powers[0] = 1.0; | |||
| for (int n = 1; n < ORDER + 1; n++) | |||
| powers[n] = powers[n - 1] * control[i]; | |||
| /* Compute the Chebishev evaluations at x_i */ | |||
| for (int n = 0; n < ORDER + 1; n++) | |||
| { | |||
| real sum = 0.0; | |||
| for (int k = 0; k < ORDER + 1; k++) | |||
| if (cheby[n][k]) | |||
| sum += (real)cheby[n][k] * powers[k]; | |||
| mat.m[i][n] = sum; | |||
| } | |||
| if (i & 1) | |||
| mat.m[i][ORDER + 1] = fabs(myerror(control[i])); | |||
| else | |||
| mat.m[i][ORDER + 1] = -fabs(myerror(control[i])); | |||
| } | |||
| /* Solve the system */ | |||
| mat = mat.inv(); | |||
| /* Compute interpolation coefficients */ | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| { | |||
| coeff[j] = 0; | |||
| for (int i = 0; i < ORDER + 2; i++) | |||
| coeff[j] += mat.m[j][i] * fxn[i]; | |||
| } | |||
| /* Compute the error */ | |||
| real error = 0; | |||
| for (int i = 0; i < ORDER + 2; i++) | |||
| error += mat.m[ORDER + 1][i] * fxn[i]; | |||
| } | |||
| int main(int argc, char **argv) | |||
| { | |||
| cheby_init(); | |||
| /* ORDER + 1 chebyshev coefficients and 1 error value */ | |||
| real coeff[ORDER + 2]; | |||
| /* ORDER + 1 zeroes of the error function */ | |||
| real zeroes[ORDER + 1]; | |||
| /* ORDER + 2 control points */ | |||
| real control[ORDER + 2]; | |||
| real bn[ORDER + 1]; | |||
| remez_init(coeff, zeroes); | |||
| cheby_coeff(coeff, bn); | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| printf("%s%12.10gx^%i", j ? "+" : "", (double)bn[j], j); | |||
| printf("\n"); | |||
| for (int n = 0; n < 200; n++) | |||
| { | |||
| remez_finderror(coeff, zeroes, control); | |||
| remez_step(coeff, control); | |||
| cheby_coeff(coeff, bn); | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| printf("%s%12.10gx^%i", j ? "+" : "", (double)bn[j], j); | |||
| printf("\n"); | |||
| remez_findzeroes(coeff, zeroes, control); | |||
| } | |||
| remez_finderror(coeff, zeroes, control); | |||
| remez_step(coeff, control); | |||
| RemezSolver<4> solver; | |||
| cheby_coeff(coeff, bn); | |||
| for (int j = 0; j < ORDER + 1; j++) | |||
| printf("%s%12.10gx^%i", j ? "+" : "", (double)bn[j], j); | |||
| printf("\n"); | |||
| solver.Run(myfun, myerror, 10); | |||
| return EXIT_SUCCESS; | |||
| } | |||