]> git.lizzy.rs Git - irrlicht.git/blob - include/irrMath.h
Fix COSOperator::getSystemMemory
[irrlicht.git] / include / irrMath.h
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #ifndef __IRR_MATH_H_INCLUDED__\r
6 #define __IRR_MATH_H_INCLUDED__\r
7 \r
8 #include "IrrCompileConfig.h"\r
9 #include "irrTypes.h"\r
10 #include <math.h>\r
11 #include <float.h>\r
12 #include <stdlib.h> // for abs() etc.\r
13 #include <limits.h> // For INT_MAX / UINT_MAX\r
14 \r
15 namespace irr\r
16 {\r
17 namespace core\r
18 {\r
19 \r
20         //! Rounding error constant often used when comparing f32 values.\r
21 \r
22         const s32 ROUNDING_ERROR_S32 = 0;\r
23 \r
24 #ifdef __IRR_HAS_S64\r
25         const s64 ROUNDING_ERROR_S64 = 0;\r
26 #endif\r
27         const f32 ROUNDING_ERROR_f32 = 0.000001f;\r
28         const f64 ROUNDING_ERROR_f64 = 0.00000001;\r
29 \r
30 #ifdef PI // make sure we don't collide with a define\r
31 #undef PI\r
32 #endif\r
33         //! Constant for PI.\r
34         const f32 PI = 3.14159265359f;\r
35 \r
36         //! Constant for reciprocal of PI.\r
37         const f32 RECIPROCAL_PI = 1.0f/PI;\r
38 \r
39         //! Constant for half of PI.\r
40         const f32 HALF_PI = PI/2.0f;\r
41 \r
42 #ifdef PI64 // make sure we don't collide with a define\r
43 #undef PI64\r
44 #endif\r
45         //! Constant for 64bit PI.\r
46         const f64 PI64 = 3.1415926535897932384626433832795028841971693993751;\r
47 \r
48         //! Constant for 64bit reciprocal of PI.\r
49         const f64 RECIPROCAL_PI64 = 1.0/PI64;\r
50 \r
51         //! 32bit Constant for converting from degrees to radians\r
52         const f32 DEGTORAD = PI / 180.0f;\r
53 \r
54         //! 32bit constant for converting from radians to degrees (formally known as GRAD_PI)\r
55         const f32 RADTODEG   = 180.0f / PI;\r
56 \r
57         //! 64bit constant for converting from degrees to radians (formally known as GRAD_PI2)\r
58         const f64 DEGTORAD64 = PI64 / 180.0;\r
59 \r
60         //! 64bit constant for converting from radians to degrees\r
61         const f64 RADTODEG64 = 180.0 / PI64;\r
62 \r
63         //! Utility function to convert a radian value to degrees\r
64         /** Provided as it can be clearer to write radToDeg(X) than RADTODEG * X\r
65         \param radians The radians value to convert to degrees.\r
66         */\r
67         inline f32 radToDeg(f32 radians)\r
68         {\r
69                 return RADTODEG * radians;\r
70         }\r
71 \r
72         //! Utility function to convert a radian value to degrees\r
73         /** Provided as it can be clearer to write radToDeg(X) than RADTODEG * X\r
74         \param radians The radians value to convert to degrees.\r
75         */\r
76         inline f64 radToDeg(f64 radians)\r
77         {\r
78                 return RADTODEG64 * radians;\r
79         }\r
80 \r
81         //! Utility function to convert a degrees value to radians\r
82         /** Provided as it can be clearer to write degToRad(X) than DEGTORAD * X\r
83         \param degrees The degrees value to convert to radians.\r
84         */\r
85         inline f32 degToRad(f32 degrees)\r
86         {\r
87                 return DEGTORAD * degrees;\r
88         }\r
89 \r
90         //! Utility function to convert a degrees value to radians\r
91         /** Provided as it can be clearer to write degToRad(X) than DEGTORAD * X\r
92         \param degrees The degrees value to convert to radians.\r
93         */\r
94         inline f64 degToRad(f64 degrees)\r
95         {\r
96                 return DEGTORAD64 * degrees;\r
97         }\r
98 \r
99         //! returns minimum of two values. Own implementation to get rid of the STL (VS6 problems)\r
100         template<class T>\r
101         inline const T& min_(const T& a, const T& b)\r
102         {\r
103                 return a < b ? a : b;\r
104         }\r
105 \r
106         //! returns minimum of three values. Own implementation to get rid of the STL (VS6 problems)\r
107         template<class T>\r
108         inline const T& min_(const T& a, const T& b, const T& c)\r
109         {\r
110                 return a < b ? min_(a, c) : min_(b, c);\r
111         }\r
112 \r
113         //! returns maximum of two values. Own implementation to get rid of the STL (VS6 problems)\r
114         template<class T>\r
115         inline const T& max_(const T& a, const T& b)\r
116         {\r
117                 return a < b ? b : a;\r
118         }\r
119 \r
120         //! returns maximum of three values. Own implementation to get rid of the STL (VS6 problems)\r
121         template<class T>\r
122         inline const T& max_(const T& a, const T& b, const T& c)\r
123         {\r
124                 return a < b ? max_(b, c) : max_(a, c);\r
125         }\r
126 \r
127         //! returns abs of two values. Own implementation to get rid of STL (VS6 problems)\r
128         template<class T>\r
129         inline T abs_(const T& a)\r
130         {\r
131                 return a < (T)0 ? -a : a;\r
132         }\r
133 \r
134         //! returns linear interpolation of a and b with ratio t\r
135         //! \return: a if t==0, b if t==1, and the linear interpolation else\r
136         template<class T>\r
137         inline T lerp(const T& a, const T& b, const f32 t)\r
138         {\r
139                 return (T)(a*(1.f-t)) + (b*t);\r
140         }\r
141 \r
142         //! clamps a value between low and high\r
143         template <class T>\r
144         inline const T clamp (const T& value, const T& low, const T& high)\r
145         {\r
146                 return min_ (max_(value,low), high);\r
147         }\r
148 \r
149         //! swaps the content of the passed parameters\r
150         // Note: We use the same trick as boost and use two template arguments to\r
151         // avoid ambiguity when swapping objects of an Irrlicht type that has not\r
152         // it's own swap overload. Otherwise we get conflicts with some compilers\r
153         // in combination with stl.\r
154         template <class T1, class T2>\r
155         inline void swap(T1& a, T2& b)\r
156         {\r
157                 T1 c(a);\r
158                 a = b;\r
159                 b = c;\r
160         }\r
161 \r
162         template <class T>\r
163         inline T roundingError();\r
164 \r
165         template <>\r
166         inline f32 roundingError()\r
167         {\r
168                 return ROUNDING_ERROR_f32;\r
169         }\r
170 \r
171         template <>\r
172         inline f64 roundingError()\r
173         {\r
174                 return ROUNDING_ERROR_f64;\r
175         }\r
176 \r
177         template <>\r
178         inline s32 roundingError()\r
179         {\r
180                 return ROUNDING_ERROR_S32;\r
181         }\r
182 \r
183         template <>\r
184         inline u32 roundingError()\r
185         {\r
186                 return ROUNDING_ERROR_S32;\r
187         }\r
188 \r
189 #ifdef __IRR_HAS_S64\r
190         template <>\r
191         inline s64 roundingError()\r
192         {\r
193                 return ROUNDING_ERROR_S64;\r
194         }\r
195 \r
196         template <>\r
197         inline u64 roundingError()\r
198         {\r
199                 return ROUNDING_ERROR_S64;\r
200         }\r
201 #endif\r
202 \r
203         template <class T>\r
204         inline T relativeErrorFactor()\r
205         {\r
206                 return 1;\r
207         }\r
208 \r
209         template <>\r
210         inline f32 relativeErrorFactor()\r
211         {\r
212                 return 4;\r
213         }\r
214 \r
215         template <>\r
216         inline f64 relativeErrorFactor()\r
217         {\r
218                 return 8;\r
219         }\r
220 \r
221         //! returns if a equals b, taking possible rounding errors into account\r
222         template <class T>\r
223         inline bool equals(const T a, const T b, const T tolerance = roundingError<T>())\r
224         {\r
225                 return (a + tolerance >= b) && (a - tolerance <= b);\r
226         }\r
227 \r
228 \r
229         //! returns if a equals b, taking relative error in form of factor\r
230         //! this particular function does not involve any division.\r
231         template <class T>\r
232         inline bool equalsRelative( const T a, const T b, const T factor = relativeErrorFactor<T>())\r
233         {\r
234                 //https://eagergames.wordpress.com/2017/04/01/fast-parallel-lines-and-vectors-test/\r
235 \r
236                 const T maxi = max_( a, b);\r
237                 const T mini = min_( a, b);\r
238                 const T maxMagnitude = max_( maxi, -mini);\r
239 \r
240                 return  (maxMagnitude*factor + maxi) == (maxMagnitude*factor + mini); // MAD Wise\r
241         }\r
242 \r
243         union FloatIntUnion32\r
244         {\r
245                 FloatIntUnion32(float f1 = 0.0f) : f(f1) {}\r
246                 // Portable sign-extraction\r
247                 bool sign() const { return (i >> 31) != 0; }\r
248 \r
249                 irr::s32 i;\r
250                 irr::f32 f;\r
251         };\r
252 \r
253         //! We compare the difference in ULP's (spacing between floating-point numbers, aka ULP=1 means there exists no float between).\r
254         //\result true when numbers have a ULP <= maxUlpDiff AND have the same sign.\r
255         inline bool equalsByUlp(f32 a, f32 b, int maxUlpDiff)\r
256         {\r
257                 // Based on the ideas and code from Bruce Dawson on\r
258                 // http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/\r
259                 // When floats are interpreted as integers the two nearest possible float numbers differ just\r
260                 // by one integer number. Also works the other way round, an integer of 1 interpreted as float\r
261                 // is for example the smallest possible float number.\r
262 \r
263                 const FloatIntUnion32 fa(a);\r
264                 const FloatIntUnion32 fb(b);\r
265 \r
266                 // Different signs, we could maybe get difference to 0, but so close to 0 using epsilons is better.\r
267                 if ( fa.sign() != fb.sign() )\r
268                 {\r
269                         // Check for equality to make sure +0==-0\r
270                         if (fa.i == fb.i)\r
271                                 return true;\r
272                         return false;\r
273                 }\r
274 \r
275                 // Find the difference in ULPs.\r
276                 const int ulpsDiff = abs_(fa.i- fb.i);\r
277                 if (ulpsDiff <= maxUlpDiff)\r
278                         return true;\r
279 \r
280                 return false;\r
281         }\r
282 \r
283         //! returns if a equals zero, taking rounding errors into account\r
284         inline bool iszero(const f64 a, const f64 tolerance = ROUNDING_ERROR_f64)\r
285         {\r
286                 return fabs(a) <= tolerance;\r
287         }\r
288 \r
289         //! returns if a equals zero, taking rounding errors into account\r
290         inline bool iszero(const f32 a, const f32 tolerance = ROUNDING_ERROR_f32)\r
291         {\r
292                 return fabsf(a) <= tolerance;\r
293         }\r
294 \r
295         //! returns if a equals not zero, taking rounding errors into account\r
296         inline bool isnotzero(const f32 a, const f32 tolerance = ROUNDING_ERROR_f32)\r
297         {\r
298                 return fabsf(a) > tolerance;\r
299         }\r
300 \r
301         //! returns if a equals zero, taking rounding errors into account\r
302         inline bool iszero(const s32 a, const s32 tolerance = 0)\r
303         {\r
304                 return ( a & 0x7ffffff ) <= tolerance;\r
305         }\r
306 \r
307         //! returns if a equals zero, taking rounding errors into account\r
308         inline bool iszero(const u32 a, const u32 tolerance = 0)\r
309         {\r
310                 return a <= tolerance;\r
311         }\r
312 \r
313 #ifdef __IRR_HAS_S64\r
314         //! returns if a equals zero, taking rounding errors into account\r
315         inline bool iszero(const s64 a, const s64 tolerance = 0)\r
316         {\r
317                 return abs_(a) <= tolerance;\r
318         }\r
319 #endif\r
320 \r
321         inline s32 s32_min(s32 a, s32 b)\r
322         {\r
323                 return min_(a, b);\r
324         }\r
325 \r
326         inline s32 s32_max(s32 a, s32 b)\r
327         {\r
328                 return max_(a, b);\r
329         }\r
330 \r
331         inline s32 s32_clamp (s32 value, s32 low, s32 high)\r
332         {\r
333                 return clamp(value, low, high);\r
334         }\r
335 \r
336         /*\r
337                 float IEEE-754 bit representation\r
338 \r
339                 0      0x00000000\r
340                 1.0    0x3f800000\r
341                 0.5    0x3f000000\r
342                 3      0x40400000\r
343                 +inf   0x7f800000\r
344                 -inf   0xff800000\r
345                 +NaN   0x7fc00000 or 0x7ff00000\r
346                 in general: number = (sign ? -1:1) * 2^(exponent) * 1.(mantissa bits)\r
347         */\r
348 \r
349         typedef union { u32 u; s32 s; f32 f; } inttofloat;\r
350 \r
351         #define F32_AS_S32(f)           (*((s32 *) &(f)))\r
352         #define F32_AS_U32(f)           (*((u32 *) &(f)))\r
353         #define F32_AS_U32_POINTER(f)   ( ((u32 *) &(f)))\r
354 \r
355         #define F32_VALUE_0             0x00000000\r
356         #define F32_VALUE_1             0x3f800000\r
357 \r
358         //! code is taken from IceFPU\r
359         //! Integer representation of a floating-point value.\r
360         inline u32 IR(f32 x) {inttofloat tmp; tmp.f=x; return tmp.u;}\r
361 \r
362         //! Floating-point representation of an integer value.\r
363         inline f32 FR(u32 x) {inttofloat tmp; tmp.u=x; return tmp.f;}\r
364         inline f32 FR(s32 x) {inttofloat tmp; tmp.s=x; return tmp.f;}\r
365 \r
366         #define F32_LOWER_0(n)          ((n) <  0.0f)\r
367         #define F32_LOWER_EQUAL_0(n)    ((n) <= 0.0f)\r
368         #define F32_GREATER_0(n)        ((n) >  0.0f)\r
369         #define F32_GREATER_EQUAL_0(n)  ((n) >= 0.0f)\r
370         #define F32_EQUAL_1(n)          ((n) == 1.0f)\r
371         #define F32_EQUAL_0(n)          ((n) == 0.0f)\r
372         #define F32_A_GREATER_B(a,b)    ((a) > (b))\r
373 \r
374 #ifndef REALINLINE\r
375         #ifdef _MSC_VER\r
376                 #define REALINLINE __forceinline\r
377         #else\r
378                 #define REALINLINE inline\r
379         #endif\r
380 #endif\r
381 \r
382 \r
383         // NOTE: This is not as exact as the c99/c++11 round function, especially at high numbers starting with 8388609\r
384         //       (only low number which seems to go wrong is 0.49999997 which is rounded to 1)\r
385         //      Also negative 0.5 is rounded up not down unlike with the standard function (p.E. input -0.5 will be 0 and not -1)\r
386         inline f32 round_( f32 x )\r
387         {\r
388                 return floorf( x + 0.5f );\r
389         }\r
390 \r
391         // calculate: sqrt ( x )\r
392         REALINLINE f32 squareroot(const f32 f)\r
393         {\r
394                 return sqrtf(f);\r
395         }\r
396 \r
397         // calculate: sqrt ( x )\r
398         REALINLINE f64 squareroot(const f64 f)\r
399         {\r
400                 return sqrt(f);\r
401         }\r
402 \r
403         // calculate: sqrt ( x )\r
404         REALINLINE s32 squareroot(const s32 f)\r
405         {\r
406                 return static_cast<s32>(squareroot(static_cast<f32>(f)));\r
407         }\r
408 \r
409 #ifdef __IRR_HAS_S64\r
410         // calculate: sqrt ( x )\r
411         REALINLINE s64 squareroot(const s64 f)\r
412         {\r
413                 return static_cast<s64>(squareroot(static_cast<f64>(f)));\r
414         }\r
415 #endif\r
416 \r
417         // calculate: 1 / sqrt ( x )\r
418         REALINLINE f64 reciprocal_squareroot(const f64 x)\r
419         {\r
420                 return 1.0 / sqrt(x);\r
421         }\r
422 \r
423         // calculate: 1 / sqrtf ( x )\r
424         REALINLINE f32 reciprocal_squareroot(const f32 f)\r
425         {\r
426                 return 1.f / sqrtf(f);\r
427         }\r
428 \r
429         // calculate: 1 / sqrtf( x )\r
430         REALINLINE s32 reciprocal_squareroot(const s32 x)\r
431         {\r
432                 return static_cast<s32>(reciprocal_squareroot(static_cast<f32>(x)));\r
433         }\r
434 \r
435         // calculate: 1 / x\r
436         REALINLINE f32 reciprocal( const f32 f )\r
437         {\r
438                 return 1.f / f;\r
439         }\r
440 \r
441         // calculate: 1 / x\r
442         REALINLINE f64 reciprocal ( const f64 f )\r
443         {\r
444                 return 1.0 / f;\r
445         }\r
446 \r
447 \r
448         // calculate: 1 / x, low precision allowed\r
449         REALINLINE f32 reciprocal_approxim ( const f32 f )\r
450         {\r
451                 return 1.f / f;\r
452         }\r
453 \r
454         REALINLINE s32 floor32(f32 x)\r
455         {\r
456                 return (s32) floorf ( x );\r
457         }\r
458 \r
459         REALINLINE s32 ceil32 ( f32 x )\r
460         {\r
461                 return (s32) ceilf ( x );\r
462         }\r
463 \r
464         // NOTE: Please check round_ documentation about some inaccuracies in this compared to standard library round function.\r
465         REALINLINE s32 round32(f32 x)\r
466         {\r
467                 return (s32) round_(x);\r
468         }\r
469 \r
470         inline f32 f32_max3(const f32 a, const f32 b, const f32 c)\r
471         {\r
472                 return a > b ? (a > c ? a : c) : (b > c ? b : c);\r
473         }\r
474 \r
475         inline f32 f32_min3(const f32 a, const f32 b, const f32 c)\r
476         {\r
477                 return a < b ? (a < c ? a : c) : (b < c ? b : c);\r
478         }\r
479 \r
480         inline f32 fract ( f32 x )\r
481         {\r
482                 return x - floorf ( x );\r
483         }\r
484 \r
485 } // end namespace core\r
486 } // end namespace irr\r
487 \r
488 using irr::core::IR;\r
489 using irr::core::FR;\r
490 \r
491 #endif\r