]> git.localhorst.tv Git - l2e.git/blob - src/math/Fixed.h
7fe099cee57ea789f0cc631f9397c89da6165e94
[l2e.git] / src / math / Fixed.h
1 #ifndef MATH_FIXED_H_
2 #define MATH_FIXED_H_
3
4 #include "utility.h"
5
6 #include <cmath>
7 #include <limits>
8 #include <ostream>
9 #include <SDL.h>
10
11
12 namespace math {
13
14 /// Fixed point number type.
15 /// The first bit is used for the sign (0 = positive, 1 = negative), the last
16 /// fracBits bits are used for the fractional part and the remaining middle
17 /// bits represent the integer value.
18 /// The sign bit of zero is undefined.
19 template<Uint8 fracBits>
20 class Fixed {
21
22 template<Uint8>
23 friend class Fixed;
24
25 public:
26         /// Create a fixed point decimal representing i/f .
27         Fixed(Sint32 i = 0, Uint32 f = 1)
28         : rep(((i < 0 ? (i * -1) : i) << IntShift()) & IntMask()) {
29                 rep /= f;
30                 if (i < 0) {
31                         rep |= SignMask();
32                 }
33         }
34         explicit Fixed(double d)
35         : rep(0) {
36                 rep = std::abs(d) * (1 << IntShift());
37                 if (d < 0) {
38                         rep |= SignMask();
39                 }
40         }
41         template<Uint8 otherFrac>
42         explicit Fixed(const Fixed<otherFrac> &other)
43         : rep(0) {
44                 Uint32 otherInt = other.RawInt();
45                 rep = DistanceShift(otherInt, fracBits, otherFrac);
46                 if (other.Sigma() < 0) {
47                         rep |= SignMask();
48                 }
49         }
50
51 public:
52         int Int() const { return IntPart() * Sigma(); }
53         int Sigma() const {
54                 if (IntPart() == 0 && FracPart() == 0) {
55                         return 0;
56                 } else if (SignPart() == 0) {
57                         return 1;
58                 } else {
59                         return -1;
60                 }
61         }
62         double Double() const { return double(SignedInt()) / (1 << IntShift()); }
63
64 public:
65         bool operator ==(const Fixed &other) const {
66                 return rep == other.rep;
67         }
68         bool operator !=(const Fixed &other) const {
69                 return rep != other.rep;
70         }
71         bool operator <(const Fixed &other) const {
72                 return SignedInt() < other.SignedInt();
73         }
74         bool operator <=(const Fixed &other) const {
75                 return SignedInt() <= other.SignedInt();
76         }
77         bool operator >(const Fixed &other) const {
78                 return SignedInt() > other.SignedInt();
79         }
80         bool operator >=(const Fixed &other) const {
81                 return SignedInt() >= other.SignedInt();
82         }
83
84         Fixed operator -() const {
85                 Fixed neg;
86                 neg.rep = rep ^ SignMask();
87                 return neg;
88         }
89
90         Fixed &operator +=(const Fixed &other) {
91                 Sint32 temp = SignedInt() + other.SignedInt();
92                 if (temp < 0) {
93                         rep = (temp * -1) | SignMask();
94                 } else {
95                         rep = temp;
96                 }
97                 return *this;
98         }
99         template<class Scalar>
100         Fixed &operator +=(Scalar i) {
101                 Sint32 temp = SignedInt() + (i << IntShift());
102                 if (temp < 0) {
103                         rep = (temp * -1) | SignMask();
104                 } else {
105                         rep = temp;
106                 }
107                 return *this;
108         }
109         Fixed &operator -=(const Fixed &other) {
110                 Sint32 temp = SignedInt() - other.SignedInt();
111                 if (temp < 0) {
112                         rep = (temp * -1) | SignMask();
113                 } else {
114                         rep = temp;
115                 }
116                 return *this;
117         }
118         template<class Scalar>
119         Fixed &operator -=(Scalar i) {
120                 Sint32 temp = SignedInt() - (i << IntShift());
121                 if (temp < 0) {
122                         rep = (temp * -1) | SignMask();
123                 } else {
124                         rep = temp;
125                 }
126                 return *this;
127         }
128         Fixed &operator *=(const Fixed &other) {
129                 Sint64 temp = SignedInt();
130                 temp *= other.SignedInt();
131                 temp /= (1 << IntShift());
132                 if (temp < 0) {
133                         rep = (temp * -1) | SignMask();
134                 } else {
135                         rep = temp;
136                 }
137                 return *this;
138         }
139         template<class Scalar>
140         Fixed &operator *=(Scalar i) {
141                 Sint32 temp = SignedInt() * i;
142                 if (temp < 0) {
143                         rep = (temp * -1) | SignMask();
144                 } else {
145                         rep = temp;
146                 }
147                 return *this;
148         }
149         Fixed &operator /=(const Fixed &other) {
150                 Sint64 temp = SignedInt();
151                 temp *= (1 << IntShift());
152                 temp /= other.SignedInt();
153                 if (temp < 0) {
154                         rep = (temp * -1) | SignMask();
155                 } else {
156                         rep = temp;
157                 }
158                 return *this;
159         }
160         template<class Scalar>
161         Fixed &operator /=(Scalar i) {
162                 Sint32 temp = SignedInt() / i;
163                 if (temp < 0) {
164                         rep = (temp * -1) | SignMask();
165                 } else {
166                         rep = temp;
167                 }
168                 return *this;
169         }
170         Fixed &operator %=(const Fixed &other) {
171                 const Uint32 myRaw = RawInt();
172                 const Uint32 otherRaw = other.RawInt();
173                 const Uint32 intQuotient = myRaw / otherRaw;
174                 rep = (myRaw - (otherRaw  * intQuotient)) | (rep & SignMask());
175                 return *this;
176         }
177         Fixed &operator %=(int i) {
178                 const Uint32 myRaw = RawInt();
179                 const Uint32 otherRaw = (i << IntShift());
180                 const Uint32 intQuotient = myRaw / otherRaw;
181                 rep = (myRaw - (otherRaw  * intQuotient)) | (rep & SignMask());
182                 return *this;
183         }
184
185 private:
186         int SignBits() const { return 1; }
187         int IntBits() const { return 32 - SignBits() - FracBits(); }
188         int FracBits() const { return fracBits; }
189
190         int SignShift() const { return 31; }
191         int IntShift() const { return fracBits; }
192         int FracShift() const { return 0; }
193
194         Uint32 SignMask() const { return 1 << SignShift(); }
195         Uint32 IntMask() const { return ~(SignMask() | FracMask()); }
196         Uint32 FracMask() const { return (1 << IntShift()) - 1; }
197
198         int SignPart() const { return (rep & SignMask()) >> SignShift(); }
199         int IntPart() const { return (rep & IntMask()) >> IntShift(); }
200         int FracPart() const { return (rep & FracMask()) >> FracShift(); }
201
202         Sint32 SignedInt() const { return Sigma() * RawInt(); }
203         Uint32 RawInt() const { return rep & (~SignMask()); }
204
205 private:
206         Uint32 rep;
207
208 };
209
210
211 template<Uint8 T, Uint8 U>
212 inline bool operator ==(const Fixed<T> &lhs, const Fixed<U> &rhs) {
213         if (T < U) {
214                 return lhs == Fixed<T>(rhs);
215         } else {
216                 return Fixed<U>(lhs) == rhs;
217         }
218 }
219
220 template<Uint8 T, Uint8 U>
221 inline bool operator !=(const Fixed<T> &lhs, const Fixed<U> &rhs) {
222         return !(lhs == rhs);
223 }
224
225 template<Uint8 T, Uint8 U>
226 inline bool operator <(const Fixed<T> &lhs, const Fixed<U> &rhs) {
227         if (T < U) {
228                 return lhs < Fixed<T>(rhs);
229         } else {
230                 return Fixed<U>(lhs) < rhs;
231         }
232 }
233
234 template<Uint8 T, Uint8 U>
235 inline bool operator <=(const Fixed<T> &lhs, const Fixed<U> &rhs) {
236         if (T < U) {
237                 return lhs <= Fixed<T>(rhs);
238         } else {
239                 return Fixed<U>(lhs) <= rhs;
240         }
241 }
242
243 template<Uint8 T, Uint8 U>
244 inline bool operator >(const Fixed<T> &lhs, const Fixed<U> &rhs) {
245         return !(lhs <= rhs);
246 }
247
248 template<Uint8 T, Uint8 U>
249 inline bool operator >=(const Fixed<T> &lhs, const Fixed<U> &rhs) {
250         return !(lhs < rhs);
251 }
252
253 template<Uint8 T, Uint8 U>
254 inline Fixed<T> operator +(const Fixed<T> &lhs, const Fixed<U> &rhs) {
255         Fixed<T> temp(lhs);
256         return temp += rhs;
257 }
258 template<Uint8 T, class Other>
259 inline Fixed<T> operator +(const Fixed<T> &lhs, const Other &rhs) {
260         Fixed<T> temp(lhs);
261         return temp += rhs;
262 }
263 template<Uint8 T, class Other>
264 inline Fixed<T> operator +(const Other &lhs, const Fixed<T> &rhs) {
265         return rhs + lhs;
266 }
267
268 template<Uint8 T, Uint8 U>
269 inline Fixed<T> operator -(const Fixed<T> &lhs, const Fixed<U> &rhs) {
270         Fixed<T> temp(lhs);
271         return temp -= rhs;
272 }
273 template<Uint8 T, class Other>
274 inline Fixed<T> operator -(const Fixed<T> &lhs, const Other &rhs) {
275         Fixed<T> temp(lhs);
276         return temp -= rhs;
277 }
278 template<Uint8 T, class Other>
279 inline Fixed<T> operator -(const Other &lhs, const Fixed<T> &rhs) {
280         return lhs + -rhs;
281 }
282
283 template<Uint8 T, Uint8 U>
284 inline Fixed<T> operator *(const Fixed<T> &lhs, const Fixed<U> &rhs) {
285         Fixed<T> temp(lhs);
286         return temp *= rhs;
287 }
288 template<Uint8 T, class Other>
289 inline Fixed<T> operator *(const Fixed<T> &lhs, const Other &rhs) {
290         Fixed<T> temp(lhs);
291         return temp *= rhs;
292 }
293 template<Uint8 T, class Other>
294 inline Fixed<T> operator *(const Other &lhs, const Fixed<T> &rhs) {
295         return rhs * lhs;
296 }
297
298 template<Uint8 T, Uint8 U>
299 inline Fixed<T> operator /(const Fixed<T> &lhs, const Fixed<U> &rhs) {
300         Fixed<T> temp(lhs);
301         return temp /= rhs;
302 }
303 template<Uint8 T, class Other>
304 inline Fixed<T> operator /(const Fixed<T> &lhs, const Other &rhs) {
305         Fixed<T> temp(lhs);
306         return temp /= rhs;
307 }
308
309 template<Uint8 T, Uint8 U>
310 inline Fixed<T> operator %(const Fixed<T> &lhs, const Fixed<U> &rhs) {
311         Fixed<T> temp(lhs);
312         return temp %= rhs;
313 }
314 template<Uint8 T, class Other>
315 inline Fixed<T> operator %(const Fixed<T> &lhs, const Other &rhs) {
316         Fixed<T> temp(lhs);
317         return temp %= rhs;
318 }
319
320
321 template<Uint8 T>
322 inline std::ostream &operator <<(std::ostream &out, const Fixed<T> &f) {
323         return out << f.Double();
324 }
325
326 }
327
328
329 namespace std {
330
331 template <Uint8 fracBits>
332 class numeric_limits<math::Fixed<fracBits> > {
333
334 public:
335         static const bool is_specialized = true;
336         static math::Fixed<fracBits> min() throw() {
337                 return max() * -1;
338         }
339         static math::Fixed<fracBits> max() throw() {
340                 return math::Fixed<fracBits>(1 << (digits - fracBits) - 1)
341                                 + math::Fixed<fracBits>((1 << fracBits) - 2, (1 << fracBits) - 1);
342         }
343         static const int digits = 31;
344         static const int digits10 = 10;
345         static const bool is_signed = true;
346         static const bool is_integer = false;
347         static const bool is_exact = true;
348         static const int radix = 2;
349         static math::Fixed<fracBits> epsilon() throw() {
350                 return math::Fixed<fracBits>(1, 1 << (digits - fracBits) - 1);
351         }
352         static math::Fixed<fracBits> round_error() throw() {
353                 return epsilon();
354         }
355
356         static const bool is_iec559 = false;
357         static const bool is_bounded = true;
358         static const bool is_modulo = false;
359
360         static const bool traps = false;
361         static const bool tinyness_before = false;
362         static const float_round_style round_style = round_toward_zero;
363 };
364
365 }
366
367 #endif