source: trunk/src/lol/math/real.h @ 1382

Last change on this file since 1382 was 1382, checked in by sam, 8 years ago

math: workaround for an apparent Visual Studio compiler bug in
template specialisation order.

  • Property svn:keywords set to Id
File size: 10.7 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11//
12// The Real class
13// --------------
14//
15
16#if !defined __LOL_MATH_REAL_H__
17#define __LOL_MATH_REAL_H__
18
19#include <stdint.h>
20
21namespace lol
22{
23
24/* This is OUR namespace. Don't let Windows headers fuck with it. */
25#undef min
26#undef max
27
28/* Avoid issues with NaCl headers */
29#undef log2
30
31/*
32 * The base class for reals. The only real reason for making this a template
33 * class is so we can have implicit constructors ("real x = 1" works) but
34 * avoid accidental implicit conversions ("int x = 1; sqrt(x)" will never
35 * call real::sqrt).
36 */
37template<int N> class Real
38{
39public:
40    Real();
41    Real(Real<N> const &x);
42    Real const &operator =(Real<N> const &x);
43    ~Real();
44
45    Real(float f);
46    Real(double f);
47    Real(int i);
48    Real(unsigned int i);
49
50    Real(char const *str);
51
52    operator float() const;
53    operator double() const;
54    operator int() const;
55    operator unsigned int() const;
56
57    Real<N> operator +() const;
58    Real<N> operator -() const;
59    Real<N> operator +(Real<N> const &x) const;
60    Real<N> operator -(Real<N> const &x) const;
61    Real<N> operator *(Real<N> const &x) const;
62    Real<N> operator /(Real<N> const &x) const;
63    Real<N> const &operator +=(Real<N> const &x);
64    Real<N> const &operator -=(Real<N> const &x);
65    Real<N> const &operator *=(Real<N> const &x);
66    Real<N> const &operator /=(Real<N> const &x);
67
68    bool operator ==(Real<N> const &x) const;
69    bool operator !=(Real<N> const &x) const;
70    bool operator <(Real<N> const &x) const;
71    bool operator >(Real<N> const &x) const;
72    bool operator <=(Real<N> const &x) const;
73    bool operator >=(Real<N> const &x) const;
74
75    bool operator !() const;
76    operator bool() const;
77
78    /* Comparison functions */
79    template<int M> friend Real<M> min(Real<M> const &a, Real<M> const &b);
80    template<int M> friend Real<M> max(Real<M> const &a, Real<M> const &b);
81    template<int M> friend Real<M> clamp(Real<M> const &x,
82                                         Real<M> const &a, Real<M> const &b);
83
84    /* Trigonometric functions */
85    template<int M> friend Real<M> sin(Real<M> const &x);
86    template<int M> friend Real<M> cos(Real<M> const &x);
87    template<int M> friend Real<M> tan(Real<M> const &x);
88    template<int M> friend Real<M> asin(Real<M> const &x);
89    template<int M> friend Real<M> acos(Real<M> const &x);
90    template<int M> friend Real<M> atan(Real<M> const &x);
91    template<int M> friend Real<M> atan2(Real<M> const &y, Real<M> const &x);
92
93    /* Hyperbolic functions */
94    template<int M> friend Real<M> sinh(Real<M> const &x);
95    template<int M> friend Real<M> cosh(Real<M> const &x);
96    template<int M> friend Real<M> tanh(Real<M> const &x);
97
98    /* Exponential and logarithmic functions */
99    template<int M> friend Real<M> exp(Real<M> const &x);
100    template<int M> friend Real<M> exp2(Real<M> const &x);
101    template<int M> friend Real<M> log(Real<M> const &x);
102    template<int M> friend Real<M> log2(Real<M> const &x);
103    template<int M> friend Real<M> log10(Real<M> const &x);
104    template<int M> friend Real<M> frexp(Real<M> const &x, int *exp);
105    template<int M> friend Real<M> ldexp(Real<M> const &x, int exp);
106    template<int M> friend Real<M> modf(Real<M> const &x, Real<M> *iptr);
107    template<int M> friend Real<M> ulp(Real<M> const &x);
108    template<int M> friend Real<M> nextafter(Real<M> const &x, Real<M> const &y);
109
110    /* Power functions */
111    template<int M> friend Real<M> re(Real<M> const &x);
112    template<int M> friend Real<M> sqrt(Real<M> const &x);
113    template<int M> friend Real<M> cbrt(Real<M> const &x);
114    template<int M> friend Real<M> pow(Real<M> const &x, Real<M> const &y);
115    template<int M> friend Real<M> gamma(Real<M> const &x);
116
117    /* Rounding, absolute value, remainder etc. */
118    template<int M> friend Real<M> ceil(Real<M> const &x);
119    template<int M> friend Real<M> copysign(Real<M> const &x, Real<M> const &y);
120    template<int M> friend Real<M> floor(Real<M> const &x);
121    template<int M> friend Real<M> fabs(Real<M> const &x);
122    template<int M> friend Real<M> round(Real<M> const &x);
123    template<int M> friend Real<M> fmod(Real<M> const &x, Real<N> const &y);
124
125    void hexprint() const;
126    void print(int ndigits = 150) const;
127
128    /* Additional operators using base C++ types */
129#define __LOL_REAL_OP_HELPER_GENERIC(op, type) \
130    inline Real<N> operator op(type x) const { return *this op (Real<N>)x; } \
131    inline Real<N> const &operator op##=(type x) { return *this = (*this op x); }
132#define __LOL_REAL_OP_HELPER_FASTMULDIV(op, type) \
133    inline Real<N> operator op(type x) const \
134    { \
135        Real<N> tmp = *this; return tmp op##= x; \
136    } \
137    inline Real<N> const &operator op##=(type x) \
138    { \
139        /* If multiplying or dividing by a power of two, take a shortcut */ \
140        if ((m_signexp << 1) && x && !(x & (x - 1))) \
141        { \
142            while (x >>= 1) \
143                m_signexp += 1 op 2 - 1; /* 1 if op is *, -1 if op is / */ \
144        } \
145        else \
146            *this = *this op (Real<N>)x; \
147        return *this; \
148    }
149#define __LOL_REAL_OP_HELPER_INT(type) \
150    __LOL_REAL_OP_HELPER_GENERIC(+, type) \
151    __LOL_REAL_OP_HELPER_GENERIC(-, type) \
152    __LOL_REAL_OP_HELPER_FASTMULDIV(*, type) \
153    __LOL_REAL_OP_HELPER_FASTMULDIV(/, type)
154#define __LOL_REAL_OP_HELPER_FLOAT(type) \
155    __LOL_REAL_OP_HELPER_GENERIC(+, type) \
156    __LOL_REAL_OP_HELPER_GENERIC(-, type) \
157    __LOL_REAL_OP_HELPER_GENERIC(*, type) \
158    __LOL_REAL_OP_HELPER_GENERIC(/, type)
159
160    __LOL_REAL_OP_HELPER_INT(int)
161    __LOL_REAL_OP_HELPER_INT(unsigned int)
162    __LOL_REAL_OP_HELPER_FLOAT(float)
163    __LOL_REAL_OP_HELPER_FLOAT(double)
164
165    /* Constants */
166    static Real<N> const R_0;
167    static Real<N> const R_1;
168    static Real<N> const R_2;
169    static Real<N> const R_3;
170    static Real<N> const R_10;
171
172    static Real<N> const R_E;
173    static Real<N> const R_LOG2E;
174    static Real<N> const R_LOG10E;
175    static Real<N> const R_LN2;
176    static Real<N> const R_LN10;
177    static Real<N> const R_PI;
178    static Real<N> const R_PI_2;
179    static Real<N> const R_PI_3;
180    static Real<N> const R_PI_4;
181    static Real<N> const R_1_PI;
182    static Real<N> const R_2_PI;
183    static Real<N> const R_2_SQRTPI;
184    static Real<N> const R_SQRT2;
185    static Real<N> const R_SQRT3;
186    static Real<N> const R_SQRT1_2;
187
188    /* XXX: changing this requires tuning real::fres (the number of
189     * Newton-Raphson iterations) and real::print (the number of printed
190     * digits) */
191    static int const BIGITS = N;
192    static int const BIGIT_BITS = 32;
193
194private:
195    uint32_t *m_mantissa;
196    uint32_t m_signexp;
197};
198
199/*
200 * The real type used for real numbers
201 */
202typedef Real<16> real;
203
204/*
205 * Mandatory forward declarations of template specialisations
206 */
207template<> real::Real();
208template<> real::Real(real const &x);
209template<> real const &real::operator =(real const &x);
210template<> real::~Real();
211template<> real::Real(float f);
212template<> real::Real(double f);
213template<> real::Real(int i);
214template<> real::Real(unsigned int i);
215template<> real::Real(char const *str);
216
217template<> real::operator float() const;
218template<> real::operator double() const;
219template<> real::operator int() const;
220template<> real::operator unsigned int() const;
221template<> real real::operator +() const;
222template<> real real::operator -() const;
223template<> real real::operator +(real const &x) const;
224template<> real real::operator -(real const &x) const;
225template<> real real::operator *(real const &x) const;
226template<> real real::operator /(real const &x) const;
227template<> real const &real::operator +=(real const &x);
228template<> real const &real::operator -=(real const &x);
229template<> real const &real::operator *=(real const &x);
230template<> real const &real::operator /=(real const &x);
231template<> bool real::operator ==(real const &x) const;
232template<> bool real::operator !=(real const &x) const;
233template<> bool real::operator <(real const &x) const;
234template<> bool real::operator >(real const &x) const;
235template<> bool real::operator <=(real const &x) const;
236template<> bool real::operator >=(real const &x) const;
237template<> bool real::operator !() const;
238template<> real::operator bool() const;
239
240template<> real min(real const &a, real const &b);
241template<> real max(real const &a, real const &b);
242template<> real clamp(real const &x, real const &a, real const &b);
243
244template<> real sin(real const &x);
245template<> real cos(real const &x);
246template<> real tan(real const &x);
247template<> real asin(real const &x);
248template<> real acos(real const &x);
249template<> real atan(real const &x);
250template<> real atan2(real const &y, real const &x);
251template<> real sinh(real const &x);
252template<> real cosh(real const &x);
253template<> real tanh(real const &x);
254template<> real exp(real const &x);
255template<> real exp2(real const &x);
256template<> real log(real const &x);
257template<> real log2(real const &x);
258template<> real log10(real const &x);
259template<> real frexp(real const &x, int *exp);
260template<> real ldexp(real const &x, int exp);
261template<> real modf(real const &x, real *iptr);
262template<> real ulp(real const &x);
263template<> real nextafter(real const &x, real const &y);
264template<> real re(real const &x);
265template<> real sqrt(real const &x);
266template<> real cbrt(real const &x);
267template<> real pow(real const &x, real const &y);
268template<> real gamma(real const &x);
269template<> real ceil(real const &x);
270template<> real copysign(real const &x, real const &y);
271template<> real floor(real const &x);
272template<> real fabs(real const &x);
273template<> real round(real const &x);
274template<> real fmod(real const &x, real const &y);
275
276template<> void real::hexprint() const;
277template<> void real::print(int ndigits) const;
278
279/* FIXME: why doesn't this work on Visual Studio? */
280#if !defined _MSC_VER
281template<> real const real::R_0;
282template<> real const real::R_1;
283template<> real const real::R_2;
284template<> real const real::R_3;
285template<> real const real::R_10;
286
287template<> real const real::R_LN2;
288template<> real const real::R_LN10;
289template<> real const real::R_LOG2E;
290template<> real const real::R_LOG10E;
291template<> real const real::R_E;
292template<> real const real::R_PI;
293template<> real const real::R_PI_2;
294template<> real const real::R_PI_3;
295template<> real const real::R_PI_4;
296template<> real const real::R_1_PI;
297template<> real const real::R_2_PI;
298template<> real const real::R_2_SQRTPI;
299template<> real const real::R_SQRT2;
300template<> real const real::R_SQRT3;
301template<> real const real::R_SQRT1_2;
302#endif
303
304} /* namespace lol */
305
306#endif // __LOL_MATH_REAL_H__
307
Note: See TracBrowser for help on using the repository browser.