// // 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 HAVE_CONFIG_H # include "config.h" #endif #include <cstring> #include "core.h" using namespace lol; /* The order of the approximation we're looking for */ static int const ORDER = 3; /* The function we want to approximate */ double myfun(double x) { return exp(x); } real myfun(real const &x) { return exp(x); } /* Naive matrix inversion */ template<int N> class Matrix { public: 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 zero except on the diagonal where it is one */ 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 = fres(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 make_table() { 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]; } } int main(int argc, char **argv) { make_table(); /* We start with ORDER+1 points and their images through myfun() */ real xn[ORDER + 1]; real fxn[ORDER + 1]; for (int i = 0; i < ORDER + 1; i++) { //xn[i] = real(2 * i - ORDER) / real(ORDER + 1); xn[i] = real(2 * i - ORDER + 1) / real(ORDER - 1); fxn[i] = myfun(xn[i]); } /* We build a matrix of Chebishev evaluations: one row per point * in our array, and column i is the evaluation of the ith order * polynomial. */ Matrix<ORDER + 1> mat; for (int j = 0; j < ORDER + 1; j++) { /* Compute the powers of x_j */ real powers[ORDER + 1]; powers[0] = 1.0; for (int i = 1; i < ORDER + 1; i++) powers[i] = powers[i - 1] * xn[j]; /* Compute the Chebishev evaluations at x_j */ for (int i = 0; i < ORDER + 1; i++) { real sum = 0.0; for (int k = 0; k < ORDER + 1; k++) if (cheby[i][k]) sum += real(cheby[i][k]) * powers[k]; mat.m[j][i] = sum; } } /* Invert the matrix and build interpolation coefficients */ mat = mat.inv(); real an[ORDER + 1]; for (int j = 0; j < ORDER + 1; j++) { an[j] = 0; for (int i = 0; i < ORDER + 1; i++) an[j] += mat.m[j][i] * fxn[i]; an[j].print(10); } return EXIT_SUCCESS; }