|
@@ -1,26 +1,34 @@ |
|
|
// |
|
|
// |
|
|
// Lol Engine - Sample math program: Chebyshev polynomials |
|
|
|
|
|
|
|
|
// Lol Engine |
|
|
// |
|
|
// |
|
|
// Copyright: (c) 2005-2011 Sam Hocevar <sam@hocevar.net> |
|
|
|
|
|
|
|
|
// Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net> |
|
|
// This program is free software; you can redistribute it and/or |
|
|
// 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 |
|
|
// modify it under the terms of the Do What The Fuck You Want To |
|
|
// Public License, Version 2, as published by Sam Hocevar. See |
|
|
// Public License, Version 2, as published by Sam Hocevar. See |
|
|
// http://sam.zoy.org/projects/COPYING.WTFPL for more details. |
|
|
// http://sam.zoy.org/projects/COPYING.WTFPL for more details. |
|
|
// |
|
|
// |
|
|
|
|
|
|
|
|
#if !defined __REMEZ_SOLVER_H__ |
|
|
|
|
|
#define __REMEZ_SOLVER_H__ |
|
|
|
|
|
|
|
|
// |
|
|
|
|
|
// The Remez class |
|
|
|
|
|
// --------------- |
|
|
|
|
|
// |
|
|
|
|
|
|
|
|
|
|
|
#if !defined __LOL_MATH_REMEZ_H__ |
|
|
|
|
|
#define __LOL_MATH_REMEZ_H__ |
|
|
|
|
|
|
|
|
template<int ORDER> class RemezSolver |
|
|
|
|
|
|
|
|
namespace lol |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
template<int ORDER, typename T> class RemezSolver |
|
|
{ |
|
|
{ |
|
|
public: |
|
|
public: |
|
|
typedef real RealFunc(real const &x); |
|
|
|
|
|
|
|
|
typedef T RealFunc(T const &x); |
|
|
|
|
|
|
|
|
RemezSolver() |
|
|
RemezSolver() |
|
|
{ |
|
|
{ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Run(real a, real b, RealFunc *func, RealFunc *weight, int steps) |
|
|
|
|
|
|
|
|
void Run(T a, T b, RealFunc *func, RealFunc *weight, int steps) |
|
|
{ |
|
|
{ |
|
|
m_func = func; |
|
|
m_func = func; |
|
|
m_weight = weight; |
|
|
m_weight = weight; |
|
@@ -49,15 +57,15 @@ public: |
|
|
PrintPoly(); |
|
|
PrintPoly(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
real ChebyEval(real const &x) |
|
|
|
|
|
|
|
|
T ChebyEval(T const &x) |
|
|
{ |
|
|
{ |
|
|
real ret = 0.0, xn = 1.0; |
|
|
|
|
|
|
|
|
T ret = 0.0, xn = 1.0; |
|
|
|
|
|
|
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
{ |
|
|
{ |
|
|
real mul = 0; |
|
|
|
|
|
|
|
|
T mul = 0; |
|
|
for (int j = 0; j < ORDER + 1; j++) |
|
|
for (int j = 0; j < ORDER + 1; j++) |
|
|
mul += coeff[j] * (real)Cheby(j, i); |
|
|
|
|
|
|
|
|
mul += coeff[j] * (T)Cheby(j, i); |
|
|
ret += mul * xn; |
|
|
ret += mul * xn; |
|
|
xn *= x; |
|
|
xn *= x; |
|
|
} |
|
|
} |
|
@@ -68,20 +76,20 @@ public: |
|
|
void Init() |
|
|
void Init() |
|
|
{ |
|
|
{ |
|
|
/* Pick up x_i where error will be 0 and compute f(x_i) */ |
|
|
/* Pick up x_i where error will be 0 and compute f(x_i) */ |
|
|
real fxn[ORDER + 1]; |
|
|
|
|
|
|
|
|
T fxn[ORDER + 1]; |
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
{ |
|
|
{ |
|
|
zeroes[i] = (real)(2 * i - ORDER) / (real)(ORDER + 1); |
|
|
|
|
|
|
|
|
zeroes[i] = (T)(2 * i - ORDER) / (T)(ORDER + 1); |
|
|
fxn[i] = Value(zeroes[i]); |
|
|
fxn[i] = Value(zeroes[i]); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* We build a matrix of Chebishev evaluations: row i contains the |
|
|
/* We build a matrix of Chebishev evaluations: row i contains the |
|
|
* evaluations of x_i for polynomial order n = 0, 1, ... */ |
|
|
* evaluations of x_i for polynomial order n = 0, 1, ... */ |
|
|
Matrix<ORDER + 1> mat; |
|
|
|
|
|
|
|
|
lol::Mat<ORDER + 1, T> mat; |
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
{ |
|
|
{ |
|
|
/* Compute the powers of x_i */ |
|
|
/* Compute the powers of x_i */ |
|
|
real powers[ORDER + 1]; |
|
|
|
|
|
|
|
|
T powers[ORDER + 1]; |
|
|
powers[0] = 1.0; |
|
|
powers[0] = 1.0; |
|
|
for (int n = 1; n < ORDER + 1; n++) |
|
|
for (int n = 1; n < ORDER + 1; n++) |
|
|
powers[n] = powers[n - 1] * zeroes[i]; |
|
|
powers[n] = powers[n - 1] * zeroes[i]; |
|
@@ -89,9 +97,9 @@ public: |
|
|
/* Compute the Chebishev evaluations at x_i */ |
|
|
/* Compute the Chebishev evaluations at x_i */ |
|
|
for (int n = 0; n < ORDER + 1; n++) |
|
|
for (int n = 0; n < ORDER + 1; n++) |
|
|
{ |
|
|
{ |
|
|
real sum = 0.0; |
|
|
|
|
|
|
|
|
T sum = 0.0; |
|
|
for (int k = 0; k < ORDER + 1; k++) |
|
|
for (int k = 0; k < ORDER + 1; k++) |
|
|
sum += (real)Cheby(n, k) * powers[k]; |
|
|
|
|
|
|
|
|
sum += (T)Cheby(n, k) * powers[k]; |
|
|
mat.m[i][n] = sum; |
|
|
mat.m[i][n] = sum; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@@ -115,21 +123,22 @@ public: |
|
|
* place as the absolute error! */ |
|
|
* place as the absolute error! */ |
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
{ |
|
|
{ |
|
|
struct { real value, error; } left, right, mid; |
|
|
|
|
|
|
|
|
struct { T value, error; } left, right, mid; |
|
|
|
|
|
|
|
|
left.value = control[i]; |
|
|
left.value = control[i]; |
|
|
left.error = ChebyEval(left.value) - Value(left.value); |
|
|
left.error = ChebyEval(left.value) - Value(left.value); |
|
|
right.value = control[i + 1]; |
|
|
right.value = control[i + 1]; |
|
|
right.error = ChebyEval(right.value) - Value(right.value); |
|
|
right.error = ChebyEval(right.value) - Value(right.value); |
|
|
|
|
|
|
|
|
static real limit = real::R_1 >> 500; |
|
|
|
|
|
|
|
|
static T limit = (T)1 >> 500; |
|
|
|
|
|
static T zero = (T)0; |
|
|
while (fabs(left.value - right.value) > limit) |
|
|
while (fabs(left.value - right.value) > limit) |
|
|
{ |
|
|
{ |
|
|
mid.value = (left.value + right.value) >> 1; |
|
|
mid.value = (left.value + right.value) >> 1; |
|
|
mid.error = ChebyEval(mid.value) - Value(mid.value); |
|
|
mid.error = ChebyEval(mid.value) - Value(mid.value); |
|
|
|
|
|
|
|
|
if ((left.error < real::R_0 && mid.error < real::R_0) |
|
|
|
|
|
|| (left.error > real::R_0 && mid.error > real::R_0)) |
|
|
|
|
|
|
|
|
if ((left.error < zero && mid.error < zero) |
|
|
|
|
|
|| (left.error > zero && mid.error > zero)) |
|
|
left = mid; |
|
|
left = mid; |
|
|
else |
|
|
else |
|
|
right = mid; |
|
|
right = mid; |
|
@@ -146,11 +155,11 @@ public: |
|
|
/* Find ORDER + 2 extrema of the error function. We need to |
|
|
/* Find ORDER + 2 extrema of the error function. We need to |
|
|
* compute the relative error, since its extrema are at slightly |
|
|
* compute the relative error, since its extrema are at slightly |
|
|
* different locations than the absolute error’s. */ |
|
|
* different locations than the absolute error’s. */ |
|
|
real final = 0; |
|
|
|
|
|
|
|
|
T final = 0; |
|
|
|
|
|
|
|
|
for (int i = 0; i < ORDER + 2; i++) |
|
|
for (int i = 0; i < ORDER + 2; i++) |
|
|
{ |
|
|
{ |
|
|
real a = -1, b = 1; |
|
|
|
|
|
|
|
|
T a = -1, b = 1; |
|
|
if (i > 0) |
|
|
if (i > 0) |
|
|
a = zeroes[i - 1]; |
|
|
a = zeroes[i - 1]; |
|
|
if (i < ORDER + 1) |
|
|
if (i < ORDER + 1) |
|
@@ -158,14 +167,14 @@ public: |
|
|
|
|
|
|
|
|
for (;;) |
|
|
for (;;) |
|
|
{ |
|
|
{ |
|
|
real c = a, delta = (b - a) >> 3; |
|
|
|
|
|
real maxerror = 0; |
|
|
|
|
|
real maxweight = 0; |
|
|
|
|
|
|
|
|
T c = a, delta = (b - a) >> 3; |
|
|
|
|
|
T maxerror = 0; |
|
|
|
|
|
T maxweight = 0; |
|
|
int best = -1; |
|
|
int best = -1; |
|
|
for (int k = 1; k <= 7; k++) |
|
|
for (int k = 1; k <= 7; k++) |
|
|
{ |
|
|
{ |
|
|
real error = ChebyEval(c) - Value(c); |
|
|
|
|
|
real weight = Weight(c); |
|
|
|
|
|
|
|
|
T error = ChebyEval(c) - Value(c); |
|
|
|
|
|
T weight = Weight(c); |
|
|
if (fabs(error * maxweight) >= fabs(maxerror * weight)) |
|
|
if (fabs(error * maxweight) >= fabs(maxerror * weight)) |
|
|
{ |
|
|
{ |
|
|
maxerror = error; |
|
|
maxerror = error; |
|
@@ -175,12 +184,12 @@ public: |
|
|
c += delta; |
|
|
c += delta; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
b = a + (real)(best + 1) * delta; |
|
|
|
|
|
a = a + (real)(best - 1) * delta; |
|
|
|
|
|
|
|
|
b = a + (T)(best + 1) * delta; |
|
|
|
|
|
a = a + (T)(best - 1) * delta; |
|
|
|
|
|
|
|
|
if (b - a < (real)1e-18) |
|
|
|
|
|
|
|
|
if (b - a < (T)1e-18) |
|
|
{ |
|
|
{ |
|
|
real e = maxerror / maxweight; |
|
|
|
|
|
|
|
|
T e = maxerror / maxweight; |
|
|
if (e > final) |
|
|
if (e > final) |
|
|
final = e; |
|
|
final = e; |
|
|
control[i] = (a + b) >> 1; |
|
|
control[i] = (a + b) >> 1; |
|
@@ -196,17 +205,17 @@ public: |
|
|
void Step() |
|
|
void Step() |
|
|
{ |
|
|
{ |
|
|
/* Pick up x_i where error will be 0 and compute f(x_i) */ |
|
|
/* Pick up x_i where error will be 0 and compute f(x_i) */ |
|
|
real fxn[ORDER + 2]; |
|
|
|
|
|
|
|
|
T fxn[ORDER + 2]; |
|
|
for (int i = 0; i < ORDER + 2; i++) |
|
|
for (int i = 0; i < ORDER + 2; i++) |
|
|
fxn[i] = Value(control[i]); |
|
|
fxn[i] = Value(control[i]); |
|
|
|
|
|
|
|
|
/* We build a matrix of Chebishev evaluations: row i contains the |
|
|
/* We build a matrix of Chebishev evaluations: row i contains the |
|
|
* evaluations of x_i for polynomial order n = 0, 1, ... */ |
|
|
* evaluations of x_i for polynomial order n = 0, 1, ... */ |
|
|
Matrix<ORDER + 2> mat; |
|
|
|
|
|
|
|
|
lol::Mat<ORDER + 2, T> mat; |
|
|
for (int i = 0; i < ORDER + 2; i++) |
|
|
for (int i = 0; i < ORDER + 2; i++) |
|
|
{ |
|
|
{ |
|
|
/* Compute the powers of x_i */ |
|
|
/* Compute the powers of x_i */ |
|
|
real powers[ORDER + 1]; |
|
|
|
|
|
|
|
|
T powers[ORDER + 1]; |
|
|
powers[0] = 1.0; |
|
|
powers[0] = 1.0; |
|
|
for (int n = 1; n < ORDER + 1; n++) |
|
|
for (int n = 1; n < ORDER + 1; n++) |
|
|
powers[n] = powers[n - 1] * control[i]; |
|
|
powers[n] = powers[n - 1] * control[i]; |
|
@@ -214,9 +223,9 @@ public: |
|
|
/* Compute the Chebishev evaluations at x_i */ |
|
|
/* Compute the Chebishev evaluations at x_i */ |
|
|
for (int n = 0; n < ORDER + 1; n++) |
|
|
for (int n = 0; n < ORDER + 1; n++) |
|
|
{ |
|
|
{ |
|
|
real sum = 0.0; |
|
|
|
|
|
|
|
|
T sum = 0.0; |
|
|
for (int k = 0; k < ORDER + 1; k++) |
|
|
for (int k = 0; k < ORDER + 1; k++) |
|
|
sum += (real)Cheby(n, k) * powers[k]; |
|
|
|
|
|
|
|
|
sum += (T)Cheby(n, k) * powers[k]; |
|
|
mat.m[i][n] = sum; |
|
|
mat.m[i][n] = sum; |
|
|
} |
|
|
} |
|
|
if (i & 1) |
|
|
if (i & 1) |
|
@@ -237,7 +246,7 @@ public: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* Compute the error */ |
|
|
/* Compute the error */ |
|
|
real error = 0; |
|
|
|
|
|
|
|
|
T error = 0; |
|
|
for (int i = 0; i < ORDER + 2; i++) |
|
|
for (int i = 0; i < ORDER + 2; i++) |
|
|
error += mat.m[ORDER + 1][i] * fxn[i]; |
|
|
error += mat.m[ORDER + 1][i] * fxn[i]; |
|
|
} |
|
|
} |
|
@@ -264,31 +273,31 @@ public: |
|
|
|
|
|
|
|
|
/* Transform Chebyshev polynomial weights into powers of X^i |
|
|
/* Transform Chebyshev polynomial weights into powers of X^i |
|
|
* in the [-1..1] range. */ |
|
|
* in the [-1..1] range. */ |
|
|
real bn[ORDER + 1]; |
|
|
|
|
|
|
|
|
T bn[ORDER + 1]; |
|
|
|
|
|
|
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
{ |
|
|
{ |
|
|
bn[i] = 0; |
|
|
bn[i] = 0; |
|
|
for (int j = 0; j < ORDER + 1; j++) |
|
|
for (int j = 0; j < ORDER + 1; j++) |
|
|
bn[i] += coeff[j] * (real)Cheby(j, i); |
|
|
|
|
|
|
|
|
bn[i] += coeff[j] * (T)Cheby(j, i); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* Transform a polynomial in the [-1..1] range into a polynomial |
|
|
/* Transform a polynomial in the [-1..1] range into a polynomial |
|
|
* in the [a..b] range. */ |
|
|
* in the [a..b] range. */ |
|
|
real k1p[ORDER + 1], k2p[ORDER + 1]; |
|
|
|
|
|
real an[ORDER + 1]; |
|
|
|
|
|
|
|
|
T k1p[ORDER + 1], k2p[ORDER + 1]; |
|
|
|
|
|
T an[ORDER + 1]; |
|
|
|
|
|
|
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
{ |
|
|
{ |
|
|
k1p[i] = i ? k1p[i - 1] * m_invk1 : real::R_1; |
|
|
|
|
|
k2p[i] = i ? k2p[i - 1] * m_invk2 : real::R_1; |
|
|
|
|
|
|
|
|
k1p[i] = i ? k1p[i - 1] * m_invk1 : (T)1; |
|
|
|
|
|
k2p[i] = i ? k2p[i - 1] * m_invk2 : (T)1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
for (int i = 0; i < ORDER + 1; i++) |
|
|
{ |
|
|
{ |
|
|
an[i] = 0; |
|
|
an[i] = 0; |
|
|
for (int j = i; j < ORDER + 1; j++) |
|
|
for (int j = i; j < ORDER + 1; j++) |
|
|
an[i] += (real)Comb(j, i) * k1p[j - i] * bn[j]; |
|
|
|
|
|
|
|
|
an[i] += (T)Comb(j, i) * k1p[j - i] * bn[j]; |
|
|
an[i] *= k2p[i]; |
|
|
an[i] *= k2p[i]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -297,33 +306,35 @@ public: |
|
|
{ |
|
|
{ |
|
|
if (j) |
|
|
if (j) |
|
|
printf("+"); |
|
|
printf("+"); |
|
|
printf("x^%i*", j); |
|
|
|
|
|
|
|
|
printf("x**%i*", j); |
|
|
an[j].print(40); |
|
|
an[j].print(40); |
|
|
} |
|
|
} |
|
|
printf("\n"); |
|
|
printf("\n"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
real Value(real const &x) |
|
|
|
|
|
|
|
|
T Value(T const &x) |
|
|
{ |
|
|
{ |
|
|
return m_func(x * m_k2 + m_k1); |
|
|
return m_func(x * m_k2 + m_k1); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
real Weight(real const &x) |
|
|
|
|
|
|
|
|
T Weight(T const &x) |
|
|
{ |
|
|
{ |
|
|
return m_weight(x * m_k2 + m_k1); |
|
|
return m_weight(x * m_k2 + m_k1); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* ORDER + 1 Chebyshev coefficients and 1 error value */ |
|
|
/* ORDER + 1 Chebyshev coefficients and 1 error value */ |
|
|
real coeff[ORDER + 2]; |
|
|
|
|
|
|
|
|
T coeff[ORDER + 2]; |
|
|
/* ORDER + 1 zeroes of the error function */ |
|
|
/* ORDER + 1 zeroes of the error function */ |
|
|
real zeroes[ORDER + 1]; |
|
|
|
|
|
|
|
|
T zeroes[ORDER + 1]; |
|
|
/* ORDER + 2 control points */ |
|
|
/* ORDER + 2 control points */ |
|
|
real control[ORDER + 2]; |
|
|
|
|
|
|
|
|
T control[ORDER + 2]; |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
RealFunc *m_func, *m_weight; |
|
|
RealFunc *m_func, *m_weight; |
|
|
real m_k1, m_k2, m_invk1, m_invk2; |
|
|
|
|
|
|
|
|
T m_k1, m_k2, m_invk1, m_invk2; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
#endif /* __REMEZ_SOLVER_H__ */ |
|
|
|
|
|
|
|
|
} /* namespace lol */ |
|
|
|
|
|
|
|
|
|
|
|
#endif /* __LOL_MATH_REMEZ_H__ */ |
|
|
|
|
|
|