Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Fixed.h
Go to the documentation of this file.
1 /* Copyright (C) 2013 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INCLUDED_FIXED
19 #define INCLUDED_FIXED
20 
21 #include "lib/types.h"
22 #include "maths/Sqrt.h"
23 
24 class CStr8;
25 class CStrW;
26 
27 #ifndef NDEBUG
28 #define USE_FIXED_OVERFLOW_CHECKS
29 #endif
30 
31 #if MSC_VERSION
32 // i32*i32 -> i64 multiply: MSVC x86 doesn't optimise i64 multiplies automatically, so use the intrinsic
33 #include <intrin.h>
34 #define FIXED_MUL_I64_I32_I32(a, b) (__emul((a), (b)))
35 #else
36 #define FIXED_MUL_I64_I32_I32(a, b) ((i64)(a) * (i64)(b))
37 #endif
38 
39 //define overflow macros
40 #ifndef USE_FIXED_OVERFLOW_CHECKS
41 
42 #define CheckSignedSubtractionOverflow(type, left, right, overflowWarning, underflowWarning)
43 #define CheckSignedAdditionOverflow(type, left, right, overflowWarning, underflowWarning)
44 #define CheckCastOverflow(var, targetType, overflowWarning, underflowWarning)
45 #define CheckU32CastOverflow(var, targetType, overflowWarning)
46 #define CheckUnsignedAdditionOverflow(result, operand, overflowWarning)
47 #define CheckUnsignedSubtractionOverflow(result, operand, overflowWarning)
48 #define CheckNegationOverflow(var, type, overflowWarning)
49 #define CheckMultiplicationOverflow(type, left, right, overflowWarning, underflowWarning)
50 #define CheckDivisionOverflow(type, left, right, overflowWarning)
51 
52 #else // USE_FIXED_OVERFLOW_CHECKS
53 
54 #define CheckSignedSubtractionOverflow(type, left, right, overflowWarning, underflowWarning) \
55  if(left > 0 && right < 0 && left > std::numeric_limits<type>::max() + right) \
56  debug_warn(overflowWarning); \
57  else if(left < 0 && right > 0 && left < std::numeric_limits<type>::min() + right) \
58  debug_warn(underflowWarning);
59 
60 #define CheckSignedAdditionOverflow(type, left, right, overflowWarning, underflowWarning) \
61  if(left > 0 && right > 0 && std::numeric_limits<type>::max() - left < right) \
62  debug_warn(overflowWarning); \
63  else if(left < 0 && right < 0 && std::numeric_limits<type>::min() - left > right) \
64  debug_warn(underflowWarning);
65 
66 #define CheckCastOverflow(var, targetType, overflowWarning, underflowWarning) \
67  if(var > std::numeric_limits<targetType>::max()) \
68  debug_warn(overflowWarning); \
69  else if(var < std::numeric_limits<targetType>::min()) \
70  debug_warn(underflowWarning);
71 
72 #define CheckU32CastOverflow(var, targetType, overflowWarning) \
73  if(var > (u32)std::numeric_limits<targetType>::max()) \
74  debug_warn(overflowWarning);
75 
76 #define CheckUnsignedAdditionOverflow(result, operand, overflowWarning) \
77  if(result < operand) \
78  debug_warn(overflowWarning);
79 
80 #define CheckUnsignedSubtractionOverflow(result, left, overflowWarning) \
81  if(result > left) \
82  debug_warn(overflowWarning);
83 
84 #define CheckNegationOverflow(var, type, overflowWarning) \
85  if(value == std::numeric_limits<type>::min()) \
86  debug_warn(overflowWarning);
87 
88 #define CheckMultiplicationOverflow(type, left, right, overflowWarning, underflowWarning) \
89  i64 res##left = (i64)left * (i64)right; \
90  CheckCastOverflow(res##left, type, overflowWarning, underflowWarning)
91 
92 #define CheckDivisionOverflow(type, left, right, overflowWarning) \
93  if(right == -1) { CheckNegationOverflow(left, type, overflowWarning) }
94 
95 #endif // USE_FIXED_OVERFLOW_CHECKS
96 
97 template <typename T>
98 inline T round_away_from_zero(float value)
99 {
100  return (T)(value >= 0 ? value + 0.5f : value - 0.5f);
101 }
102 
103 template <typename T>
104 inline T round_away_from_zero(double value)
105 {
106  return (T)(value >= 0 ? value + 0.5 : value - 0.5);
107 }
108 
109 /**
110  * A simple fixed-point number class.
111  *
112  * Use 'fixed' rather than using this class directly.
113  */
114 template<typename T, T max_t, int total_bits, int int_bits, int fract_bits_, int fract_pow2>
115 class CFixed
116 {
117 private:
119 
120  explicit CFixed(T v) : value(v) { }
121 
122 public:
123  enum { fract_bits = fract_bits_ };
124 
125  CFixed() : value(0) { }
126 
127  static CFixed Zero() { return CFixed(0); }
128  static CFixed Epsilon() { return CFixed(1); }
129  static CFixed Pi();
130 
131  T GetInternalValue() const { return value; }
132  void SetInternalValue(T n) { value = n; }
133 
134  // Conversion to/from primitive types:
135 
136  static CFixed FromInt(int n)
137  {
138  return CFixed(n << fract_bits);
139  }
140 
141  static CFixed FromFloat(float n)
142  {
143  if (!isfinite(n))
144  return CFixed(0);
145  float scaled = n * fract_pow2;
146  return CFixed(round_away_from_zero<T>(scaled));
147  }
148 
149  static CFixed FromDouble(double n)
150  {
151  if (!isfinite(n))
152  return CFixed(0);
153  double scaled = n * fract_pow2;
154  return CFixed(round_away_from_zero<T>(scaled));
155  }
156 
157  static CFixed FromString(const CStr8& s);
158  static CFixed FromString(const CStrW& s);
159 
160  /// Convert to float. May be lossy - float can't represent all values.
161  float ToFloat() const
162  {
163  return (float)value / (float)fract_pow2;
164  }
165 
166  /// Convert to double. Won't be lossy - double can precisely represent all values.
167  double ToDouble() const
168  {
169  return value / (double)fract_pow2;
170  }
171 
172  int ToInt_RoundToZero() const
173  {
174  if (value > 0)
175  return value >> fract_bits;
176  else
177  return (value + fract_pow2 - 1) >> fract_bits;
178  }
179 
181  {
182  return (value + fract_pow2 - 1) >> fract_bits;
183  }
184 
186  {
187  return value >> fract_bits;
188  }
189 
190  int ToInt_RoundToNearest() const // (ties to infinity)
191  {
192  return (value + fract_pow2/2) >> fract_bits;
193  }
194 
195  /// Returns the shortest string such that FromString will parse to the correct value.
196  CStr8 ToString() const;
197 
198  /// Returns true if the number is precisely 0.
199  bool IsZero() const { return value == 0; }
200 
201  /// Equality.
202  bool operator==(CFixed n) const { return (value == n.value); }
203 
204  /// Inequality.
205  bool operator!=(CFixed n) const { return (value != n.value); }
206 
207  /// Numeric comparison.
208  bool operator<=(CFixed n) const { return (value <= n.value); }
209 
210  /// Numeric comparison.
211  bool operator<(CFixed n) const { return (value < n.value); }
212 
213  /// Numeric comparison.
214  bool operator>=(CFixed n) const { return (value >= n.value); }
215 
216  /// Numeric comparison.
217  bool operator>(CFixed n) const { return (value > n.value); }
218 
219  // Basic arithmetic:
220 
221  /// Add a CFixed. Might overflow.
223  {
224  CheckSignedAdditionOverflow(T, value, n.value, L"Overflow in CFixed::operator+(CFixed n)", L"Underflow in CFixed::operator+(CFixed n)")
225  return CFixed(value + n.value);
226  }
227 
228  /// Subtract a CFixed. Might overflow.
230  {
231  CheckSignedSubtractionOverflow(T, value, n.value, L"Overflow in CFixed::operator-(CFixed n)", L"Underflow in CFixed::operator-(CFixed n)")
232  return CFixed(value - n.value);
233  }
234 
235  /// Add a CFixed. Might overflow.
236  CFixed& operator+=(CFixed n) { *this = *this + n; return *this; }
237 
238  /// Subtract a CFixed. Might overflow.
239  CFixed& operator-=(CFixed n) { *this = *this - n; return *this; }
240 
241  /// Negate a CFixed.
243  {
244  CheckNegationOverflow(value, T, L"Overflow in CFixed::operator-()")
245  return CFixed(-value);
246  }
247 
248  /// Divide by a CFixed. Must not have n.IsZero(). Might overflow.
250  {
251  i64 t = (i64)value << fract_bits;
252  i64 result = t / (i64)n.value;
253 
254  CheckCastOverflow(result, T, L"Overflow in CFixed::operator/(CFixed n)", L"Underflow in CFixed::operator/(CFixed n)")
255  return CFixed((T)result);
256  }
257 
258  /// Multiply by an integer. Might overflow.
259  CFixed operator*(int n) const
260  {
261  CheckMultiplicationOverflow(T, value, n, L"Overflow in CFixed::operator*(int n)", L"Underflow in CFixed::operator*(int n)")
262  return CFixed(value * n);
263  }
264 
265  /// Divide by an integer. Must not have n == 0. Cannot overflow unless n == -1.
266  CFixed operator/(int n) const
267  {
268  CheckDivisionOverflow(T, value, n, L"Overflow in CFixed::operator/(int n)")
269  return CFixed(value / n);
270  }
271 
272  /// Mod by a fixed. Must not have n == 0. Result has the same sign as n.
274  {
275  T t = value % n.value;
276  if (n.value > 0 && t < 0)
277  t += n.value;
278  else if (n.value < 0 && t > 0)
279  t += n.value;
280 
281  return CFixed(t);
282  }
283 
284  CFixed Absolute() const { return CFixed(abs(value)); }
285 
286  /**
287  * Multiply by a CFixed. Likely to overflow if both numbers are large,
288  * so we use an ugly name instead of operator* to make it obvious.
289  */
291  {
293  t >>= fract_bits;
294 
295  CheckCastOverflow(t, T, L"Overflow in CFixed::Multiply(CFixed n)", L"Underflow in CFixed::Multiply(CFixed n)")
296  return CFixed((T)t);
297  }
298 
299  /**
300  * Multiply the value by itself. Might overflow.
301  */
302  CFixed Square() const
303  {
304  return (*this).Multiply(*this);
305  }
306 
307  /**
308  * Compute this*m/d. Must not have d == 0. Won't overflow if the result can be represented as a CFixed.
309  */
311  {
313  CheckCastOverflow(t, T, L"Overflow in CFixed::Multiply(CFixed n)", L"Underflow in CFixed::Multiply(CFixed n)")
314  return CFixed((T)t);
315  }
316 
317  CFixed Sqrt() const
318  {
319  if (value <= 0)
320  return CFixed(0);
321  u32 s = isqrt64((u64)value << fract_bits);
322  return CFixed(s);
323  }
324 
325 private:
326  // Prevent dangerous accidental implicit conversions of floats to ints in certain operations
327  CFixed operator*(float n) const;
328  CFixed operator/(float n) const;
329 };
330 
331 /**
332  * A fixed-point number class with 1-bit sign, 15-bit integral part, 16-bit fractional part.
333  */
335 
336 /**
337  * Default fixed-point type used by the engine.
338  */
340 
341 namespace std
342 {
343 /**
344  * std::numeric_limits specialisation, currently just providing min and max
345  */
346 template<typename T, T max_t, int total_bits, int int_bits, int fract_bits_, int fract_pow2>
347 struct numeric_limits<CFixed<T, max_t, total_bits, int_bits, fract_bits_, fract_pow2> >
348 {
350 public:
351  static const bool is_specialized = true;
352  static fixed min() throw() { fixed f; f.SetInternalValue(std::numeric_limits<T>::min()); return f; }
353  static fixed max() throw() { fixed f; f.SetInternalValue(std::numeric_limits<T>::max()); return f; }
354 };
355 }
356 
357 /**
358  * Inaccurate approximation of atan2 over fixed-point numbers.
359  * Maximum error is almost 0.08 radians (4.5 degrees).
360  */
362 
363 /**
364  * Compute sin(a) and cos(a).
365  * Maximum error for -2pi < a < 2pi is almost 0.0005.
366  */
367 void sincos_approx(CFixed_15_16 a, CFixed_15_16& sin_out, CFixed_15_16& cos_out);
368 
369 #endif // INCLUDED_FIXED
CFixed< T, max_t, total_bits, int_bits, fract_bits_, fract_pow2 > fixed
Definition: Fixed.h:349
A simple fixed-point number class.
Definition: Fixed.h:115
bool operator>(CFixed n) const
Numeric comparison.
Definition: Fixed.h:217
CFixed()
Definition: Fixed.h:125
#define FIXED_MUL_I64_I32_I32(a, b)
Definition: Fixed.h:36
static CFixed Zero()
Definition: Fixed.h:127
CFixed_15_16 fixed
Default fixed-point type used by the engine.
Definition: Fixed.h:339
#define isfinite
Definition: posix.h:127
CFixed Absolute() const
Definition: Fixed.h:284
CFixed operator-() const
Negate a CFixed.
Definition: Fixed.h:242
CFixed & operator+=(CFixed n)
Add a CFixed. Might overflow.
Definition: Fixed.h:236
CFixed operator+(CFixed n) const
Add a CFixed. Might overflow.
Definition: Fixed.h:222
CFixed & operator-=(CFixed n)
Subtract a CFixed. Might overflow.
Definition: Fixed.h:239
T GetInternalValue() const
Definition: Fixed.h:131
static CFixed Pi()
Definition: Fixed.cpp:182
#define CheckSignedSubtractionOverflow(type, left, right, overflowWarning, underflowWarning)
Definition: Fixed.h:54
CFixed operator%(CFixed n) const
Mod by a fixed. Must not have n == 0. Result has the same sign as n.
Definition: Fixed.h:273
int ToInt_RoundToZero() const
Definition: Fixed.h:172
void SetInternalValue(T n)
Definition: Fixed.h:132
CFixed< i32,(i32) 0x7fffffff, 32, 15, 16, 65536 > CFixed_15_16
A fixed-point number class with 1-bit sign, 15-bit integral part, 16-bit fractional part...
Definition: Fixed.h:334
CFixed operator/(int n) const
Divide by an integer. Must not have n == 0. Cannot overflow unless n == -1.
Definition: Fixed.h:266
CFixed(T v)
Definition: Fixed.h:120
T round_away_from_zero(float value)
Definition: Fixed.h:98
CFixed Sqrt() const
Definition: Fixed.h:317
CFixed Multiply(CFixed n) const
Multiply by a CFixed.
Definition: Fixed.h:290
float ToFloat() const
Convert to float. May be lossy - float can&#39;t represent all values.
Definition: Fixed.h:161
static CFixed Epsilon()
Definition: Fixed.h:128
#define CheckNegationOverflow(var, type, overflowWarning)
Definition: Fixed.h:84
u32 isqrt64(u64 n)
64-bit integer square root.
Definition: Sqrt.cpp:23
bool operator>=(CFixed n) const
Numeric comparison.
Definition: Fixed.h:214
static CFixed FromString(const CStr8 &s)
Definition: Fixed.cpp:27
#define CheckDivisionOverflow(type, left, right, overflowWarning)
Definition: Fixed.h:92
#define T(string_literal)
Definition: secure_crt.cpp:70
CFixed operator*(int n) const
Multiply by an integer. Might overflow.
Definition: Fixed.h:259
int ToInt_RoundToNegInfinity() const
Definition: Fixed.h:185
T value
Definition: Fixed.h:118
double ToDouble() const
Convert to double. Won&#39;t be lossy - double can precisely represent all values.
Definition: Fixed.h:167
#define CheckSignedAdditionOverflow(type, left, right, overflowWarning, underflowWarning)
Definition: Fixed.h:60
CFixed MulDiv(CFixed m, CFixed d) const
Compute this*m/d.
Definition: Fixed.h:310
static CFixed FromInt(int n)
Definition: Fixed.h:136
CFixed operator-(CFixed n) const
Subtract a CFixed. Might overflow.
Definition: Fixed.h:229
#define u64
Definition: types.h:42
#define i64
Definition: types.h:37
#define u32
Definition: types.h:41
bool IsZero() const
Returns true if the number is precisely 0.
Definition: Fixed.h:199
bool operator<(CFixed n) const
Numeric comparison.
Definition: Fixed.h:211
CStr8 ToString() const
Returns the shortest string such that FromString will parse to the correct value. ...
Definition: Fixed.cpp:96
#define CheckMultiplicationOverflow(type, left, right, overflowWarning, underflowWarning)
Definition: Fixed.h:88
bool operator!=(CFixed n) const
Inequality.
Definition: Fixed.h:205
bool operator<=(CFixed n) const
Numeric comparison.
Definition: Fixed.h:208
static CFixed FromFloat(float n)
Definition: Fixed.h:141
void sincos_approx(CFixed_15_16 a, CFixed_15_16 &sin_out, CFixed_15_16 &cos_out)
Compute sin(a) and cos(a).
Definition: Fixed.cpp:187
CFixed Square() const
Multiply the value by itself.
Definition: Fixed.h:302
CFixed operator/(CFixed n) const
Divide by a CFixed. Must not have n.IsZero(). Might overflow.
Definition: Fixed.h:249
int ToInt_RoundToNearest() const
Definition: Fixed.h:190
bool operator==(CFixed n) const
Equality.
Definition: Fixed.h:202
CFixed_15_16 atan2_approx(CFixed_15_16 y, CFixed_15_16 x)
Inaccurate approximation of atan2 over fixed-point numbers.
Definition: Fixed.cpp:147
static CFixed FromDouble(double n)
Definition: Fixed.h:149
int ToInt_RoundToInfinity() const
Definition: Fixed.h:180
#define CheckCastOverflow(var, targetType, overflowWarning, underflowWarning)
Definition: Fixed.h:66