]> git.localhorst.tv Git - l2e.git/blob - src/math/Fixed.h
a3982755dea86c8d147229fe0e19c33fb1caf2e4
[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         Fixed &operator +=(int i) {
100                 Sint32 temp = SignedInt() + (i << IntShift());
101                 if (temp < 0) {
102                         rep = (temp * -1) | SignMask();
103                 } else {
104                         rep = temp;
105                 }
106                 return *this;
107         }
108         Fixed &operator -=(const Fixed &other) {
109                 Sint32 temp = SignedInt() - other.SignedInt();
110                 if (temp < 0) {
111                         rep = (temp * -1) | SignMask();
112                 } else {
113                         rep = temp;
114                 }
115                 return *this;
116         }
117         Fixed &operator -=(int i) {
118                 Sint32 temp = SignedInt() - (i << IntShift());
119                 if (temp < 0) {
120                         rep = (temp * -1) | SignMask();
121                 } else {
122                         rep = temp;
123                 }
124                 return *this;
125         }
126         Fixed &operator *=(const Fixed &other) {
127                 Sint64 temp = SignedInt();
128                 temp *= other.SignedInt();
129                 temp /= (1 << IntShift());
130                 if (temp < 0) {
131                         rep = (temp * -1) | SignMask();
132                 } else {
133                         rep = temp;
134                 }
135                 return *this;
136         }
137         Fixed &operator *=(int i) {
138                 Sint32 temp = SignedInt() * i;
139                 if (temp < 0) {
140                         rep = (temp * -1) | SignMask();
141                 } else {
142                         rep = temp;
143                 }
144                 return *this;
145         }
146         Fixed &operator /=(const Fixed &other) {
147                 Sint64 temp = SignedInt();
148                 temp *= (1 << IntShift());
149                 temp /= other.SignedInt();
150                 if (temp < 0) {
151                         rep = (temp * -1) | SignMask();
152                 } else {
153                         rep = temp;
154                 }
155                 return *this;
156         }
157         Fixed &operator /=(int i) {
158                 Sint32 temp = SignedInt() / i;
159                 if (temp < 0) {
160                         rep = (temp * -1) | SignMask();
161                 } else {
162                         rep = temp;
163                 }
164                 return *this;
165         }
166         Fixed &operator %=(const Fixed &other) {
167                 const Uint32 myRaw = RawInt();
168                 const Uint32 otherRaw = other.RawInt();
169                 const Uint32 intQuotient = myRaw / otherRaw;
170                 rep = (myRaw - (otherRaw  * intQuotient)) | (rep & SignMask());
171                 return *this;
172         }
173         Fixed &operator %=(int i) {
174                 const Uint32 myRaw = RawInt();
175                 const Uint32 otherRaw = (i << IntShift());
176                 const Uint32 intQuotient = myRaw / otherRaw;
177                 rep = (myRaw - (otherRaw  * intQuotient)) | (rep & SignMask());
178                 return *this;
179         }
180
181 private:
182         int SignBits() const { return 1; }
183         int IntBits() const { return 32 - SignBits() - FracBits(); }
184         int FracBits() const { return fracBits; }
185
186         int SignShift() const { return 31; }
187         int IntShift() const { return fracBits; }
188         int FracShift() const { return 0; }
189
190         Uint32 SignMask() const { return 1 << SignShift(); }
191         Uint32 IntMask() const { return ~(SignMask() | FracMask()); }
192         Uint32 FracMask() const { return (1 << IntShift()) - 1; }
193
194         int SignPart() const { return (rep & SignMask()) >> SignShift(); }
195         int IntPart() const { return (rep & IntMask()) >> IntShift(); }
196         int FracPart() const { return (rep & FracMask()) >> FracShift(); }
197
198         Sint32 SignedInt() const { return Sigma() * RawInt(); }
199         Uint32 RawInt() const { return rep & (~SignMask()); }
200
201 private:
202         Uint32 rep;
203
204 };
205
206
207 template<Uint8 T, Uint8 U>
208 inline bool operator ==(const Fixed<T> &lhs, const Fixed<U> &rhs) {
209         if (T < U) {
210                 return lhs == Fixed<T>(rhs);
211         } else {
212                 return Fixed<U>(lhs) == rhs;
213         }
214 }
215
216 template<Uint8 T, Uint8 U>
217 inline bool operator !=(const Fixed<T> &lhs, const Fixed<U> &rhs) {
218         return !(lhs == rhs);
219 }
220
221 template<Uint8 T, Uint8 U>
222 inline bool operator <(const Fixed<T> &lhs, const Fixed<U> &rhs) {
223         if (T < U) {
224                 return lhs < Fixed<T>(rhs);
225         } else {
226                 return Fixed<U>(lhs) < rhs;
227         }
228 }
229
230 template<Uint8 T, Uint8 U>
231 inline bool operator <=(const Fixed<T> &lhs, const Fixed<U> &rhs) {
232         if (T < U) {
233                 return lhs <= Fixed<T>(rhs);
234         } else {
235                 return Fixed<U>(lhs) <= rhs;
236         }
237 }
238
239 template<Uint8 T, Uint8 U>
240 inline bool operator >(const Fixed<T> &lhs, const Fixed<U> &rhs) {
241         return !(lhs <= rhs);
242 }
243
244 template<Uint8 T, Uint8 U>
245 inline bool operator >=(const Fixed<T> &lhs, const Fixed<U> &rhs) {
246         return !(lhs < rhs);
247 }
248
249 template<Uint8 T, Uint8 U>
250 inline Fixed<T> operator +(const Fixed<T> &lhs, const Fixed<U> &rhs) {
251         Fixed<T> temp(lhs);
252         return temp += rhs;
253 }
254 template<Uint8 T, class Other>
255 inline Fixed<T> operator +(const Fixed<T> &lhs, const Other &rhs) {
256         Fixed<T> temp(lhs);
257         return temp += rhs;
258 }
259 template<Uint8 T, class Other>
260 inline Fixed<T> operator +(const Other &lhs, const Fixed<T> &rhs) {
261         return rhs + lhs;
262 }
263
264 template<Uint8 T, Uint8 U>
265 inline Fixed<T> operator -(const Fixed<T> &lhs, const Fixed<U> &rhs) {
266         Fixed<T> temp(lhs);
267         return temp -= rhs;
268 }
269 template<Uint8 T, class Other>
270 inline Fixed<T> operator -(const Fixed<T> &lhs, const Other &rhs) {
271         Fixed<T> temp(lhs);
272         return temp -= rhs;
273 }
274 template<Uint8 T, class Other>
275 inline Fixed<T> operator -(const Other &lhs, const Fixed<T> &rhs) {
276         return lhs + -rhs;
277 }
278
279 template<Uint8 T, Uint8 U>
280 inline Fixed<T> operator *(const Fixed<T> &lhs, const Fixed<U> &rhs) {
281         Fixed<T> temp(lhs);
282         return temp *= rhs;
283 }
284 template<Uint8 T, class Other>
285 inline Fixed<T> operator *(const Fixed<T> &lhs, const Other &rhs) {
286         Fixed<T> temp(lhs);
287         return temp *= rhs;
288 }
289 template<Uint8 T, class Other>
290 inline Fixed<T> operator *(const Other &lhs, const Fixed<T> &rhs) {
291         return rhs * lhs;
292 }
293
294 template<Uint8 T, Uint8 U>
295 inline Fixed<T> operator /(const Fixed<T> &lhs, const Fixed<U> &rhs) {
296         Fixed<T> temp(lhs);
297         return temp /= rhs;
298 }
299 template<Uint8 T, class Other>
300 inline Fixed<T> operator /(const Fixed<T> &lhs, const Other &rhs) {
301         Fixed<T> temp(lhs);
302         return temp /= rhs;
303 }
304
305 template<Uint8 T, Uint8 U>
306 inline Fixed<T> operator %(const Fixed<T> &lhs, const Fixed<U> &rhs) {
307         Fixed<T> temp(lhs);
308         return temp %= rhs;
309 }
310 template<Uint8 T, class Other>
311 inline Fixed<T> operator %(const Fixed<T> &lhs, const Other &rhs) {
312         Fixed<T> temp(lhs);
313         return temp %= rhs;
314 }
315
316
317 template<Uint8 T>
318 inline std::ostream &operator <<(std::ostream &out, const Fixed<T> &f) {
319         return out << f.Double();
320 }
321
322 }
323
324
325 namespace std {
326
327 template <Uint8 fracBits>
328 class numeric_limits<math::Fixed<fracBits> > {
329
330 public:
331         static const bool is_specialized = true;
332         static math::Fixed<fracBits> min() throw() {
333                 return max() * -1;
334         }
335         static math::Fixed<fracBits> max() throw() {
336                 return math::Fixed<fracBits>(1 << (digits - fracBits) - 1)
337                                 + math::Fixed<fracBits>((1 << fracBits) - 2, (1 << fracBits) - 1);
338         }
339         static const int digits = 31;
340         static const int digits10 = 10;
341         static const bool is_signed = true;
342         static const bool is_integer = false;
343         static const bool is_exact = true;
344         static const int radix = 2;
345         static math::Fixed<fracBits> epsilon() throw() {
346                 return math::Fixed<fracBits>(1, 1 << (digits - fracBits) - 1);
347         }
348         static math::Fixed<fracBits> round_error() throw() {
349                 return epsilon();
350         }
351
352         static const bool is_iec559 = false;
353         static const bool is_bounded = true;
354         static const bool is_modulo = false;
355
356         static const bool traps = false;
357         static const bool tinyness_before = false;
358         static const float_round_style round_style = round_toward_zero;
359 };
360
361 }
362
363 #endif