Browse Source

lolremez: useless refactoring.

undefined
Sam Hocevar 11 years ago
parent
commit
afc62a5399
3 changed files with 54 additions and 57 deletions
  1. +2
    -2
      tools/lolremez/lolremez.cpp
  2. +36
    -41
      tools/lolremez/solver.cpp
  3. +16
    -14
      tools/lolremez/solver.h

+ 2
- 2
tools/lolremez/lolremez.cpp View File

@@ -81,8 +81,8 @@ int main(int argc, char **argv)
FAIL(); FAIL();
} }


RemezSolver solver(degree + 1, 20);
solver.Run(xmin, xmax, f, g);
remez_solver solver(degree + 1, 20);
solver.run(xmin, xmax, f, g);


return 0; return 0;
} }


+ 36
- 41
tools/lolremez/solver.cpp View File

@@ -26,14 +26,14 @@


using lol::real; using lol::real;


RemezSolver::RemezSolver(int order, int decimals)
remez_solver::remez_solver(int order, int decimals)
: m_order(order), : m_order(order),
m_decimals(decimals), m_decimals(decimals),
m_has_weight(false) m_has_weight(false)
{ {
} }


void RemezSolver::Run(real a, real b, char const *func, char const *weight)
void remez_solver::run(real a, real b, char const *func, char const *weight)
{ {
using std::printf; using std::printf;


@@ -49,38 +49,32 @@ void RemezSolver::Run(real a, real b, char const *func, char const *weight)
m_k2 = (b - a) / 2; m_k2 = (b - a) / 2;
m_epsilon = pow((real)10, (real)-(m_decimals + 2)); m_epsilon = pow((real)10, (real)-(m_decimals + 2));


Init();

PrintPoly();

real error = -1;
remez_init();
print_poly();


for (int n = 0; ; n++) for (int n = 0; ; n++)
{ {
real newerror = FindExtrema();
printf(" -:- error at step %i: ", n);
newerror.print(m_decimals);
printf("\n");
real old_error = m_error;


Step();
find_extrema();
remez_step();


if (error >= (real)0 && fabs(newerror - error) < error * m_epsilon)
if (m_error >= (real)0
&& fabs(m_error - old_error) < m_error * m_epsilon)
break; break;
error = newerror;

PrintPoly();


FindZeroes();
print_poly();
find_zeroes();
} }


PrintPoly();
print_poly();
} }


