ソースを参照

math: write a faster factorial method for use in exp() and sin(). These

functions are now about 20% faster.
legacy
Sam Hocevar sam 13年前
コミット
c4bad581a2
2個のファイルの変更48行の追加17行の削除
  1. +46
    -16
      src/real.cpp
  2. +2
    -1
      test/math/remez.cpp

+ 46
- 16
src/real.cpp ファイルの表示

@@ -693,6 +693,32 @@ real pow(real const &x, real const &y)
}
}

static real fast_fact(int x)
{
real ret = real::R_1;
int i = 1, multiplier = 1, exponent = 0;

for (;;)
{
if (i++ >= x)
/* Multiplication is a no-op if multiplier == 1 */
return ldexp(ret * multiplier, exponent);

int tmp = i;
while ((tmp & 1) == 0)
{
tmp >>= 1;
exponent++;
}
if (multiplier * tmp / tmp != multiplier)
{
ret *= multiplier;
multiplier = 1;
}
multiplier *= tmp;
}
}

real gamma(real const &x)
{
/* We use Spouge's formula. FIXME: precision is far from acceptable,
@@ -802,22 +828,19 @@ static real fast_exp_sub(real const &x, real const &y)
* no effort whatsoever was made to improve convergence outside this
* domain of validity. The argument y is used for cases where we
* don't want the leading 1 in the Taylor series. */
real ret = real::R_1 - y, fact = real::R_1, xn = x;
real ret = real::R_1 - y, xn = x;
int i = 1;

for (int i = 1; ; i++)
for (;;)
{
real newret = ret + xn;
if (newret == ret)
break;
ret = newret;
real mul = (i + 1);
fact *= mul;
ret *= mul;
ret = newret * ++i;
xn *= x;
}
ret /= fact;

return ret;
return ret / fast_fact(i);
}

real exp(real const &x)
@@ -1004,18 +1027,17 @@ real sin(real const &x)
absx = real::R_PI - absx;

real ret = real::R_0, fact = real::R_1, xn = absx, mx2 = -absx * absx;
for (int i = 1; ; i += 2)
int i = 1;
for (;;)
{
real newret = ret + xn;
if (newret == ret)
break;
ret = newret;
real mul = (i + 1) * (i + 2);
fact *= mul;
ret *= mul;
ret = newret * ((i + 1) * (i + 2));
xn *= mx2;
i += 2;
}
ret /= fact;
ret /= fast_fact(i);

/* Propagate sign */
if (switch_sign)
@@ -1286,8 +1308,8 @@ void real::print(int ndigits) const
static real fast_pi()
{
/* Approximate Pi using Machin's formula: 16*atan(1/5)-4*atan(1/239) */
real ret = 0.0, x0 = 5.0, x1 = 239.0;
real const m0 = -x0 * x0, m1 = -x1 * x1, r16 = 16.0, r4 = 4.0;
real ret = 0, x0 = 5, x1 = 239;
real const m0 = -x0 * x0, m1 = -x1 * x1, r16 = 16, r4 = 4;

for (int i = 1; ; i += 2)
{
@@ -1308,6 +1330,14 @@ real const real::R_2 = (real)2.0;
real const real::R_3 = (real)3.0;
real const real::R_10 = (real)10.0;

/*
* Initialisation order is important here:
* - fast_log() requires R_1
* - log() requires R_LN2
* - re() require R_2
* - exp() requires R_0, R_1, R_LN2
* - sqrt() requires R_3
*/
real const real::R_LN2 = fast_log(R_2);
real const real::R_LN10 = log(R_10);
real const real::R_LOG2E = re(R_LN2);


+ 2
- 1
test/math/remez.cpp ファイルの表示

@@ -24,11 +24,12 @@ using lol::RemezSolver;

/* See the tutorial at http://lol.zoy.org/wiki/doc/maths/remez */
real f(real const &x) { return exp(x); }
real g(real const &x) { return exp(x); }

int main(int argc, char **argv)
{
RemezSolver<4, real> solver;
solver.Run(-1, 1, f, 30);
solver.Run(-1, 1, f, g, 30);
return 0;
}


読み込み中…
キャンセル
保存