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
5 #ifndef __IRR_MATH_H_INCLUDED__
\r
6 #define __IRR_MATH_H_INCLUDED__
\r
8 #include "IrrCompileConfig.h"
\r
9 #include "irrTypes.h"
\r
12 #include <stdlib.h> // for abs() etc.
\r
13 #include <limits.h> // For INT_MAX / UINT_MAX
\r
20 //! Rounding error constant often used when comparing f32 values.
\r
22 const s32 ROUNDING_ERROR_S32 = 0;
\r
24 #ifdef __IRR_HAS_S64
\r
25 const s64 ROUNDING_ERROR_S64 = 0;
\r
27 const f32 ROUNDING_ERROR_f32 = 0.000001f;
\r
28 const f64 ROUNDING_ERROR_f64 = 0.00000001;
\r
30 #ifdef PI // make sure we don't collide with a define
\r
33 //! Constant for PI.
\r
34 const f32 PI = 3.14159265359f;
\r
36 //! Constant for reciprocal of PI.
\r
37 const f32 RECIPROCAL_PI = 1.0f/PI;
\r
39 //! Constant for half of PI.
\r
40 const f32 HALF_PI = PI/2.0f;
\r
42 #ifdef PI64 // make sure we don't collide with a define
\r
45 //! Constant for 64bit PI.
\r
46 const f64 PI64 = 3.1415926535897932384626433832795028841971693993751;
\r
48 //! Constant for 64bit reciprocal of PI.
\r
49 const f64 RECIPROCAL_PI64 = 1.0/PI64;
\r
51 //! 32bit Constant for converting from degrees to radians
\r
52 const f32 DEGTORAD = PI / 180.0f;
\r
54 //! 32bit constant for converting from radians to degrees (formally known as GRAD_PI)
\r
55 const f32 RADTODEG = 180.0f / PI;
\r
57 //! 64bit constant for converting from degrees to radians (formally known as GRAD_PI2)
\r
58 const f64 DEGTORAD64 = PI64 / 180.0;
\r
60 //! 64bit constant for converting from radians to degrees
\r
61 const f64 RADTODEG64 = 180.0 / PI64;
\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
67 inline f32 radToDeg(f32 radians)
\r
69 return RADTODEG * radians;
\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
76 inline f64 radToDeg(f64 radians)
\r
78 return RADTODEG64 * radians;
\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
85 inline f32 degToRad(f32 degrees)
\r
87 return DEGTORAD * degrees;
\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
94 inline f64 degToRad(f64 degrees)
\r
96 return DEGTORAD64 * degrees;
\r
99 //! returns minimum of two values. Own implementation to get rid of the STL (VS6 problems)
\r
101 inline const T& min_(const T& a, const T& b)
\r
103 return a < b ? a : b;
\r
106 //! returns minimum of three values. Own implementation to get rid of the STL (VS6 problems)
\r
108 inline const T& min_(const T& a, const T& b, const T& c)
\r
110 return a < b ? min_(a, c) : min_(b, c);
\r
113 //! returns maximum of two values. Own implementation to get rid of the STL (VS6 problems)
\r
115 inline const T& max_(const T& a, const T& b)
\r
117 return a < b ? b : a;
\r
120 //! returns maximum of three values. Own implementation to get rid of the STL (VS6 problems)
\r
122 inline const T& max_(const T& a, const T& b, const T& c)
\r
124 return a < b ? max_(b, c) : max_(a, c);
\r
127 //! returns abs of two values. Own implementation to get rid of STL (VS6 problems)
\r
129 inline T abs_(const T& a)
\r
131 return a < (T)0 ? -a : a;
\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
137 inline T lerp(const T& a, const T& b, const f32 t)
\r
139 return (T)(a*(1.f-t)) + (b*t);
\r
142 //! clamps a value between low and high
\r
144 inline const T clamp (const T& value, const T& low, const T& high)
\r
146 return min_ (max_(value,low), high);
\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
163 inline T roundingError();
\r
166 inline f32 roundingError()
\r
168 return ROUNDING_ERROR_f32;
\r
172 inline f64 roundingError()
\r
174 return ROUNDING_ERROR_f64;
\r
178 inline s32 roundingError()
\r
180 return ROUNDING_ERROR_S32;
\r
184 inline u32 roundingError()
\r
186 return ROUNDING_ERROR_S32;
\r
189 #ifdef __IRR_HAS_S64
\r
191 inline s64 roundingError()
\r
193 return ROUNDING_ERROR_S64;
\r
197 inline u64 roundingError()
\r
199 return ROUNDING_ERROR_S64;
\r
204 inline T relativeErrorFactor()
\r
210 inline f32 relativeErrorFactor()
\r
216 inline f64 relativeErrorFactor()
\r
221 //! returns if a equals b, taking possible rounding errors into account
\r
223 inline bool equals(const T a, const T b, const T tolerance = roundingError<T>())
\r
225 return (a + tolerance >= b) && (a - tolerance <= b);
\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
232 inline bool equalsRelative( const T a, const T b, const T factor = relativeErrorFactor<T>())
\r
234 //https://eagergames.wordpress.com/2017/04/01/fast-parallel-lines-and-vectors-test/
\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
240 return (maxMagnitude*factor + maxi) == (maxMagnitude*factor + mini); // MAD Wise
\r
243 union FloatIntUnion32
\r
245 FloatIntUnion32(float f1 = 0.0f) : f(f1) {}
\r
246 // Portable sign-extraction
\r
247 bool sign() const { return (i >> 31) != 0; }
\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
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
263 const FloatIntUnion32 fa(a);
\r
264 const FloatIntUnion32 fb(b);
\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
269 // Check for equality to make sure +0==-0
\r
275 // Find the difference in ULPs.
\r
276 const int ulpsDiff = abs_(fa.i- fb.i);
\r
277 if (ulpsDiff <= maxUlpDiff)
\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
286 return fabs(a) <= tolerance;
\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
292 return fabsf(a) <= tolerance;
\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
298 return fabsf(a) > tolerance;
\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
304 return ( a & 0x7ffffff ) <= tolerance;
\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
310 return a <= tolerance;
\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
317 return abs_(a) <= tolerance;
\r
321 inline s32 s32_min(s32 a, s32 b)
\r
323 const s32 mask = (a - b) >> 31;
\r
324 return (a & mask) | (b & ~mask);
\r
327 inline s32 s32_max(s32 a, s32 b)
\r
329 const s32 mask = (a - b) >> 31;
\r
330 return (b & mask) | (a & ~mask);
\r
333 inline s32 s32_clamp (s32 value, s32 low, s32 high)
\r
335 return s32_min(s32_max(value,low), high);
\r
339 float IEEE-754 bit representation
\r
347 +NaN 0x7fc00000 or 0x7ff00000
\r
348 in general: number = (sign ? -1:1) * 2^(exponent) * 1.(mantissa bits)
\r
351 typedef union { u32 u; s32 s; f32 f; } inttofloat;
\r
353 #define F32_AS_S32(f) (*((s32 *) &(f)))
\r
354 #define F32_AS_U32(f) (*((u32 *) &(f)))
\r
355 #define F32_AS_U32_POINTER(f) ( ((u32 *) &(f)))
\r
357 #define F32_VALUE_0 0x00000000
\r
358 #define F32_VALUE_1 0x3f800000
\r
360 //! code is taken from IceFPU
\r
361 //! Integer representation of a floating-point value.
\r
362 inline u32 IR(f32 x) {inttofloat tmp; tmp.f=x; return tmp.u;}
\r
364 //! Floating-point representation of an integer value.
\r
365 inline f32 FR(u32 x) {inttofloat tmp; tmp.u=x; return tmp.f;}
\r
366 inline f32 FR(s32 x) {inttofloat tmp; tmp.s=x; return tmp.f;}
\r
368 #define F32_LOWER_0(n) ((n) < 0.0f)
\r
369 #define F32_LOWER_EQUAL_0(n) ((n) <= 0.0f)
\r
370 #define F32_GREATER_0(n) ((n) > 0.0f)
\r
371 #define F32_GREATER_EQUAL_0(n) ((n) >= 0.0f)
\r
372 #define F32_EQUAL_1(n) ((n) == 1.0f)
\r
373 #define F32_EQUAL_0(n) ((n) == 0.0f)
\r
374 #define F32_A_GREATER_B(a,b) ((a) > (b))
\r
378 #define REALINLINE __forceinline
\r
380 #define REALINLINE inline
\r
384 //! conditional set based on mask and arithmetic shift
\r
385 REALINLINE u32 if_c_a_else_b ( const s32 condition, const u32 a, const u32 b )
\r
387 return ( ( -condition >> 31 ) & ( a ^ b ) ) ^ b;
\r
390 //! conditional set based on mask and arithmetic shift
\r
391 REALINLINE u16 if_c_a_else_b ( const s16 condition, const u16 a, const u16 b )
\r
393 return ( ( -condition >> 15 ) & ( a ^ b ) ) ^ b;
\r
396 //! conditional set based on mask and arithmetic shift
\r
397 REALINLINE u32 if_c_a_else_0 ( const s32 condition, const u32 a )
\r
399 return ( -condition >> 31 ) & a;
\r
403 if (condition) state |= m; else state &= ~m;
\r
405 REALINLINE void setbit_cond ( u32 &state, s32 condition, u32 mask )
\r
407 // 0, or any positive to mask
\r
408 //s32 conmask = -condition >> 31;
\r
409 state ^= ( ( -condition >> 31 ) ^ state ) & mask;
\r
412 // NOTE: This is not as exact as the c99/c++11 round function, especially at high numbers starting with 8388609
\r
413 // (only low number which seems to go wrong is 0.49999997 which is rounded to 1)
\r
414 // 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
415 inline f32 round_( f32 x )
\r
417 return floorf( x + 0.5f );
\r
420 // calculate: sqrt ( x )
\r
421 REALINLINE f32 squareroot(const f32 f)
\r
426 // calculate: sqrt ( x )
\r
427 REALINLINE f64 squareroot(const f64 f)
\r
432 // calculate: sqrt ( x )
\r
433 REALINLINE s32 squareroot(const s32 f)
\r
435 return static_cast<s32>(squareroot(static_cast<f32>(f)));
\r
438 #ifdef __IRR_HAS_S64
\r
439 // calculate: sqrt ( x )
\r
440 REALINLINE s64 squareroot(const s64 f)
\r
442 return static_cast<s64>(squareroot(static_cast<f64>(f)));
\r
446 // calculate: 1 / sqrt ( x )
\r
447 REALINLINE f64 reciprocal_squareroot(const f64 x)
\r
449 return 1.0 / sqrt(x);
\r
452 // calculate: 1 / sqrtf ( x )
\r
453 REALINLINE f32 reciprocal_squareroot(const f32 f)
\r
455 return 1.f / sqrtf(f);
\r
458 // calculate: 1 / sqrtf( x )
\r
459 REALINLINE s32 reciprocal_squareroot(const s32 x)
\r
461 return static_cast<s32>(reciprocal_squareroot(static_cast<f32>(x)));
\r
464 // calculate: 1 / x
\r
465 REALINLINE f32 reciprocal( const f32 f )
\r
470 // calculate: 1 / x
\r
471 REALINLINE f64 reciprocal ( const f64 f )
\r
477 // calculate: 1 / x, low precision allowed
\r
478 REALINLINE f32 reciprocal_approxim ( const f32 f )
\r
483 REALINLINE s32 floor32(f32 x)
\r
485 return (s32) floorf ( x );
\r
488 REALINLINE s32 ceil32 ( f32 x )
\r
490 return (s32) ceilf ( x );
\r
493 // NOTE: Please check round_ documentation about some inaccuracies in this compared to standard library round function.
\r
494 REALINLINE s32 round32(f32 x)
\r
496 return (s32) round_(x);
\r
499 inline f32 f32_max3(const f32 a, const f32 b, const f32 c)
\r
501 return a > b ? (a > c ? a : c) : (b > c ? b : c);
\r
504 inline f32 f32_min3(const f32 a, const f32 b, const f32 c)
\r
506 return a < b ? (a < c ? a : c) : (b < c ? b : c);
\r
509 inline f32 fract ( f32 x )
\r
511 return x - floorf ( x );
\r
514 } // end namespace core
\r
515 } // end namespace irr
\r
517 using irr::core::IR;
\r
518 using irr::core::FR;
\r