/* /*
* This is basically the first Remez step: we solve a system of * This is basically the first Remez step: we solve a system of
* order N+1 and get a good initial polynomial estimate. * order N+1 and get a good initial polynomial estimate.
*/ */
void RemezSolver::Init()
void remez_solver::remez_init()
{ {
/* m_order + 1 zeroes of the error function */ /* m_order + 1 zeroes of the error function */
m_zeroes.Resize(m_order + 1); m_zeroes.Resize(m_order + 1);
@@ -94,7 +88,7 @@ void RemezSolver::Init()
for (int i = 0; i < m_order + 1; i++) for (int i = 0; i < m_order + 1; i++)
{ {
m_zeroes[i] = (real)(2 * i - m_order) / (real)(m_order + 1); m_zeroes[i] = (real)(2 * i - m_order) / (real)(m_order + 1);
fxn.Push(EvalFunc(m_zeroes[i]));
fxn.Push(eval_func(m_zeroes[i]));
} }


/* We build a matrix of Chebishev evaluations: row i contains the /* We build a matrix of Chebishev evaluations: row i contains the
@@ -126,12 +120,12 @@ void RemezSolver::Init()
* Every subsequent iteration of the Remez algorithm: we solve a system * Every subsequent iteration of the Remez algorithm: we solve a system
* of order N+2 to both refine the estimate and compute the error. * of order N+2 to both refine the estimate and compute the error.
*/ */
void RemezSolver::Step()
void remez_solver::remez_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) */
array<real> fxn; array<real> fxn;
for (int i = 0; i < m_order + 2; i++) for (int i = 0; i < m_order + 2; i++)
fxn.Push(EvalFunc(m_control[i]));
fxn.Push(eval_func(m_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, ... */
@@ -146,7 +140,7 @@ void RemezSolver::Step()
/* The last line of the system is the oscillating error */ /* The last line of the system is the oscillating error */
for (int i = 0; i < m_order + 2; i++) for (int i = 0; i < m_order + 2; i++)
{ {
real error = fabs(EvalWeight(m_control[i]));
real error = fabs(eval_weight(m_control[i]));
system[i][m_order + 1] = (i & 1) ? error : -error; system[i][m_order + 1] = (i & 1) ? error : -error;
} }


@@ -170,7 +164,7 @@ void RemezSolver::Step()
error += system[m_order + 1][i] * fxn[i]; error += system[m_order + 1][i] * fxn[i];
} }


void RemezSolver::FindZeroes()
void remez_solver::find_zeroes()
{ {
m_stats_cheby = m_stats_func = m_stats_weight = 0.f; m_stats_cheby = m_stats_func = m_stats_weight = 0.f;


@@ -182,9 +176,9 @@ void RemezSolver::FindZeroes()
struct { real value, error; } a, b, c; struct { real value, error; } a, b, c;


a.value = m_control[i]; a.value = m_control[i];
a.error = EvalEstimate(a.value) - EvalFunc(a.value);
a.error = eval_estimate(a.value) - eval_func(a.value);
b.value = m_control[i + 1]; b.value = m_control[i + 1];
b.error = EvalEstimate(b.value) - EvalFunc(b.value);
b.error = eval_estimate(b.value) - eval_func(b.value);


static real limit = ldexp((real)1, -500); static real limit = ldexp((real)1, -500);
static real zero = (real)0; static real zero = (real)0;
@@ -199,7 +193,7 @@ void RemezSolver::FindZeroes()
* we may be at an inflection point. Use the midpoint to get * we may be at an inflection point. Use the midpoint to get
* out of this situation. */ * out of this situation. */
c.value = newc == c.value ? (a.value + b.value) / 2 : newc; c.value = newc == c.value ? (a.value + b.value) / 2 : newc;
c.error = EvalEstimate(c.value) - EvalFunc(c.value);
c.error = eval_estimate(c.value) - eval_func(c.value);


if (c.error == zero) if (c.error == zero)
break; break;
@@ -214,19 +208,19 @@ void RemezSolver::FindZeroes()
m_zeroes[i] = c.value; m_zeroes[i] = c.value;
} }


printf(" -:- times for zeroes: estimate %f func %f weight %f\n",
printf(" -:- timings for zeroes: estimate %f func %f weight %f\n",
m_stats_cheby, m_stats_func, m_stats_weight); m_stats_cheby, m_stats_func, m_stats_weight);
} }


/* XXX: this is the real costly function */ /* XXX: this is the real costly function */
real RemezSolver::FindExtrema()
void remez_solver::find_extrema()
{ {
using std::printf; using std::printf;


/* Find m_order + 2 extrema of the error function. We need to /* Find m_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;
m_error = 0;


m_stats_cheby = m_stats_func = m_stats_weight = 0.f; m_stats_cheby = m_stats_func = m_stats_weight = 0.f;
int evals = 0, rounds = 0; int evals = 0, rounds = 0;
@@ -250,8 +244,8 @@ real RemezSolver::FindExtrema()
if (r == 0 || (k & 1)) if (r == 0 || (k & 1))
{ {
++evals; ++evals;
real error = fabs(EvalEstimate(c) - EvalFunc(c));
real weight = fabs(EvalWeight(c));
real error = fabs(eval_estimate(c) - eval_func(c));
real weight = fabs(eval_weight(c));
/* if error/weight >= maxerror/maxweight */ /* if error/weight >= maxerror/maxweight */
if (error * maxweight >= maxerror * weight) if (error * maxweight >= maxerror * weight)
{ {
@@ -280,22 +274,23 @@ real RemezSolver::FindExtrema()
if (delta < m_epsilon) if (delta < m_epsilon)
{ {
real e = fabs(maxerror / maxweight); real e = fabs(maxerror / maxweight);
if (e > final)
final = e;
if (e > m_error)
m_error = e;
m_control[i] = (a + b) / 2; m_control[i] = (a + b) / 2;
break; break;
} }
} }
} }


