1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
10 #include <cstdlib> // for abs() etc.
11 #include <climits> // For INT_MAX / UINT_MAX
12 #include <type_traits>
19 //! Rounding error constant often used when comparing f32 values.
21 const f32 ROUNDING_ERROR_f32
= 0.000001f
;
22 const f64 ROUNDING_ERROR_f64
= 0.00000001;
24 #ifdef PI // make sure we don't collide with a define
28 const f32 PI
= 3.14159265359f
;
30 //! Constant for reciprocal of PI.
31 const f32 RECIPROCAL_PI
= 1.0f
/ PI
;
33 //! Constant for half of PI.
34 const f32 HALF_PI
= PI
/ 2.0f
;
36 #ifdef PI64 // make sure we don't collide with a define
39 //! Constant for 64bit PI.
40 const f64 PI64
= 3.1415926535897932384626433832795028841971693993751;
42 //! Constant for 64bit reciprocal of PI.
43 const f64 RECIPROCAL_PI64
= 1.0 / PI64
;
45 //! 32bit Constant for converting from degrees to radians
46 const f32 DEGTORAD
= PI
/ 180.0f
;
48 //! 32bit constant for converting from radians to degrees (formally known as GRAD_PI)
49 const f32 RADTODEG
= 180.0f
/ PI
;
51 //! 64bit constant for converting from degrees to radians (formally known as GRAD_PI2)
52 const f64 DEGTORAD64
= PI64
/ 180.0;
54 //! 64bit constant for converting from radians to degrees
55 const f64 RADTODEG64
= 180.0 / PI64
;
57 //! Utility function to convert a radian value to degrees
58 /** Provided as it can be clearer to write radToDeg(X) than RADTODEG * X
59 \param radians The radians value to convert to degrees.
61 inline f32
radToDeg(f32 radians
)
63 return RADTODEG
* radians
;
66 //! Utility function to convert a radian value to degrees
67 /** Provided as it can be clearer to write radToDeg(X) than RADTODEG * X
68 \param radians The radians value to convert to degrees.
70 inline f64
radToDeg(f64 radians
)
72 return RADTODEG64
* radians
;
75 //! Utility function to convert a degrees value to radians
76 /** Provided as it can be clearer to write degToRad(X) than DEGTORAD * X
77 \param degrees The degrees value to convert to radians.
79 inline f32
degToRad(f32 degrees
)
81 return DEGTORAD
* degrees
;
84 //! Utility function to convert a degrees value to radians
85 /** Provided as it can be clearer to write degToRad(X) than DEGTORAD * X
86 \param degrees The degrees value to convert to radians.
88 inline f64
degToRad(f64 degrees
)
90 return DEGTORAD64
* degrees
;
93 //! returns minimum of two values. Own implementation to get rid of the STL (VS6 problems)
95 inline const T
&min_(const T
&a
, const T
&b
)
100 //! returns minimum of three values. Own implementation to get rid of the STL (VS6 problems)
102 inline const T
&min_(const T
&a
, const T
&b
, const T
&c
)
104 return a
< b
? min_(a
, c
) : min_(b
, c
);
107 //! returns maximum of two values. Own implementation to get rid of the STL (VS6 problems)
109 inline const T
&max_(const T
&a
, const T
&b
)
111 return a
< b
? b
: a
;
114 //! returns maximum of three values. Own implementation to get rid of the STL (VS6 problems)
116 inline const T
&max_(const T
&a
, const T
&b
, const T
&c
)
118 return a
< b
? max_(b
, c
) : max_(a
, c
);
121 //! returns abs of two values. Own implementation to get rid of STL (VS6 problems)
123 inline T
abs_(const T
&a
)
125 return a
< (T
)0 ? -a
: a
;
128 //! returns linear interpolation of a and b with ratio t
129 //! \return: a if t==0, b if t==1, and the linear interpolation else
131 inline T
lerp(const T
&a
, const T
&b
, const f32 t
)
133 return (T
)(a
* (1.f
- t
)) + (b
* t
);
136 //! clamps a value between low and high
138 inline const T
clamp(const T
&value
, const T
&low
, const T
&high
)
140 return min_(max_(value
, low
), high
);
143 //! swaps the content of the passed parameters
144 // Note: We use the same trick as boost and use two template arguments to
145 // avoid ambiguity when swapping objects of an Irrlicht type that has not
146 // it's own swap overload. Otherwise we get conflicts with some compilers
147 // in combination with stl.
148 template <class T1
, class T2
>
149 inline void swap(T1
&a
, T2
&b
)
157 inline T
roundingError();
160 inline f32
roundingError()
162 return ROUNDING_ERROR_f32
;
166 inline f64
roundingError()
168 return ROUNDING_ERROR_f64
;
172 inline T
relativeErrorFactor()
178 inline f32
relativeErrorFactor()
184 inline f64
relativeErrorFactor()
189 //! returns if a equals b, for types without rounding errors
190 template <class T
, std::enable_if_t
<std::is_integral
<T
>::value
, bool> = true>
191 inline bool equals(const T a
, const T b
)
196 //! returns if a equals b, taking possible rounding errors into account
197 template <class T
, std::enable_if_t
<std::is_floating_point
<T
>::value
, bool> = true>
198 inline bool equals(const T a
, const T b
, const T tolerance
= roundingError
<T
>())
200 return std::abs(a
- b
) <= tolerance
;
203 //! returns if a equals b, taking relative error in form of factor
204 //! this particular function does not involve any division.
206 inline bool equalsRelative(const T a
, const T b
, const T factor
= relativeErrorFactor
<T
>())
208 // https://eagergames.wordpress.com/2017/04/01/fast-parallel-lines-and-vectors-test/
210 const T maxi
= max_(a
, b
);
211 const T mini
= min_(a
, b
);
212 const T maxMagnitude
= max_(maxi
, -mini
);
214 return (maxMagnitude
* factor
+ maxi
) == (maxMagnitude
* factor
+ mini
); // MAD Wise
217 union FloatIntUnion32
219 FloatIntUnion32(float f1
= 0.0f
) :
221 // Portable sign-extraction
222 bool sign() const { return (i
>> 31) != 0; }
228 //! We compare the difference in ULP's (spacing between floating-point numbers, aka ULP=1 means there exists no float between).
229 //\result true when numbers have a ULP <= maxUlpDiff AND have the same sign.
230 inline bool equalsByUlp(f32 a
, f32 b
, int maxUlpDiff
)
232 // Based on the ideas and code from Bruce Dawson on
233 // http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/
234 // When floats are interpreted as integers the two nearest possible float numbers differ just
235 // by one integer number. Also works the other way round, an integer of 1 interpreted as float
236 // is for example the smallest possible float number.
238 const FloatIntUnion32
fa(a
);
239 const FloatIntUnion32
fb(b
);
241 // Different signs, we could maybe get difference to 0, but so close to 0 using epsilons is better.
242 if (fa
.sign() != fb
.sign()) {
243 // Check for equality to make sure +0==-0
249 // Find the difference in ULPs.
250 const int ulpsDiff
= abs_(fa
.i
- fb
.i
);
251 if (ulpsDiff
<= maxUlpDiff
)
257 //! returns if a equals zero, taking rounding errors into account
258 inline bool iszero(const f64 a
, const f64 tolerance
= ROUNDING_ERROR_f64
)
260 return fabs(a
) <= tolerance
;
263 //! returns if a equals zero, taking rounding errors into account
264 inline bool iszero(const f32 a
, const f32 tolerance
= ROUNDING_ERROR_f32
)
266 return fabsf(a
) <= tolerance
;
269 //! returns if a equals not zero, taking rounding errors into account
270 inline bool isnotzero(const f32 a
, const f32 tolerance
= ROUNDING_ERROR_f32
)
272 return fabsf(a
) > tolerance
;
275 //! returns if a equals zero, taking rounding errors into account
276 inline bool iszero(const s32 a
, const s32 tolerance
= 0)
278 return (a
& 0x7ffffff) <= tolerance
;
281 //! returns if a equals zero, taking rounding errors into account
282 inline bool iszero(const u32 a
, const u32 tolerance
= 0)
284 return a
<= tolerance
;
287 //! returns if a equals zero, taking rounding errors into account
288 inline bool iszero(const s64 a
, const s64 tolerance
= 0)
290 return abs_(a
) <= tolerance
;
293 inline s32
s32_min(s32 a
, s32 b
)
298 inline s32
s32_max(s32 a
, s32 b
)
303 inline s32
s32_clamp(s32 value
, s32 low
, s32 high
)
305 return clamp(value
, low
, high
);
309 float IEEE-754 bit representation
317 +NaN 0x7fc00000 or 0x7ff00000
318 in general: number = (sign ? -1:1) * 2^(exponent) * 1.(mantissa bits)
328 #define F32_AS_S32(f) (*((s32 *)&(f)))
329 #define F32_AS_U32(f) (*((u32 *)&(f)))
330 #define F32_AS_U32_POINTER(f) (((u32 *)&(f)))
332 #define F32_VALUE_0 0x00000000
333 #define F32_VALUE_1 0x3f800000
335 //! code is taken from IceFPU
336 //! Integer representation of a floating-point value.
344 //! Floating-point representation of an integer value.
358 #define F32_LOWER_0(n) ((n) < 0.0f)
359 #define F32_LOWER_EQUAL_0(n) ((n) <= 0.0f)
360 #define F32_GREATER_0(n) ((n) > 0.0f)
361 #define F32_GREATER_EQUAL_0(n) ((n) >= 0.0f)
362 #define F32_EQUAL_1(n) ((n) == 1.0f)
363 #define F32_EQUAL_0(n) ((n) == 0.0f)
364 #define F32_A_GREATER_B(a, b) ((a) > (b))
368 #define REALINLINE __forceinline
370 #define REALINLINE inline
374 // NOTE: This is not as exact as the c99/c++11 round function, especially at high numbers starting with 8388609
375 // (only low number which seems to go wrong is 0.49999997 which is rounded to 1)
376 // 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)
377 inline f32
round_(f32 x
)
379 return floorf(x
+ 0.5f
);
382 // calculate: sqrt ( x )
383 REALINLINE f32
squareroot(const f32 f
)
388 // calculate: sqrt ( x )
389 REALINLINE f64
squareroot(const f64 f
)
394 // calculate: sqrt ( x )
395 REALINLINE s32
squareroot(const s32 f
)
397 return static_cast<s32
>(squareroot(static_cast<f32
>(f
)));
400 // calculate: sqrt ( x )
401 REALINLINE s64
squareroot(const s64 f
)
403 return static_cast<s64
>(squareroot(static_cast<f64
>(f
)));
406 // calculate: 1 / sqrt ( x )
407 REALINLINE f64
reciprocal_squareroot(const f64 x
)
409 return 1.0 / sqrt(x
);
412 // calculate: 1 / sqrtf ( x )
413 REALINLINE f32
reciprocal_squareroot(const f32 f
)
415 return 1.f
/ sqrtf(f
);
418 // calculate: 1 / sqrtf( x )
419 REALINLINE s32
reciprocal_squareroot(const s32 x
)
421 return static_cast<s32
>(reciprocal_squareroot(static_cast<f32
>(x
)));
425 REALINLINE f32
reciprocal(const f32 f
)
431 REALINLINE f64
reciprocal(const f64 f
)
436 // calculate: 1 / x, low precision allowed
437 REALINLINE f32
reciprocal_approxim(const f32 f
)
442 REALINLINE s32
floor32(f32 x
)
444 return (s32
)floorf(x
);
447 REALINLINE s32
ceil32(f32 x
)
449 return (s32
)ceilf(x
);
452 // NOTE: Please check round_ documentation about some inaccuracies in this compared to standard library round function.
453 REALINLINE s32
round32(f32 x
)
455 return (s32
)round_(x
);
458 inline f32
f32_max3(const f32 a
, const f32 b
, const f32 c
)
460 return a
> b
? (a
> c
? a
: c
) : (b
> c
? b
: c
);
463 inline f32
f32_min3(const f32 a
, const f32 b
, const f32 c
)
465 return a
< b
? (a
< c
? a
: c
) : (b
< c
? b
: c
);
468 inline f32
fract(f32 x
)
470 return x
- floorf(x
);
473 } // end namespace core
474 } // end namespace irr