Browse Source

math: use exponentiation by squaring for real::pow().

legacy
Sam Hocevar 7 years ago
parent
commit
7b9d98109b
1 changed files with 28 additions and 12 deletions
  1. +28
    -12
      src/math/real.cpp

+ 28
- 12
src/math/real.cpp View File

@@ -101,7 +101,7 @@ template<> real::~Real()
delete[] m_mantissa; delete[] m_mantissa;
} }


/* FIXME: 64-bit integer loading is incorrect,we lose precision. */
/* FIXME: 64-bit integer loading is incorrect, we lose precision. */
template<> real::Real(int32_t i) { new(this) real((double)i); } template<> real::Real(int32_t i) { new(this) real((double)i); }
template<> real::Real(uint32_t i) { new(this) real((double)i); } template<> real::Real(uint32_t i) { new(this) real((double)i); }
template<> real::Real(int64_t i) { new(this) real((double)i); } template<> real::Real(int64_t i) { new(this) real((double)i); }
@@ -747,25 +747,41 @@ template<> real cbrt(real const &x)


template<> real pow(real const &x, real const &y) template<> real pow(real const &x, real const &y)
{ {
/* Shortcuts for degenerate cases */
if (!y) if (!y)
return real::R_1(); return real::R_1();
if (!x) if (!x)
return real::R_0(); return real::R_0();
if (x > real::R_0())
return exp(y * log(x));
else /* x < 0 */

/* Small integer exponent: use exponentiation by squaring */
int int_y = (int)y;
if (y == (real)int_y)
{ {
/* Odd integer exponent */
if (y == (round(y / 2) * 2))
return exp(y * log(-x));
real ret = real::R_1();
real x_n = int_y > 0 ? x : inverse(x);


/* Even integer exponent */
if (y == round(y))
return -exp(y * log(-x));
while (int_y) /* Can be > 0 or < 0 */
{
if (int_y & 1)
ret *= x_n;
x_n *= x_n;
int_y /= 2;
}


/* FIXME: negative nth root */
return real::R_0();
return ret;
} }

/* If x is positive, nothing special to do. */
if (x > real::R_0())
return exp(y * log(x));

/* XXX: manpage for pow() says “If x is a finite value less than 0,
* and y is a finite noninteger, a domain error occurs, and a NaN is
* returned”. We check whether y is closer to an even number or to
* an odd number and return something reasonable. */
real round_y = round(y);
bool is_odd = round_y / 2 == round(round_y / 2);
return is_odd ? exp(y * log(-x)) : -exp(y * log(-x));
} }


static real fast_fact(unsigned int x) static real fast_fact(unsigned int x)


Loading…
Cancel
Save