Pyrogenesis  trunk
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  CFixed operator>>(int n) const
249  {
250  ASSERT(n >= 0 && n < 32);
251  return CFixed(value >> n);
252  }
253 
254  CFixed operator<<(int n) const
255  {
256  ASSERT(n >= 0 && n < 32);
257  // TODO: check for overflow
258  return CFixed(value << n);
259  }
260 
261  /// Divide by a CFixed. Must not have n.IsZero(). Might overflow.
263  {
264  i64 t = (i64)value << fract_bits;
265  i64 result = t / (i64)n.value;
266 
267  CheckCastOverflow(result, T, L"Overflow in CFixed::operator/(CFixed n)", L"Underflow in CFixed::operator/(CFixed n)")
268  return CFixed((T)result);
269  }
270 
271  /// Multiply by an integer. Might overflow.
272  CFixed operator*(int n) const
273  {
274  CheckMultiplicationOverflow(T, value, n, L"Overflow in CFixed::operator*(int n)", L"Underflow in CFixed::operator*(int n)")
275  return CFixed(value * n);
276  }
277 
278  /// Multiply by an integer. Avoids overflow by clamping to min/max representable value.
279  CFixed MultiplyClamp(int n) const
280  {
281  i64 t = (i64)value * n;
282  t = std::max((i64)std::numeric_limits<T>::min(), std::min((i64)std::numeric_limits<T>::max(), t));
283  return CFixed((i32)t);
284  }
285 
286  /// Divide by an integer. Must not have n == 0. Cannot overflow unless n == -1.
287  CFixed operator/(int n) const
288  {
289  CheckDivisionOverflow(T, value, n, L"Overflow in CFixed::operator/(int n)")
290  return CFixed(value / n);
291  }
292 
293  /// Mod by a fixed. Must not have n == 0. Result has the same sign as n.
295  {
296  T t = value % n.value;
297  if (n.value > 0 && t < 0)
298  t += n.value;
299  else if (n.value < 0 && t > 0)
300  t += n.value;
301 
302  return CFixed(t);
303  }
304 
305  CFixed Absolute() const { return CFixed(abs(value)); }
306 
307  /**
308  * Multiply by a CFixed. Likely to overflow if both numbers are large,
309  * so we use an ugly name instead of operator* to make it obvious.
310  */
312  {
313  i64 t = FIXED_MUL_I64_I32_I32(value, n.value);
314  t >>= fract_bits;
315 
316  CheckCastOverflow(t, T, L"Overflow in CFixed::Multiply(CFixed n)", L"Underflow in CFixed::Multiply(CFixed n)")
317  return CFixed((T)t);
318  }
319 
320  /**
321  * Multiply the value by itself. Might overflow.
322  */
323  CFixed Square() const
324  {
325  return (*this).Multiply(*this);
326  }
327 
328  /**
329  * Compute this*m/d. Must not have d == 0. Won't overflow if the result can be represented as a CFixed.
330  */
332  {
333  i64 t = FIXED_MUL_I64_I32_I32(value, m.value) / (i64)d.value;
334  CheckCastOverflow(t, T, L"Overflow in CFixed::Multiply(CFixed n)", L"Underflow in CFixed::Multiply(CFixed n)")
335  return CFixed((T)t);
336  }
337 
338  CFixed Sqrt() const
339  {
340  if (value <= 0)
341  return CFixed(0);
342  u32 s = isqrt64((u64)value << fract_bits);
343  return CFixed(s);
344  }
345 
346 private:
347  // Prevent dangerous accidental implicit conversions of floats to ints in certain operations
348  CFixed operator*(float n) const;
349  CFixed operator/(float n) const;
350 };
351 
352 /**
353  * A fixed-point number class with 1-bit sign, 15-bit integral part, 16-bit fractional part.
354  */
356 
357 /**
358  * Default fixed-point type used by the engine.
359  */
361 
362 namespace std
363 {
364 /**
365  * std::numeric_limits specialisation, currently just providing min and max
366  */
367 template<typename T, T max_t, int total_bits, int int_bits, int fract_bits_, int fract_pow2>
368 struct numeric_limits<CFixed<T, max_t, total_bits, int_bits, fract_bits_, fract_pow2> >
369 {
371 public:
372  static const bool is_specialized = true;
373  static fixed min() throw() { fixed f; f.SetInternalValue(std::numeric_limits<T>::min()); return f; }
374  static fixed max() throw() { fixed f; f.SetInternalValue(std::numeric_limits<T>::max()); return f; }
375 };
376 }
377 
378 /**
379  * Inaccurate approximation of atan2 over fixed-point numbers.
380  * Maximum error is almost 0.08 radians (4.5 degrees).
381  */
383 
384 /**
385  * Compute sin(a) and cos(a).
386  * Maximum error for -2pi < a < 2pi is almost 0.0005.
387  */
388 void sincos_approx(CFixed_15_16 a, CFixed_15_16& sin_out, CFixed_15_16& cos_out);
389 
390 #endif // INCLUDED_FIXED
CFixed< T, max_t, total_bits, int_bits, fract_bits_, fract_pow2 > fixed
Definition: Fixed.h:370
A simple fixed-point number class.
Definition: Fixed.h:115
int64_t i64
Definition: types.h:35
bool operator>(CFixed n) const
Numeric comparison.
Definition: Fixed.h:217
CFixed()
Definition: Fixed.h:125
Definition: Fixed.h:123
#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:360
#define isfinite
Definition: posix.h:127
CFixed operator>>(int n) const
Definition: Fixed.h:248
CFixed Absolute() const
Definition: Fixed.h:305
CFixed operator-() const
Negate a CFixed.
Definition: Fixed.h:242
CFixed & operator+=(CFixed n)
Add a CFixed. Might overflow.
Definition: Fixed.h:236
Definition: unique_range.h:196
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
#define ASSERT(expr)
same as ENSURE in debug mode, does nothing in release mode.
Definition: debug.h:315
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:294
int ToInt_RoundToZero() const
Definition: Fixed.h:172
uint64_t u64
Definition: types.h:40
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:355
CFixed operator/(int n) const
Divide by an integer. Must not have n == 0. Cannot overflow unless n == -1.
Definition: Fixed.h:287
CFixed(T v)
Definition: Fixed.h:120
uint32_t u32
Definition: types.h:39
T round_away_from_zero(float value)
Definition: Fixed.h:98
CFixed Sqrt() const
Definition: Fixed.h:338
CFixed Multiply(CFixed n) const
Multiply by a CFixed.
Definition: Fixed.h:311
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:76
CFixed operator*(int n) const
Multiply by an integer. Might overflow.
Definition: Fixed.h:272
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:331
int32_t i32
Definition: types.h:34
static CFixed FromInt(int n)
Definition: Fixed.h:136
CFixed operator-(CFixed n) const
Subtract a CFixed. Might overflow.
Definition: Fixed.h:229
CFixed operator<<(int n) const
Definition: Fixed.h:254
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
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
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
CFixed Square() const
Multiply the value by itself.
Definition: Fixed.h:323
CFixed operator/(CFixed n) const
Divide by a CFixed. Must not have n.IsZero(). Might overflow.
Definition: Fixed.h:262
int ToInt_RoundToNearest() const
Definition: Fixed.h:190
CFixed MultiplyClamp(int n) const
Multiply by an integer. Avoids overflow by clamping to min/max representable value.
Definition: Fixed.h:279
bool operator==(CFixed n) const
Equality.
Definition: Fixed.h:202
static CFixed FromDouble(double n)
Definition: Fixed.h:149
int ToInt_RoundToInfinity() const
Definition: Fixed.h:180
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
#define CheckCastOverflow(var, targetType, overflowWarning, underflowWarning)
Definition: Fixed.h:66