| @@ -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) | ||||