• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef _DEMATH_H
2 #define _DEMATH_H
3 /*-------------------------------------------------------------------------
4  * drawElements Base Portability Library
5  * -------------------------------------
6  *
7  * Copyright 2014 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Basic mathematical operations.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "deDefs.h"
27 #include "deMemory.h"
28 
29 #include <math.h>
30 #include <float.h>
31 
32 DE_BEGIN_EXTERN_C
33 
34 /* Mathematical constants. */
35 
36 #define DE_PI 3.14159265358979324f            /*!< Pi.                    */
37 #define DE_LOG_2 0.69314718056f               /*!< log_e(2.0)                */
38 #define DE_INV_LOG_2 1.44269504089f           /*!< 1.0 / log_e(2.0)        */
39 #define DE_E 2.71828182845904523536f          /*!< e.                        */
40 #define DE_LOG2_E 1.44269504088896340736f     /*!< log_2(e).                */
41 #define DE_INV_LOG2_E 0.69314718055994530942f /*!< 1.0 / log_2(e).        */
42 
43 #define DE_PI_DOUBLE 3.14159265358979323846 /*!< Pi as a double.        */
44 #define DE_PI_16BIT 0x4248                  /*!< Pi. as a float16b        */
45 
46 /* Rounding mode control. */
47 
48 typedef enum deRoundingMode_e
49 {
50     DE_ROUNDINGMODE_TO_NEAREST_EVEN = 0,
51     DE_ROUNDINGMODE_TO_ZERO,
52     DE_ROUNDINGMODE_TO_POSITIVE_INF,
53     DE_ROUNDINGMODE_TO_NEGATIVE_INF,
54 
55     DE_ROUNDINGMODE_LAST
56 } deRoundingMode;
57 
58 deRoundingMode deGetRoundingMode(void);
59 bool deSetRoundingMode(deRoundingMode mode);
60 
61 void deMath_selfTest(void);
62 
63 /* Float properties */
64 
deFloatBitsToUint32(float x)65 static inline uint32_t deFloatBitsToUint32(float x)
66 {
67     uint32_t bits;
68     deMemcpy((void *)&bits, (void *)&x, 4);
69     return bits;
70 }
71 
deDoubleBitsToUint64(double x)72 static inline uint64_t deDoubleBitsToUint64(double x)
73 {
74     uint64_t bits;
75     deMemcpy((void *)&bits, (void *)&x, 8);
76     return bits;
77 }
78 
deFloatIsPositiveZero(float x)79 static inline bool deFloatIsPositiveZero(float x)
80 {
81     return x == 0 && (deFloatBitsToUint32(x) >> 31) == 0;
82 }
83 
deDoubleIsPositiveZero(double x)84 static inline bool deDoubleIsPositiveZero(double x)
85 {
86     return x == 0 && (deDoubleBitsToUint64(x) >> 63) == 0;
87 }
88 
deFloatIsNegativeZero(float x)89 static inline bool deFloatIsNegativeZero(float x)
90 {
91     return x == 0 && (deFloatBitsToUint32(x) >> 31) != 0;
92 }
93 
deDoubleIsNegativeZero(double x)94 static inline bool deDoubleIsNegativeZero(double x)
95 {
96     return x == 0 && (deDoubleBitsToUint64(x) >> 63) != 0;
97 }
98 
deFloatIsIEEENaN(float x)99 static inline bool deFloatIsIEEENaN(float x)
100 {
101     uint32_t e = (deFloatBitsToUint32(x) & 0x7f800000u) >> 23;
102     uint32_t m = (deFloatBitsToUint32(x) & 0x007fffffu);
103     return e == 0xff && m != 0;
104 }
105 
deDoubleIsIEEENaN(double x)106 static inline bool deDoubleIsIEEENaN(double x)
107 {
108     uint64_t e = (deDoubleBitsToUint64(x) & 0x7ff0000000000000ull) >> 52;
109     uint64_t m = (deDoubleBitsToUint64(x) & 0x000fffffffffffffull);
110     return e == 0x7ff && m != 0;
111 }
112 
113 /* \note The definition used for signaling NaN here is valid for ARM and
114  * x86 but possibly not for other platforms.
115  *
116  * These are defined as overloads so that they can be used in templated
117  * code without risking a type conversion which would triggern an exception
118  * on a signaling NaN.  We don't use deIsNan in these helpers because they
119  * do a comparison operation which may also trigger exceptions.
120  */
deFloatIsSignalingNaN(float x)121 static inline bool deFloatIsSignalingNaN(float x)
122 {
123     return deFloatIsIEEENaN(x) && (deFloatBitsToUint32(x) & (1u << 22)) == 0;
124 }
125 
deDoubleIsSignalingNaN(double x)126 static inline bool deDoubleIsSignalingNaN(double x)
127 {
128     return deDoubleIsIEEENaN(x) && (deDoubleBitsToUint64(x) & (1ull << 51)) == 0;
129 }
130 
deFloatIsQuietNaN(float x)131 static inline bool deFloatIsQuietNaN(float x)
132 {
133     return deFloatIsIEEENaN(x) && (deFloatBitsToUint32(x) & (1u << 22)) != 0;
134 }
135 
deDoubleIsQuietNaN(double x)136 static inline bool deDoubleIsQuietNaN(double x)
137 {
138     return deDoubleIsIEEENaN(x) && (deDoubleBitsToUint64(x) & (1ull << 51)) != 0;
139 }
140 
141 /* Basic utilities. */
142 
deFloatAbs(float x)143 static inline float deFloatAbs(float x)
144 {
145     return (x >= 0.0f) ? x : -x;
146 }
deFloatMin(float a,float b)147 static inline float deFloatMin(float a, float b)
148 {
149     return (a <= b) ? a : b;
150 }
deFloatMax(float a,float b)151 static inline float deFloatMax(float a, float b)
152 {
153     return (a >= b) ? a : b;
154 }
deFloatClamp(float x,float mn,float mx)155 static inline float deFloatClamp(float x, float mn, float mx)
156 {
157     return (x <= mn) ? mn : ((x >= mx) ? mx : x);
158 }
159 
deAbs(double x)160 static inline double deAbs(double x)
161 {
162     return (x >= 0.0) ? x : -x;
163 }
deMin(double a,double b)164 static inline double deMin(double a, double b)
165 {
166     return (a <= b) ? a : b;
167 }
deMax(double a,double b)168 static inline double deMax(double a, double b)
169 {
170     return (a >= b) ? a : b;
171 }
deClamp(double x,double mn,double mx)172 static inline double deClamp(double x, double mn, double mx)
173 {
174     return (x <= mn) ? mn : ((x >= mx) ? mx : x);
175 }
176 
177 /* Utility functions. */
178 
deFloatSign(float a)179 static inline float deFloatSign(float a)
180 {
181     return (a == 0.0f) ? 0.0f : ((a > 0.0f) ? +1.0f : -1.0f);
182 }
deFloatIntSign(float a)183 static inline int deFloatIntSign(float a)
184 {
185     return (a == 0.0f) ? 0 : ((a > 0.0f) ? +1 : -1);
186 }
deFloatFloor(float a)187 static inline float deFloatFloor(float a)
188 {
189     return (float)floor(a);
190 }
deFloatCeil(float a)191 static inline float deFloatCeil(float a)
192 {
193     return (float)ceil(a);
194 }
deFloatRound(float a)195 static inline float deFloatRound(float a)
196 {
197     return deFloatFloor(a + 0.5f);
198 }
deFloatFrac(float a)199 static inline float deFloatFrac(float a)
200 {
201     return a - deFloatFloor(a);
202 }
deFloatMod(float a,float b)203 static inline float deFloatMod(float a, float b)
204 {
205     return (float)fmod(a, b);
206 }
deFloatModf(float x,float * i)207 static inline float deFloatModf(float x, float *i)
208 {
209     double j   = 0;
210     double ret = modf(x, &j);
211     *i         = (float)j;
212     return (float)ret;
213 }
deFloatMadd(float a,float b,float c)214 static inline float deFloatMadd(float a, float b, float c)
215 {
216     return (a * b) + c;
217 }
deFloatTrunc(float a)218 static inline float deFloatTrunc(float a)
219 {
220     return deFloatSign(a) * deFloatFloor(deFloatAbs(a));
221 }
deFloatLdExp(float a,int exponent)222 static inline float deFloatLdExp(float a, int exponent)
223 {
224     return (float)ldexp(a, exponent);
225 }
deFloatFrExp(float x,int * exponent)226 static inline float deFloatFrExp(float x, int *exponent)
227 {
228     return (float)frexp(x, exponent);
229 }
230 float deFloatFractExp(float x, int *exponent);
231 
deSign(double x)232 static inline double deSign(double x)
233 {
234     return deDoubleIsIEEENaN(x) ? x : (double)((x > 0.0) - (x < 0.0));
235 }
deIntSign(double x)236 static inline int deIntSign(double x)
237 {
238     return (x > 0.0) - (x < 0.0);
239 }
deFloor(double a)240 static inline double deFloor(double a)
241 {
242     return floor(a);
243 }
deCeil(double a)244 static inline double deCeil(double a)
245 {
246     return ceil(a);
247 }
deRound(double a)248 static inline double deRound(double a)
249 {
250     return floor(a + 0.5);
251 }
deFrac(double a)252 static inline double deFrac(double a)
253 {
254     return a - deFloor(a);
255 }
deMod(double a,double b)256 static inline double deMod(double a, double b)
257 {
258     return fmod(a, b);
259 }
deModf(double x,double * i)260 static inline double deModf(double x, double *i)
261 {
262     return modf(x, i);
263 }
deMadd(double a,double b,double c)264 static inline double deMadd(double a, double b, double c)
265 {
266     return (a * b) + c;
267 }
deTrunc(double a)268 static inline double deTrunc(double a)
269 {
270     return deSign(a) * floor(fabs(a));
271 }
deLdExp(double a,int exponent)272 static inline double deLdExp(double a, int exponent)
273 {
274     return ldexp(a, exponent);
275 }
276 double deRoundEven(double a);
deFrExp(double x,int * exponent)277 static inline double deFrExp(double x, int *exponent)
278 {
279     return frexp(x, exponent);
280 }
281 /* Like frexp, except the returned fraction is in range [1.0, 2.0) */
282 double deFractExp(double x, int *exponent);
283 
284 /* Exponential functions. */
285 
deFloatPow(float a,float b)286 static inline float deFloatPow(float a, float b)
287 {
288     return (float)pow(a, b);
289 }
deFloatExp(float a)290 static inline float deFloatExp(float a)
291 {
292     return (float)exp(a);
293 }
deFloatLog(float a)294 static inline float deFloatLog(float a)
295 {
296     return (float)log(a);
297 }
deFloatExp2(float a)298 static inline float deFloatExp2(float a)
299 {
300     return (float)exp(a * DE_LOG_2);
301 }
deFloatLog2(float a)302 static inline float deFloatLog2(float a)
303 {
304     return (float)log(a) * DE_INV_LOG_2;
305 }
deFloatSqrt(float a)306 static inline float deFloatSqrt(float a)
307 {
308     return (float)sqrt(a);
309 }
deFloatRcp(float a)310 static inline float deFloatRcp(float a)
311 {
312     return (1.0f / a);
313 }
deFloatRsq(float a)314 static inline float deFloatRsq(float a)
315 {
316     float s = (float)sqrt(a);
317     return (s == 0.0f) ? 0.0f : (1.0f / s);
318 }
319 
dePow(double a,double b)320 static inline double dePow(double a, double b)
321 {
322     return pow(a, b);
323 }
deExp(double a)324 static inline double deExp(double a)
325 {
326     return exp(a);
327 }
deLog(double a)328 static inline double deLog(double a)
329 {
330     return log(a);
331 }
deExp2(double a)332 static inline double deExp2(double a)
333 {
334     return exp(a * log(2.0));
335 }
deLog2(double a)336 static inline double deLog2(double a)
337 {
338     return log(a) / log(2.0);
339 }
deSqrt(double a)340 static inline double deSqrt(double a)
341 {
342     return sqrt(a);
343 }
deCbrt(double a)344 static inline double deCbrt(double a)
345 {
346     return deSign(a) * dePow(deAbs(a), 1.0 / 3.0);
347 }
348 
349 /* Geometric functions. */
350 
deFloatRadians(float a)351 static inline float deFloatRadians(float a)
352 {
353     return a * (DE_PI / 180.0f);
354 }
deFloatDegrees(float a)355 static inline float deFloatDegrees(float a)
356 {
357     return a * (180.0f / DE_PI);
358 }
deFloatSin(float a)359 static inline float deFloatSin(float a)
360 {
361     return (float)sin(a);
362 }
deFloatCos(float a)363 static inline float deFloatCos(float a)
364 {
365     return (float)cos(a);
366 }
deFloatTan(float a)367 static inline float deFloatTan(float a)
368 {
369     return (float)tan(a);
370 }
deFloatAsin(float a)371 static inline float deFloatAsin(float a)
372 {
373     return (float)asin(a);
374 }
deFloatAcos(float a)375 static inline float deFloatAcos(float a)
376 {
377     return (float)acos(a);
378 }
deFloatAtan2(float y,float x)379 static inline float deFloatAtan2(float y, float x)
380 {
381     return (float)atan2(y, x);
382 }
deFloatAtanOver(float yOverX)383 static inline float deFloatAtanOver(float yOverX)
384 {
385     return (float)atan(yOverX);
386 }
deFloatSinh(float a)387 static inline float deFloatSinh(float a)
388 {
389     return (float)sinh(a);
390 }
deFloatCosh(float a)391 static inline float deFloatCosh(float a)
392 {
393     return (float)cosh(a);
394 }
deFloatTanh(float a)395 static inline float deFloatTanh(float a)
396 {
397     return (float)tanh(a);
398 }
deFloatAsinh(float a)399 static inline float deFloatAsinh(float a)
400 {
401     return deFloatLog(a + deFloatSqrt(a * a + 1));
402 }
deFloatAcosh(float a)403 static inline float deFloatAcosh(float a)
404 {
405     return deFloatLog(a + deFloatSqrt(a * a - 1));
406 }
deFloatAtanh(float a)407 static inline float deFloatAtanh(float a)
408 {
409     return 0.5f * deFloatLog((1.0f + a) / (1.0f - a));
410 }
411 
deSin(double a)412 static inline double deSin(double a)
413 {
414     return sin(a);
415 }
deCos(double a)416 static inline double deCos(double a)
417 {
418     return cos(a);
419 }
deTan(double a)420 static inline double deTan(double a)
421 {
422     return tan(a);
423 }
deAsin(double a)424 static inline double deAsin(double a)
425 {
426     return asin(a);
427 }
deAcos(double a)428 static inline double deAcos(double a)
429 {
430     return acos(a);
431 }
deAtan2(double y,double x)432 static inline double deAtan2(double y, double x)
433 {
434     return atan2(y, x);
435 }
deAtanOver(double yOverX)436 static inline double deAtanOver(double yOverX)
437 {
438     return atan(yOverX);
439 }
deSinh(double a)440 static inline double deSinh(double a)
441 {
442     return sinh(a);
443 }
deCosh(double a)444 static inline double deCosh(double a)
445 {
446     return cosh(a);
447 }
deTanh(double a)448 static inline double deTanh(double a)
449 {
450     return tanh(a);
451 }
deAsinh(double a)452 static inline double deAsinh(double a)
453 {
454     return deLog(a + deSqrt(a * a + 1));
455 }
deAcosh(double a)456 static inline double deAcosh(double a)
457 {
458     return deLog(a + deSqrt(a * a - 1));
459 }
deAtanh(double a)460 static inline double deAtanh(double a)
461 {
462     return 0.5 * deLog((1.0 + a) / (1.0 - a));
463 }
464 
465 /* Interpolation. */
466 
deFloatMix(float a,float b,float t)467 static inline float deFloatMix(float a, float b, float t)
468 {
469     return a * (1.0f - t) + b * t;
470 }
deFloatStep(float limit,float val)471 static inline float deFloatStep(float limit, float val)
472 {
473     return (val < limit) ? 0.0f : 1.0f;
474 }
deFloatSmoothStep(float e0,float e1,float v)475 static inline float deFloatSmoothStep(float e0, float e1, float v)
476 {
477     float t;
478     if (v <= e0)
479         return 0.0f;
480     if (v >= e1)
481         return 1.0f;
482     t = (v - e0) / (e1 - e0);
483     return t * t * (3.0f - 2.0f * t);
484 }
485 
deMix(double a,double b,double t)486 static inline double deMix(double a, double b, double t)
487 {
488     return a * (1.0 - t) + b * t;
489 }
deStep(double limit,double val)490 static inline double deStep(double limit, double val)
491 {
492     return (val < limit) ? 0.0 : 1.0;
493 }
494 
495 /* Convert int to float. If the value cannot be represented exactly in native single precision format, return
496  * either the nearest lower or the nearest higher representable value, chosen in an implementation-defined manner.
497  *
498  * \note Choosing either nearest lower or nearest higher means that implementation could for example consistently
499  *       choose the lower value, i.e. this function does not round towards nearest.
500  * \note Value returned is in native single precision format. For example with x86 extended precision, the value
501  *       returned might not be representable in IEEE single precision float.
502  */
deInt32ToFloat(int32_t x)503 static inline float deInt32ToFloat(int32_t x)
504 {
505     return (float)x;
506 }
507 
508 /* Convert to float. If the value cannot be represented exactly in IEEE single precision floating point format,
509  * return the nearest lower (round towards negative inf). */
510 float deInt32ToFloatRoundToNegInf(int32_t x);
511 
512 /* Convert to float. If the value cannot be represented exactly IEEE single precision floating point format,
513  * return the nearest higher (round towards positive inf). */
514 float deInt32ToFloatRoundToPosInf(int32_t x);
515 
516 /* Conversion to integer. */
517 
deChopFloatToInt32(float x)518 static inline int32_t deChopFloatToInt32(float x)
519 {
520     return (int32_t)x;
521 }
deFloorFloatToInt32(float x)522 static inline int32_t deFloorFloatToInt32(float x)
523 {
524     return (int32_t)(deFloatFloor(x));
525 }
deCeilFloatToInt32(float x)526 static inline int32_t deCeilFloatToInt32(float x)
527 {
528     return (int32_t)(deFloatCeil(x));
529 }
530 
deChopToInt32(double x)531 static inline int32_t deChopToInt32(double x)
532 {
533     return (int32_t)x;
534 }
deFloorToInt32(double x)535 static inline int32_t deFloorToInt32(double x)
536 {
537     return (int32_t)(deFloor(x));
538 }
deCeilToInt32(double x)539 static inline int32_t deCeilToInt32(double x)
540 {
541     return (int32_t)(deCeil(x));
542 }
543 
544 /* Arithmetic round */
deRoundFloatToInt16(float x)545 static inline int16_t deRoundFloatToInt16(float x)
546 {
547     if (x >= 0.0f)
548         return (int16_t)(x + 0.5f);
549     else
550         return (int16_t)(x - 0.5f);
551 }
deRoundFloatToInt32(float x)552 static inline int32_t deRoundFloatToInt32(float x)
553 {
554     if (x >= 0.0f)
555         return (int32_t)(x + 0.5f);
556     else
557         return (int32_t)(x - 0.5f);
558 }
deRoundFloatToInt64(float x)559 static inline int64_t deRoundFloatToInt64(float x)
560 {
561     if (x >= 0.0f)
562         return (int64_t)(x + 0.5f);
563     else
564         return (int64_t)(x - 0.5f);
565 }
566 
deRoundToInt16(double x)567 static inline int16_t deRoundToInt16(double x)
568 {
569     if (x >= 0.0)
570         return (int16_t)(x + 0.5);
571     else
572         return (int16_t)(x - 0.5);
573 }
deRoundToInt32(double x)574 static inline int32_t deRoundToInt32(double x)
575 {
576     if (x >= 0.0)
577         return (int32_t)(x + 0.5);
578     else
579         return (int32_t)(x - 0.5);
580 }
deRoundToInt64(double x)581 static inline int64_t deRoundToInt64(double x)
582 {
583     if (x >= 0.0)
584         return (int64_t)(x + 0.5);
585     else
586         return (int64_t)(x - 0.5);
587 }
588 
589 DE_END_EXTERN_C
590 
591 #endif /* _DEMATH_H */
592