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); | |||
| } | |||
| } | |||
| }; | |||