printf(" -:- times for extrema: estimate %f func %f weight %f\n",
printf(" -:- timings for extrema: estimate %f func %f weight %f\n",
m_stats_cheby, m_stats_func, m_stats_weight); m_stats_cheby, m_stats_func, m_stats_weight);
printf(" -:- calls: %d rounds, %d evals\n", rounds, evals); printf(" -:- calls: %d rounds, %d evals\n", rounds, evals);

return final;
printf(" -:- error: ");
m_error.print(m_decimals);
printf("\n");
} }


void RemezSolver::PrintPoly()
void remez_solver::print_poly()
{ {
using std::printf; using std::printf;


@@ -315,7 +310,7 @@ void RemezSolver::PrintPoly()
printf("\n\n"); printf("\n\n");
} }


real RemezSolver::EvalEstimate(real const &x)
real remez_solver::eval_estimate(real const &x)
{ {
Timer t; Timer t;
real ret = m_estimate.eval(x); real ret = m_estimate.eval(x);
@@ -323,7 +318,7 @@ real RemezSolver::EvalEstimate(real const &x)
return ret; return ret;
} }


real RemezSolver::EvalFunc(real const &x)
real remez_solver::eval_func(real const &x)
{ {
Timer t; Timer t;
real ret = m_func.eval(x * m_k2 + m_k1); real ret = m_func.eval(x * m_k2 + m_k1);
@@ -331,7 +326,7 @@ real RemezSolver::EvalFunc(real const &x)
return ret; return ret;
} }


real RemezSolver::EvalWeight(real const &x)
real remez_solver::eval_weight(real const &x)
{ {
Timer t; Timer t;
real ret = m_has_weight ? m_weight.eval(x * m_k2 + m_k1) : real(1); real ret = m_has_weight ? m_weight.eval(x * m_k2 + m_k1) : real(1);


+ 16
- 14
tools/lolremez/solver.h View File

@@ -13,32 +13,34 @@
#pragma once #pragma once


// //
// The RemezSolver class
// ---------------------
// The remez_solver class
// ----------------------
// //


#include <cstdio> #include <cstdio>


#include "expression.h" #include "expression.h"


class RemezSolver
class remez_solver
{ {
public: public:
RemezSolver(int order, int decimals);
remez_solver(int order, int decimals);


void Run(lol::real a, lol::real b,
void run(lol::real a, lol::real b,
char const *func, char const *weight = nullptr); char const *func, char const *weight = nullptr);


private: private:
void Init();
void FindZeroes();
lol::real FindExtrema();
void Step();
void PrintPoly();
void remez_init();
void remez_step();


lol::real EvalEstimate(lol::real const &x);
lol::real EvalFunc(lol::real const &x);
lol::real EvalWeight(lol::real const &x);
void find_zeroes();
void find_extrema();

void print_poly();

lol::real eval_estimate(lol::real const &x);
lol::real eval_func(lol::real const &x);
lol::real eval_weight(lol::real const &x);


private: private:
/* User-defined parameters */ /* User-defined parameters */
@@ -52,7 +54,7 @@ private:
lol::array<lol::real> m_zeroes; lol::array<lol::real> m_zeroes;
lol::array<lol::real> m_control; lol::array<lol::real> m_control;


lol::real m_k1, m_k2, m_epsilon;
lol::real m_k1, m_k2, m_epsilon, m_error;


/* Statistics */ /* Statistics */
float m_stats_cheby; float m_stats_cheby;


Loading…
Cancel
Save