that are not explicitly real, even with namespace mistakes.legacy
@@ -152,6 +152,7 @@ void DebugSphere::TickDraw(float deltams) | |||
#endif | |||
int const ndiv = 2; | |||
using std::log; | |||
int const ntriangles = 20 * (1 << (ndiv * 2)) | |||
* (int)(log(1.0f / 0.01f) / log(1.1f) + 0.9999f); | |||
@@ -24,101 +24,107 @@ | |||
namespace lol | |||
{ | |||
class real | |||
/* | |||
* The base class for reals. The only real reason for making this a template | |||
* class is so we can have implicit constructors ("real x = 1" works) but | |||
* avoid accidental implicit conversions ("int x = 1; sqrt(x)" will never | |||
* call real::sqrt). | |||
*/ | |||
template<int N> class Real | |||
{ | |||
public: | |||
real(); | |||
real(real const &x); | |||
real const &operator =(real const &x); | |||
~real(); | |||
Real(); | |||
Real(Real<N> const &x); | |||
Real const &operator =(Real<N> const &x); | |||
~Real(); | |||
real(float f); | |||
real(double f); | |||
real(int i); | |||
real(unsigned int i); | |||
Real(float f); | |||
Real(double f); | |||
Real(int i); | |||
Real(unsigned int i); | |||
real(char const *str); | |||
Real(char const *str); | |||
operator float() const; | |||
operator double() const; | |||
operator int() const; | |||
operator unsigned int() const; | |||
real operator +() const; | |||
real operator -() const; | |||
real operator +(real const &x) const; | |||
real operator -(real const &x) const; | |||
real operator *(real const &x) const; | |||
real operator /(real const &x) const; | |||
real const &operator +=(real const &x); | |||
real const &operator -=(real const &x); | |||
real const &operator *=(real const &x); | |||
real const &operator /=(real const &x); | |||
bool operator ==(real const &x) const; | |||
bool operator !=(real const &x) const; | |||
bool operator <(real const &x) const; | |||
bool operator >(real const &x) const; | |||
bool operator <=(real const &x) const; | |||
bool operator >=(real const &x) const; | |||
Real<N> operator +() const; | |||
Real<N> operator -() const; | |||
Real<N> operator +(Real<N> const &x) const; | |||
Real<N> operator -(Real<N> const &x) const; | |||
Real<N> operator *(Real<N> const &x) const; | |||
Real<N> operator /(Real<N> const &x) const; | |||
Real<N> const &operator +=(Real<N> const &x); | |||
Real<N> const &operator -=(Real<N> const &x); | |||
Real<N> const &operator *=(Real<N> const &x); | |||
Real<N> const &operator /=(Real<N> const &x); | |||
bool operator ==(Real<N> const &x) const; | |||
bool operator !=(Real<N> const &x) const; | |||
bool operator <(Real<N> const &x) const; | |||
bool operator >(Real<N> const &x) const; | |||
bool operator <=(Real<N> const &x) const; | |||
bool operator >=(Real<N> const &x) const; | |||
bool operator !() const; | |||
operator bool() const; | |||
/* Trigonometric functions */ | |||
friend real sin(real const &x); | |||
friend real cos(real const &x); | |||
friend real tan(real const &x); | |||
friend real asin(real const &x); | |||
friend real acos(real const &x); | |||
friend real atan(real const &x); | |||
friend real atan2(real const &y, real const &x); | |||
template<int M> friend Real<M> sin(Real<M> const &x); | |||
template<int M> friend Real<M> cos(Real<M> const &x); | |||
template<int M> friend Real<M> tan(Real<M> const &x); | |||
template<int M> friend Real<M> asin(Real<M> const &x); | |||
template<int M> friend Real<M> acos(Real<M> const &x); | |||
template<int M> friend Real<M> atan(Real<M> const &x); | |||
template<int M> friend Real<M> atan2(Real<M> const &y, Real<M> const &x); | |||
/* Hyperbolic functions */ | |||
friend real sinh(real const &x); | |||
friend real cosh(real const &x); | |||
friend real tanh(real const &x); | |||
template<int M> friend Real<M> sinh(Real<M> const &x); | |||
template<int M> friend Real<M> cosh(Real<M> const &x); | |||
template<int M> friend Real<M> tanh(Real<M> const &x); | |||
/* Exponential and logarithmic functions */ | |||
friend real exp(real const &x); | |||
friend real exp2(real const &x); | |||
friend real log(real const &x); | |||
friend real log2(real const &x); | |||
friend real log10(real const &x); | |||
friend real frexp(real const &x, int *exp); | |||
friend real ldexp(real const &x, int exp); | |||
friend real modf(real const &x, real *iptr); | |||
friend real ulp(real const &x); | |||
friend real nextafter(real const &x, real const &y); | |||
template<int M> friend Real<M> exp(Real<M> const &x); | |||
template<int M> friend Real<M> exp2(Real<M> const &x); | |||
template<int M> friend Real<M> log(Real<M> const &x); | |||
template<int M> friend Real<M> log2(Real<M> const &x); | |||
template<int M> friend Real<M> log10(Real<M> const &x); | |||
template<int M> friend Real<M> frexp(Real<M> const &x, int *exp); | |||
template<int M> friend Real<M> ldexp(Real<M> const &x, int exp); | |||
template<int M> friend Real<M> modf(Real<M> const &x, Real<M> *iptr); | |||
template<int M> friend Real<M> ulp(Real<M> const &x); | |||
template<int M> friend Real<M> nextafter(Real<M> const &x, Real<M> const &y); | |||
/* Power functions */ | |||
friend real re(real const &x); | |||
friend real sqrt(real const &x); | |||
friend real cbrt(real const &x); | |||
friend real pow(real const &x, real const &y); | |||
friend real gamma(real const &x); | |||
template<int M> friend Real<M> re(Real<M> const &x); | |||
template<int M> friend Real<M> sqrt(Real<M> const &x); | |||
template<int M> friend Real<M> cbrt(Real<M> const &x); | |||
template<int M> friend Real<M> pow(Real<M> const &x, Real<M> const &y); | |||
template<int M> friend Real<M> gamma(Real<M> const &x); | |||
/* Rounding, absolute value, remainder etc. */ | |||
friend real ceil(real const &x); | |||
friend real copysign(real const &x, real const &y); | |||
friend real floor(real const &x); | |||
friend real fabs(real const &x); | |||
friend real round(real const &x); | |||
friend real fmod(real const &x, real const &y); | |||
template<int M> friend Real<M> ceil(Real<M> const &x); | |||
template<int M> friend Real<M> copysign(Real<M> const &x, Real<M> const &y); | |||
template<int M> friend Real<M> floor(Real<M> const &x); | |||
template<int M> friend Real<M> fabs(Real<M> const &x); | |||
template<int M> friend Real<M> round(Real<M> const &x); | |||
template<int M> friend Real<M> fmod(Real<M> const &x, Real<N> const &y); | |||
void hexprint() const; | |||
void print(int ndigits = 150) const; | |||
/* Additional operators using base C++ types */ | |||
#define __LOL_REAL_OP_HELPER_GENERIC(op, type) \ | |||
inline real operator op(type x) const { return *this op (real)x; } \ | |||
inline real const &operator op##=(type x) { return *this = (*this op x); } | |||
inline Real<N> operator op(type x) const { return *this op (Real<N>)x; } \ | |||
inline Real<N> const &operator op##=(type x) { return *this = (*this op x); } | |||
#define __LOL_REAL_OP_HELPER_FASTMULDIV(op, type) \ | |||
inline real operator op(type x) const \ | |||
inline Real<N> operator op(type x) const \ | |||
{ \ | |||
real tmp = *this; return tmp op##= x; \ | |||
Real<N> tmp = *this; return tmp op##= x; \ | |||
} \ | |||
inline real const &operator op##=(type x) \ | |||
inline Real<N> const &operator op##=(type x) \ | |||
{ \ | |||
/* If multiplying or dividing by a power of two, take a shortcut */ \ | |||
if ((m_signexp << 1) && x && !(x & (x - 1))) \ | |||
@@ -127,7 +133,7 @@ public: | |||
m_signexp += 1 op 2 - 1; /* 1 if op is *, -1 if op is / */ \ | |||
} \ | |||
else \ | |||
*this = *this op (real)x; \ | |||
*this = *this op (Real<N>)x; \ | |||
return *this; \ | |||
} | |||
#define __LOL_REAL_OP_HELPER_INT(type) \ | |||
@@ -147,32 +153,32 @@ public: | |||
__LOL_REAL_OP_HELPER_FLOAT(double) | |||
/* Constants */ | |||
static real const R_0; | |||
static real const R_1; | |||
static real const R_2; | |||
static real const R_3; | |||
static real const R_10; | |||
static real const R_E; | |||
static real const R_LOG2E; | |||
static real const R_LOG10E; | |||
static real const R_LN2; | |||
static real const R_LN10; | |||
static real const R_PI; | |||
static real const R_PI_2; | |||
static real const R_PI_3; | |||
static real const R_PI_4; | |||
static real const R_1_PI; | |||
static real const R_2_PI; | |||
static real const R_2_SQRTPI; | |||
static real const R_SQRT2; | |||
static real const R_SQRT3; | |||
static real const R_SQRT1_2; | |||
static Real<N> const R_0; | |||
static Real<N> const R_1; | |||
static Real<N> const R_2; | |||
static Real<N> const R_3; | |||
static Real<N> const R_10; | |||
static Real<N> const R_E; | |||
static Real<N> const R_LOG2E; | |||
static Real<N> const R_LOG10E; | |||
static Real<N> const R_LN2; | |||
static Real<N> const R_LN10; | |||
static Real<N> const R_PI; | |||
static Real<N> const R_PI_2; | |||
static Real<N> const R_PI_3; | |||
static Real<N> const R_PI_4; | |||
static Real<N> const R_1_PI; | |||
static Real<N> const R_2_PI; | |||
static Real<N> const R_2_SQRTPI; | |||
static Real<N> const R_SQRT2; | |||
static Real<N> const R_SQRT3; | |||
static Real<N> const R_SQRT1_2; | |||
/* XXX: changing this requires tuning real::fres (the number of | |||
* Newton-Raphson iterations) and real::print (the number of printed | |||
* digits) */ | |||
static int const BIGITS = 16; | |||
static int const BIGITS = N; | |||
static int const BIGIT_BITS = 32; | |||
private: | |||
@@ -180,6 +186,82 @@ private: | |||
uint32_t m_signexp; | |||
}; | |||
/* | |||
* The real type used for real numbers | |||
*/ | |||
typedef Real<16> real; | |||
/* | |||
* Mandatory forward declarations of template specialisations | |||
*/ | |||
template<> real::Real(); | |||
template<> real::Real(real const &x); | |||
template<> real const &real::operator =(real const &x); | |||
template<> real::~Real(); | |||
template<> real::Real(float f); | |||
template<> real::Real(double f); | |||
template<> real::Real(int i); | |||
template<> real::Real(unsigned int i); | |||
template<> real::Real(char const *str); | |||
template<> real::operator float() const; | |||
template<> real::operator double() const; | |||
template<> real::operator int() const; | |||
template<> real::operator unsigned int() const; | |||
template<> real real::operator +() const; | |||
template<> real real::operator -() const; | |||
template<> real real::operator +(real const &x) const; | |||
template<> real real::operator -(real const &x) const; | |||
template<> real real::operator *(real const &x) const; | |||
template<> real real::operator /(real const &x) const; | |||
template<> real const &real::operator +=(real const &x); | |||
template<> real const &real::operator -=(real const &x); | |||
template<> real const &real::operator *=(real const &x); | |||
template<> real const &real::operator /=(real const &x); | |||
template<> bool real::operator ==(real const &x) const; | |||
template<> bool real::operator !=(real const &x) const; | |||
template<> bool real::operator <(real const &x) const; | |||
template<> bool real::operator >(real const &x) const; | |||
template<> bool real::operator <=(real const &x) const; | |||
template<> bool real::operator >=(real const &x) const; | |||
template<> bool real::operator !() const; | |||
template<> real::operator bool() const; | |||
template<> real sin(real const &x); | |||
template<> real cos(real const &x); | |||
template<> real tan(real const &x); | |||
template<> real asin(real const &x); | |||
template<> real acos(real const &x); | |||
template<> real atan(real const &x); | |||
template<> real atan2(real const &y, real const &x); | |||
template<> real sinh(real const &x); | |||
template<> real cosh(real const &x); | |||
template<> real tanh(real const &x); | |||
template<> real exp(real const &x); | |||
template<> real exp2(real const &x); | |||
template<> real log(real const &x); | |||
template<> real log2(real const &x); | |||
template<> real log10(real const &x); | |||
template<> real frexp(real const &x, int *exp); | |||
template<> real ldexp(real const &x, int exp); | |||
template<> real modf(real const &x, real *iptr); | |||
template<> real ulp(real const &x); | |||
template<> real nextafter(real const &x, real const &y); | |||
template<> real re(real const &x); | |||
template<> real sqrt(real const &x); | |||
template<> real cbrt(real const &x); | |||
template<> real pow(real const &x, real const &y); | |||
template<> real gamma(real const &x); | |||
template<> real ceil(real const &x); | |||
template<> real copysign(real const &x, real const &y); | |||
template<> real floor(real const &x); | |||
template<> real fabs(real const &x); | |||
template<> real round(real const &x); | |||
template<> real fmod(real const &x, real const &y); | |||
template<> void real::hexprint() const; | |||
template<> void real::print(int ndigits) const; | |||
} /* namespace lol */ | |||
#endif // __LOL_MATH_REAL_H__ | |||
@@ -1047,7 +1047,7 @@ static inline Quat<T> operator /(Quat<T> x, Quat<T> const &y) | |||
tprefix \ | |||
inline double len(tname<type> const &a) \ | |||
{ \ | |||
using namespace std; \ | |||
using std::sqrt; \ | |||
return sqrt((double)sqlen(a)); \ | |||
} \ | |||
\ | |||
@@ -269,6 +269,7 @@ public: | |||
#define LOLUNIT_ASSERT_DOUBLES_EQUAL_GENERIC(msg, a, b, t) \ | |||
do { \ | |||
m_asserts++; \ | |||
using std::fabs; \ | |||
if (True() && fabs((a) - (b)) > fabs((t))) \ | |||
{ \ | |||
m_errorlog << std::endl << std::endl; \ | |||
@@ -33,20 +33,20 @@ using namespace std; | |||
namespace lol | |||
{ | |||
real::real() | |||
template<> real::Real() | |||
{ | |||
m_mantissa = new uint32_t[BIGITS]; | |||
m_signexp = 0; | |||
} | |||
real::real(real const &x) | |||
template<> real::Real(real const &x) | |||
{ | |||
m_mantissa = new uint32_t[BIGITS]; | |||
memcpy(m_mantissa, x.m_mantissa, BIGITS * sizeof(uint32_t)); | |||
m_signexp = x.m_signexp; | |||
} | |||
real const &real::operator =(real const &x) | |||
template<> real const &real::operator =(real const &x) | |||
{ | |||
if (&x != this) | |||
{ | |||
@@ -57,16 +57,16 @@ real const &real::operator =(real const &x) | |||
return *this; | |||
} | |||
real::~real() | |||
template<> real::~Real() | |||
{ | |||
delete[] m_mantissa; | |||
} | |||
real::real(float f) { new(this) real((double)f); } | |||
real::real(int i) { new(this) real((double)i); } | |||
real::real(unsigned int i) { new(this) real((double)i); } | |||
template<> real::Real(float f) { new(this) real((double)f); } | |||
template<> real::Real(int i) { new(this) real((double)i); } | |||
template<> real::Real(unsigned int i) { new(this) real((double)i); } | |||
real::real(double d) | |||
template<> real::Real(double d) | |||
{ | |||
new(this) real(); | |||
@@ -93,11 +93,11 @@ real::real(double d) | |||
memset(m_mantissa + 2, 0, (BIGITS - 2) * sizeof(m_mantissa[0])); | |||
} | |||
real::operator float() const { return (float)(double)(*this); } | |||
real::operator int() const { return (int)(double)(*this); } | |||
real::operator unsigned int() const { return (unsigned int)(double)(*this); } | |||
template<> real::operator float() const { return (float)(double)(*this); } | |||
template<> real::operator int() const { return (int)(double)(*this); } | |||
template<> real::operator unsigned() const { return (unsigned)(double)(*this); } | |||
real::operator double() const | |||
template<> real::operator double() const | |||
{ | |||
union { double d; uint64_t x; } u; | |||
@@ -135,7 +135,7 @@ real::operator double() const | |||
/* | |||
* Create a real number from an ASCII representation | |||
*/ | |||
real::real(char const *str) | |||
template<> real::Real(char const *str) | |||
{ | |||
real ret = 0; | |||
int exponent = 0; | |||
@@ -192,19 +192,19 @@ real::real(char const *str) | |||
new(this) real(ret); | |||
} | |||
real real::operator +() const | |||
template<> real real::operator +() const | |||
{ | |||
return *this; | |||
} | |||
real real::operator -() const | |||
template<> real real::operator -() const | |||
{ | |||
real ret = *this; | |||
ret.m_signexp ^= 0x80000000u; | |||
return ret; | |||
} | |||
real real::operator +(real const &x) const | |||
template<> real real::operator +(real const &x) const | |||
{ | |||
if (x.m_signexp << 1 == 0) | |||
return *this; | |||
@@ -268,7 +268,7 @@ real real::operator +(real const &x) const | |||
return ret; | |||
} | |||
real real::operator -(real const &x) const | |||
template<> real real::operator -(real const &x) const | |||
{ | |||
if (x.m_signexp << 1 == 0) | |||
return *this; | |||
@@ -372,7 +372,7 @@ real real::operator -(real const &x) const | |||
return ret; | |||
} | |||
real real::operator *(real const &x) const | |||
template<> real real::operator *(real const &x) const | |||
{ | |||
real ret; | |||
@@ -445,36 +445,36 @@ real real::operator *(real const &x) const | |||
return ret; | |||
} | |||
real real::operator /(real const &x) const | |||
template<> real real::operator /(real const &x) const | |||
{ | |||
return *this * re(x); | |||
} | |||
real const &real::operator +=(real const &x) | |||
template<> real const &real::operator +=(real const &x) | |||
{ | |||
real tmp = *this; | |||
return *this = tmp + x; | |||
} | |||
real const &real::operator -=(real const &x) | |||
template<> real const &real::operator -=(real const &x) | |||
{ | |||
real tmp = *this; | |||
return *this = tmp - x; | |||
} | |||
real const &real::operator *=(real const &x) | |||
template<> real const &real::operator *=(real const &x) | |||
{ | |||
real tmp = *this; | |||
return *this = tmp * x; | |||
} | |||
real const &real::operator /=(real const &x) | |||
template<> real const &real::operator /=(real const &x) | |||
{ | |||
real tmp = *this; | |||
return *this = tmp / x; | |||
} | |||
bool real::operator ==(real const &x) const | |||
template<> bool real::operator ==(real const &x) const | |||
{ | |||
if ((m_signexp << 1) == 0 && (x.m_signexp << 1) == 0) | |||
return true; | |||
@@ -485,12 +485,12 @@ bool real::operator ==(real const &x) const | |||
return memcmp(m_mantissa, x.m_mantissa, BIGITS * sizeof(uint32_t)) == 0; | |||
} | |||
bool real::operator !=(real const &x) const | |||
template<> bool real::operator !=(real const &x) const | |||
{ | |||
return !(*this == x); | |||
} | |||
bool real::operator <(real const &x) const | |||
template<> bool real::operator <(real const &x) const | |||
{ | |||
/* Ensure both numbers are positive */ | |||
if (m_signexp >> 31) | |||
@@ -510,12 +510,12 @@ bool real::operator <(real const &x) const | |||
return false; | |||
} | |||
bool real::operator <=(real const &x) const | |||
template<> bool real::operator <=(real const &x) const | |||
{ | |||
return !(*this > x); | |||
} | |||
bool real::operator >(real const &x) const | |||
template<> bool real::operator >(real const &x) const | |||
{ | |||
/* Ensure both numbers are positive */ | |||
if (m_signexp >> 31) | |||
@@ -535,17 +535,17 @@ bool real::operator >(real const &x) const | |||
return false; | |||
} | |||
bool real::operator >=(real const &x) const | |||
template<> bool real::operator >=(real const &x) const | |||
{ | |||
return !(*this < x); | |||
} | |||
bool real::operator !() const | |||
template<> bool real::operator !() const | |||
{ | |||
return !(bool)*this; | |||
} | |||
real::operator bool() const | |||
template<> real::operator bool() const | |||
{ | |||
/* A real is "true" if it is non-zero (exponent is non-zero) AND | |||
* not NaN (exponent is not full bits OR higher order mantissa is zero) */ | |||
@@ -553,7 +553,7 @@ real::operator bool() const | |||
return exponent && (~exponent || m_mantissa[0] == 0); | |||
} | |||
real re(real const &x) | |||
template<> real re(real const &x) | |||
{ | |||
if (!(x.m_signexp << 1)) | |||
{ | |||
@@ -586,7 +586,7 @@ real re(real const &x) | |||
return ret; | |||
} | |||
real sqrt(real const &x) | |||
template<> real sqrt(real const &x) | |||
{ | |||
/* if zero, return x */ | |||
if (!(x.m_signexp << 1)) | |||
@@ -633,7 +633,7 @@ real sqrt(real const &x) | |||
return ret * x; | |||
} | |||
real cbrt(real const &x) | |||
template<> real cbrt(real const &x) | |||
{ | |||
/* if zero, return x */ | |||
if (!(x.m_signexp << 1)) | |||
@@ -670,7 +670,7 @@ real cbrt(real const &x) | |||
return ret; | |||
} | |||
real pow(real const &x, real const &y) | |||
template<> real pow(real const &x, real const &y) | |||
{ | |||
if (!y) | |||
return real::R_1; | |||
@@ -719,7 +719,7 @@ static real fast_fact(int x) | |||
} | |||
} | |||
real gamma(real const &x) | |||
template<> real gamma(real const &x) | |||
{ | |||
/* We use Spouge's formula. FIXME: precision is far from acceptable, | |||
* especially with large values. We need to compute this with higher | |||
@@ -746,7 +746,7 @@ real gamma(real const &x) | |||
return ret; | |||
} | |||
real fabs(real const &x) | |||
template<> real fabs(real const &x) | |||
{ | |||
real ret = x; | |||
ret.m_signexp &= 0x7fffffffu; | |||
@@ -786,7 +786,7 @@ static real fast_log(real const &x) | |||
return z * sum * 4; | |||
} | |||
real log(real const &x) | |||
template<> real log(real const &x) | |||
{ | |||
/* Strategy for log(x): if x = 2^E*M then log(x) = E log(2) + log(M), | |||
* with the property that M is in [1..2[, so fast_log() applies here. */ | |||
@@ -802,7 +802,7 @@ real log(real const &x) | |||
+ fast_log(tmp); | |||
} | |||
real log2(real const &x) | |||
template<> real log2(real const &x) | |||
{ | |||
/* Strategy for log2(x): see log(x). */ | |||
real tmp = x; | |||
@@ -817,7 +817,7 @@ real log2(real const &x) | |||
+ fast_log(tmp) * real::R_LOG2E; | |||
} | |||
real log10(real const &x) | |||
template<> real log10(real const &x) | |||
{ | |||
return log(x) * real::R_LOG10E; | |||
} | |||
@@ -843,7 +843,7 @@ static real fast_exp_sub(real const &x, real const &y) | |||
return ret / fast_fact(i); | |||
} | |||
real exp(real const &x) | |||
template<> real exp(real const &x) | |||
{ | |||
/* Strategy for exp(x): the Taylor series does not converge very fast | |||
* with large positive or negative values. | |||
@@ -868,7 +868,7 @@ real exp(real const &x) | |||
return x1; | |||
} | |||
real exp2(real const &x) | |||
template<> real exp2(real const &x) | |||
{ | |||
/* Strategy for exp2(x): see strategy in exp(). */ | |||
int e0 = x; | |||
@@ -878,7 +878,7 @@ real exp2(real const &x) | |||
return x1; | |||
} | |||
real sinh(real const &x) | |||
template<> real sinh(real const &x) | |||
{ | |||
/* We cannot always use (exp(x)-exp(-x))/2 because we'll lose | |||
* accuracy near zero. We only use this identity for |x|>0.5. If | |||
@@ -889,7 +889,7 @@ real sinh(real const &x) | |||
return (x1 - x2) / 2; | |||
} | |||
real tanh(real const &x) | |||
template<> real tanh(real const &x) | |||
{ | |||
/* See sinh() for the strategy here */ | |||
bool near_zero = (fabs(x) < real::R_1 / 2); | |||
@@ -899,14 +899,14 @@ real tanh(real const &x) | |||
return (x1 - x2) / x3; | |||
} | |||
real cosh(real const &x) | |||
template<> real cosh(real const &x) | |||
{ | |||
/* No need to worry about accuracy here; maybe the last bit is slightly | |||
* off, but that's about it. */ | |||
return (exp(x) + exp(-x)) / 2; | |||
} | |||
real frexp(real const &x, int *exp) | |||
template<> real frexp(real const &x, int *exp) | |||
{ | |||
if (!x) | |||
{ | |||
@@ -921,7 +921,7 @@ real frexp(real const &x, int *exp) | |||
return ret; | |||
} | |||
real ldexp(real const &x, int exp) | |||
template<> real ldexp(real const &x, int exp) | |||
{ | |||
real ret = x; | |||
if (ret) | |||
@@ -929,7 +929,7 @@ real ldexp(real const &x, int exp) | |||
return ret; | |||
} | |||
real modf(real const &x, real *iptr) | |||
template<> real modf(real const &x, real *iptr) | |||
{ | |||
real absx = fabs(x); | |||
real tmp = floor(absx); | |||
@@ -938,7 +938,7 @@ real modf(real const &x, real *iptr) | |||
return copysign(absx - tmp, x); | |||
} | |||
real ulp(real const &x) | |||
template<> real ulp(real const &x) | |||
{ | |||
real ret = real::R_1; | |||
if (x) | |||
@@ -948,7 +948,7 @@ real ulp(real const &x) | |||
return ret; | |||
} | |||
real nextafter(real const &x, real const &y) | |||
template<> real nextafter(real const &x, real const &y) | |||
{ | |||
if (x == y) | |||
return x; | |||
@@ -958,7 +958,7 @@ real nextafter(real const &x, real const &y) | |||
return x - ulp(x); | |||
} | |||
real copysign(real const &x, real const &y) | |||
template<> real copysign(real const &x, real const &y) | |||
{ | |||
real ret = x; | |||
ret.m_signexp &= 0x7fffffffu; | |||
@@ -966,7 +966,7 @@ real copysign(real const &x, real const &y) | |||
return ret; | |||
} | |||
real floor(real const &x) | |||
template<> real floor(real const &x) | |||
{ | |||
/* Strategy for floor(x): | |||
* - if negative, return -ceil(-x) | |||
@@ -997,7 +997,7 @@ real floor(real const &x) | |||
return ret; | |||
} | |||
real ceil(real const &x) | |||
template<> real ceil(real const &x) | |||
{ | |||
/* Strategy for ceil(x): | |||
* - if negative, return -floor(-x) | |||
@@ -1012,7 +1012,7 @@ real ceil(real const &x) | |||
return ret + real::R_1; | |||
} | |||
real round(real const &x) | |||
template<> real round(real const &x) | |||
{ | |||
if (x < real::R_0) | |||
return -round(-x); | |||
@@ -1020,7 +1020,7 @@ real round(real const &x) | |||
return floor(x + (real::R_1 / 2)); | |||
} | |||
real fmod(real const &x, real const &y) | |||
template<> real fmod(real const &x, real const &y) | |||
{ | |||
if (!y) | |||
return real::R_0; /* FIXME: return NaN */ | |||
@@ -1032,7 +1032,7 @@ real fmod(real const &x, real const &y) | |||
return x - tmp * y; | |||
} | |||
real sin(real const &x) | |||
template<> real sin(real const &x) | |||
{ | |||
int switch_sign = x.m_signexp & 0x80000000u; | |||
@@ -1065,12 +1065,12 @@ real sin(real const &x) | |||
return ret; | |||
} | |||
real cos(real const &x) | |||
template<> real cos(real const &x) | |||
{ | |||
return sin(real::R_PI_2 - x); | |||
} | |||
real tan(real const &x) | |||
template<> real tan(real const &x) | |||
{ | |||
/* Constrain input to [-π,π] */ | |||
real y = fmod(x, real::R_PI); | |||
@@ -1137,17 +1137,17 @@ static inline real asinacos(real const &x, int is_asin, int is_negative) | |||
return ret; | |||
} | |||
real asin(real const &x) | |||
template<> real asin(real const &x) | |||
{ | |||
return asinacos(x, 1, x.m_signexp >> 31); | |||
} | |||
real acos(real const &x) | |||
template<> real acos(real const &x) | |||
{ | |||
return asinacos(x, 0, x.m_signexp >> 31); | |||
} | |||
real atan(real const &x) | |||
template<> real atan(real const &x) | |||
{ | |||
/* Computing atan(x): we choose a different Taylor series depending on | |||
* the value of x to help with convergence. | |||
@@ -1250,7 +1250,7 @@ real atan(real const &x) | |||
return ret; | |||
} | |||
real atan2(real const &y, real const &x) | |||
template<> real atan2(real const &y, real const &x) | |||
{ | |||
if (!y) | |||
{ | |||
@@ -1276,7 +1276,7 @@ real atan2(real const &y, real const &x) | |||
return ret; | |||
} | |||
void real::hexprint() const | |||
template<> void real::hexprint() const | |||
{ | |||
printf("%08x", m_signexp); | |||
for (int i = 0; i < BIGITS; i++) | |||
@@ -1284,7 +1284,7 @@ void real::hexprint() const | |||
printf("\n"); | |||
} | |||
void real::print(int ndigits) const | |||
template<> void real::print(int ndigits) const | |||
{ | |||
real x = *this; | |||
@@ -1350,11 +1350,11 @@ static real fast_pi() | |||
return ret; | |||
} | |||
real const real::R_0 = (real)0.0; | |||
real const real::R_1 = (real)1.0; | |||
real const real::R_2 = (real)2.0; | |||
real const real::R_3 = (real)3.0; | |||
real const real::R_10 = (real)10.0; | |||
template<> real const real::R_0 = (real)0.0; | |||
template<> real const real::R_1 = (real)1.0; | |||
template<> real const real::R_2 = (real)2.0; | |||
template<> real const real::R_3 = (real)3.0; | |||
template<> real const real::R_10 = (real)10.0; | |||
/* | |||
* Initialisation order is important here: | |||
@@ -1364,21 +1364,21 @@ real const real::R_10 = (real)10.0; | |||
* - 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); | |||
real const real::R_LOG10E = re(R_LN10); | |||
real const real::R_E = exp(R_1); | |||
real const real::R_PI = fast_pi(); | |||
real const real::R_PI_2 = R_PI / 2; | |||
real const real::R_PI_3 = R_PI / R_3; | |||
real const real::R_PI_4 = R_PI / 4; | |||
real const real::R_1_PI = re(R_PI); | |||
real const real::R_2_PI = R_1_PI * 2; | |||
real const real::R_2_SQRTPI = re(sqrt(R_PI)) * 2; | |||
real const real::R_SQRT2 = sqrt(R_2); | |||
real const real::R_SQRT3 = sqrt(R_3); | |||
real const real::R_SQRT1_2 = R_SQRT2 / 2; | |||
template<> real const real::R_LN2 = fast_log(R_2); | |||
template<> real const real::R_LN10 = log(R_10); | |||
template<> real const real::R_LOG2E = re(R_LN2); | |||
template<> real const real::R_LOG10E = re(R_LN10); | |||
template<> real const real::R_E = exp(R_1); | |||
template<> real const real::R_PI = fast_pi(); | |||
template<> real const real::R_PI_2 = R_PI / 2; | |||
template<> real const real::R_PI_3 = R_PI / R_3; | |||
template<> real const real::R_PI_4 = R_PI / 4; | |||
template<> real const real::R_1_PI = re(R_PI); | |||
template<> real const real::R_2_PI = R_1_PI * 2; | |||
template<> real const real::R_2_SQRTPI = re(sqrt(R_PI)) * 2; | |||
template<> real const real::R_SQRT2 = sqrt(R_2); | |||
template<> real const real::R_SQRT3 = sqrt(R_3); | |||
template<> real const real::R_SQRT1_2 = R_SQRT2 / 2; | |||
} /* namespace lol */ | |||
@@ -24,6 +24,8 @@ LOLUNIT_FIXTURE(TrigTest) | |||
{ | |||
LOLUNIT_TEST(Sin) | |||
{ | |||
using std::fabs; | |||
for (int i = -10000; i < 10000; i++) | |||
{ | |||
double f = (double)i * (1.0 / 1000.0); | |||
@@ -34,7 +36,7 @@ LOLUNIT_FIXTURE(TrigTest) | |||
#endif | |||
double b = lol_sin(f); | |||
LOLUNIT_SET_CONTEXT(f); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, std::fabs(f) * 1e-11); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, fabs(f) * 1e-11); | |||
} | |||
for (int i = -10000; i < 10000; i++) | |||
@@ -47,12 +49,14 @@ LOLUNIT_FIXTURE(TrigTest) | |||
#endif | |||
double b = lol_sin(f); | |||
LOLUNIT_SET_CONTEXT(f); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, std::fabs(f) * 1e-11); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, fabs(f) * 1e-11); | |||
} | |||
} | |||
LOLUNIT_TEST(Cos) | |||
{ | |||
using std::fabs; | |||
for (int i = -10000; i < 10000; i++) | |||
{ | |||
double f = (double)i * (1.0 / 1000.0); | |||
@@ -63,7 +67,7 @@ LOLUNIT_FIXTURE(TrigTest) | |||
#endif | |||
double b = lol_cos(f); | |||
LOLUNIT_SET_CONTEXT(f); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, std::fabs(f) * 1e-11); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, fabs(f) * 1e-11); | |||
} | |||
for (int i = -10000; i < 10000; i++) | |||
@@ -76,12 +80,14 @@ LOLUNIT_FIXTURE(TrigTest) | |||
#endif | |||
double b = lol_cos(f); | |||
LOLUNIT_SET_CONTEXT(f); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, std::fabs(f) * 1e-11); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, fabs(f) * 1e-11); | |||
} | |||
} | |||
LOLUNIT_TEST(SinCos) | |||
{ | |||
using std::fabs; | |||
for (int i = -10000; i < 10000; i++) | |||
{ | |||
double f = (double)i * (1.0 / 1000.0); | |||
@@ -95,8 +101,8 @@ LOLUNIT_FIXTURE(TrigTest) | |||
double b1, b2; | |||
lol_sincos(f, &b1, &b2); | |||
LOLUNIT_SET_CONTEXT(f); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a1, b1, std::fabs(f) * 1e-11); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a2, b2, std::fabs(f) * 1e-11); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a1, b1, fabs(f) * 1e-11); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a2, b2, fabs(f) * 1e-11); | |||
} | |||
for (int i = -10000; i < 10000; i++) | |||
@@ -112,13 +118,15 @@ LOLUNIT_FIXTURE(TrigTest) | |||
double b1, b2; | |||
lol_sincos(f, &b1, &b2); | |||
LOLUNIT_SET_CONTEXT(f); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a1, b1, std::fabs(f) * 1e-11); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a2, b2, std::fabs(f) * 1e-11); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a1, b1, fabs(f) * 1e-11); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a2, b2, fabs(f) * 1e-11); | |||
} | |||
} | |||
LOLUNIT_TEST(Tan) | |||
{ | |||
using std::fabs; | |||
for (int i = -100000; i < 100000; i++) | |||
{ | |||
double f = (double)i * (1.0 / 10000.0); | |||
@@ -129,12 +137,12 @@ LOLUNIT_FIXTURE(TrigTest) | |||
#endif | |||
double b = lol_tan(f); | |||
LOLUNIT_SET_CONTEXT(f); | |||
if (std::fabs(a) > 1e4) | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, std::fabs(a) * std::fabs(a) * 1e-11); | |||
else if (std::fabs(a) > 1.0) | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, std::fabs(a) * 1e-11); | |||
if (fabs(a) > 1e4) | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, fabs(a) * fabs(a) * 1e-11); | |||
else if (fabs(a) > 1.0) | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, fabs(a) * 1e-11); | |||
else | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, std::fabs(f) * 1e-11); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, fabs(f) * 1e-11); | |||
} | |||
for (int i = -10000; i < 10000; i++) | |||
@@ -147,12 +155,12 @@ LOLUNIT_FIXTURE(TrigTest) | |||
#endif | |||
double b = lol_tan(f); | |||
LOLUNIT_SET_CONTEXT(f); | |||
if (std::fabs(a) > 1e4) | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, std::fabs(a) * std::fabs(a) * 1e-11); | |||
else if (std::fabs(a) > 1.0) | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, std::fabs(a) * 1e-11); | |||
if (fabs(a) > 1e4) | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, fabs(a) * fabs(a) * 1e-11); | |||
else if (fabs(a) > 1.0) | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, fabs(a) * 1e-11); | |||
else | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, std::fabs(f) * 1e-11); | |||
LOLUNIT_ASSERT_DOUBLES_EQUAL(a, b, fabs(f) * 1e-11); | |||
} | |||
} | |||
}; | |||