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
28 #include <math.h>
29 #include <float.h>
30
31 DE_BEGIN_EXTERN_C
32
33 /* Mathematical constants. */
34
35 #define DE_PI 3.14159265358979324f /*!< Pi. */
36 #define DE_LOG_2 0.69314718056f /*!< log_e(2.0) */
37 #define DE_INV_LOG_2 1.44269504089f /*!< 1.0 / log_e(2.0) */
38 #define DE_E 2.71828182845904523536f /*!< e. */
39 #define DE_LOG2_E 1.44269504088896340736f /*!< log_2(e). */
40 #define DE_INV_LOG2_E 0.69314718055994530942f /*!< 1.0 / log_2(e). */
41
42 #define DE_PI_DOUBLE 3.14159265358979323846 /*!< Pi as a double. */
43 #define DE_PI_16BIT 0x4248 /*!< Pi. as a float16b */
44
45 /* Rounding mode control. */
46
47 typedef enum deRoundingMode_e
48 {
49 DE_ROUNDINGMODE_TO_NEAREST_EVEN = 0,
50 DE_ROUNDINGMODE_TO_ZERO,
51 DE_ROUNDINGMODE_TO_POSITIVE_INF,
52 DE_ROUNDINGMODE_TO_NEGATIVE_INF,
53
54 DE_ROUNDINGMODE_LAST
55 } deRoundingMode;
56
57 deRoundingMode deGetRoundingMode (void);
58 deBool deSetRoundingMode (deRoundingMode mode);
59
60 void deMath_selfTest (void);
61
62 /* Float properties */
63
64 /* \note The NaN test probably won't work with -ffast-math */
65
deFloatIsInf(float x)66 DE_INLINE int deFloatIsInf (float x) { return (x > FLT_MAX) - (x < -FLT_MAX); }
deFloatIsNaN(float x)67 DE_INLINE deBool deFloatIsNaN (float x) { return (x != x); }
68
deIsInf(double x)69 DE_INLINE int deIsInf (double x) { return (x > DBL_MAX) - (x < -DBL_MAX); }
deIsNaN(double x)70 DE_INLINE deBool deIsNaN (double x) { return (x != x); }
71
72 /* Basic utilities. */
73
deFloatAbs(float x)74 DE_INLINE float deFloatAbs (float x) { return (x >= 0.0f) ? x : -x; }
deFloatMin(float a,float b)75 DE_INLINE float deFloatMin (float a, float b) { return (a <= b) ? a : b; }
deFloatMax(float a,float b)76 DE_INLINE float deFloatMax (float a, float b) { return (a >= b) ? a : b; }
deFloatClamp(float x,float mn,float mx)77 DE_INLINE float deFloatClamp (float x, float mn, float mx) { return (x <= mn) ? mn : ((x >= mx) ? mx : x); }
78
deAbs(double x)79 DE_INLINE double deAbs (double x) { return (x >= 0.0) ? x : -x; }
deMin(double a,double b)80 DE_INLINE double deMin (double a, double b) { return (a <= b) ? a : b; }
deMax(double a,double b)81 DE_INLINE double deMax (double a, double b) { return (a >= b) ? a : b; }
deClamp(double x,double mn,double mx)82 DE_INLINE double deClamp (double x, double mn, double mx) { return (x <= mn) ? mn : ((x >= mx) ? mx : x); }
83
84 /* Utility functions. */
85
deFloatSign(float a)86 DE_INLINE float deFloatSign (float a) { return (a == 0.0f) ? 0.0f : ((a > 0.0f) ? +1.0f : -1.0f); }
deFloatIntSign(float a)87 DE_INLINE int deFloatIntSign (float a) { return (a == 0.0f) ? 0 : ((a > 0.0f) ? +1 : -1); }
deFloatFloor(float a)88 DE_INLINE float deFloatFloor (float a) { return (float)floor(a); }
deFloatCeil(float a)89 DE_INLINE float deFloatCeil (float a) { return (float)ceil(a); }
deFloatRound(float a)90 DE_INLINE float deFloatRound (float a) { return deFloatFloor(a + 0.5f); }
deFloatFrac(float a)91 DE_INLINE float deFloatFrac (float a) { return a - deFloatFloor(a); }
deFloatMod(float a,float b)92 DE_INLINE float deFloatMod (float a, float b) { return (float)fmod(a, b); }
deFloatModf(float x,float * i)93 DE_INLINE float deFloatModf (float x, float* i) { double j = 0; double ret = modf(x, &j); *i = (float)j; return (float)ret; }
deFloatMadd(float a,float b,float c)94 DE_INLINE float deFloatMadd (float a, float b, float c) { return (a*b) + c; }
deFloatTrunc(float a)95 DE_INLINE float deFloatTrunc (float a) { return deFloatSign(a) * deFloatFloor(deFloatAbs(a)); }
deFloatLdExp(float a,int exponent)96 DE_INLINE float deFloatLdExp (float a, int exponent) { return (float)ldexp(a, exponent); }
deFloatFrExp(float x,int * exponent)97 DE_INLINE float deFloatFrExp (float x, int* exponent) { return (float)frexp(x, exponent); }
98 float deFloatFractExp (float x, int* exponent);
99
deSign(double x)100 DE_INLINE double deSign (double x) { return deIsNaN(x) ? x : (double)((x > 0.0) - (x < 0.0)); }
deIntSign(double x)101 DE_INLINE int deIntSign (double x) { return (x > 0.0) - (x < 0.0); }
deFloor(double a)102 DE_INLINE double deFloor (double a) { return floor(a); }
deCeil(double a)103 DE_INLINE double deCeil (double a) { return ceil(a); }
deRound(double a)104 DE_INLINE double deRound (double a) { return floor(a + 0.5); }
deFrac(double a)105 DE_INLINE double deFrac (double a) { return a - deFloor(a); }
deMod(double a,double b)106 DE_INLINE double deMod (double a, double b) { return fmod(a, b); }
deModf(double x,double * i)107 DE_INLINE double deModf (double x, double* i) { return modf(x, i); }
deMadd(double a,double b,double c)108 DE_INLINE double deMadd (double a, double b, double c) { return (a*b) + c; }
deTrunc(double a)109 DE_INLINE double deTrunc (double a) { return deSign(a) * floor(fabs(a)); }
deLdExp(double a,int exponent)110 DE_INLINE double deLdExp (double a, int exponent) { return ldexp(a, exponent); }
111 double deRoundEven (double a);
deFrExp(double x,int * exponent)112 DE_INLINE double deFrExp (double x, int* exponent) { return frexp(x, exponent); }
113 /* Like frexp, except the returned fraction is in range [1.0, 2.0) */
114 double deFractExp (double x, int* exponent);
115
116 /* Exponential functions. */
117
deFloatPow(float a,float b)118 DE_INLINE float deFloatPow (float a, float b) { return (float)pow(a, b); }
deFloatExp(float a)119 DE_INLINE float deFloatExp (float a) { return (float)exp(a); }
deFloatLog(float a)120 DE_INLINE float deFloatLog (float a) { return (float)log(a); }
deFloatExp2(float a)121 DE_INLINE float deFloatExp2 (float a) { return (float)exp(a * DE_LOG_2); }
deFloatLog2(float a)122 DE_INLINE float deFloatLog2 (float a) { return (float)log(a) * DE_INV_LOG_2; }
deFloatSqrt(float a)123 DE_INLINE float deFloatSqrt (float a) { return (float)sqrt(a); }
deFloatRcp(float a)124 DE_INLINE float deFloatRcp (float a) { return (1.0f / a); }
deFloatRsq(float a)125 DE_INLINE float deFloatRsq (float a) { float s = (float)sqrt(a); return (s == 0.0f) ? 0.0f : (1.0f / s); }
126
dePow(double a,double b)127 DE_INLINE double dePow (double a, double b) { return pow(a, b); }
deExp(double a)128 DE_INLINE double deExp (double a) { return exp(a); }
deLog(double a)129 DE_INLINE double deLog (double a) { return log(a); }
deExp2(double a)130 DE_INLINE double deExp2 (double a) { return exp(a * log(2.0)); }
deLog2(double a)131 DE_INLINE double deLog2 (double a) { return log(a) / log(2.0); }
deSqrt(double a)132 DE_INLINE double deSqrt (double a) { return sqrt(a); }
deCbrt(double a)133 DE_INLINE double deCbrt (double a) { return deSign(a) * dePow(deAbs(a), 1.0 / 3.0); }
134
135 /* Geometric functions. */
136
deFloatRadians(float a)137 DE_INLINE float deFloatRadians (float a) { return a * (DE_PI / 180.0f); }
deFloatDegrees(float a)138 DE_INLINE float deFloatDegrees (float a) { return a * (180.0f / DE_PI); }
deFloatSin(float a)139 DE_INLINE float deFloatSin (float a) { return (float)sin(a); }
deFloatCos(float a)140 DE_INLINE float deFloatCos (float a) { return (float)cos(a); }
deFloatTan(float a)141 DE_INLINE float deFloatTan (float a) { return (float)tan(a); }
deFloatAsin(float a)142 DE_INLINE float deFloatAsin (float a) { return (float)asin(a); }
deFloatAcos(float a)143 DE_INLINE float deFloatAcos (float a) { return (float)acos(a); }
deFloatAtan2(float y,float x)144 DE_INLINE float deFloatAtan2 (float y, float x) { return (float)atan2(y, x); }
deFloatAtanOver(float yOverX)145 DE_INLINE float deFloatAtanOver (float yOverX) { return (float)atan(yOverX); }
deFloatSinh(float a)146 DE_INLINE float deFloatSinh (float a) { return (float)sinh(a); }
deFloatCosh(float a)147 DE_INLINE float deFloatCosh (float a) { return (float)cosh(a); }
deFloatTanh(float a)148 DE_INLINE float deFloatTanh (float a) { return (float)tanh(a); }
deFloatAsinh(float a)149 DE_INLINE float deFloatAsinh (float a) { return deFloatLog(a + deFloatSqrt(a*a + 1)); }
deFloatAcosh(float a)150 DE_INLINE float deFloatAcosh (float a) { return deFloatLog(a + deFloatSqrt(a*a - 1)); }
deFloatAtanh(float a)151 DE_INLINE float deFloatAtanh (float a) { return 0.5f*deFloatLog((1.0f+a)/(1.0f-a)); }
152
deSin(double a)153 DE_INLINE double deSin (double a) { return sin(a); }
deCos(double a)154 DE_INLINE double deCos (double a) { return cos(a); }
deTan(double a)155 DE_INLINE double deTan (double a) { return tan(a); }
deAsin(double a)156 DE_INLINE double deAsin (double a) { return asin(a); }
deAcos(double a)157 DE_INLINE double deAcos (double a) { return acos(a); }
deAtan2(double y,double x)158 DE_INLINE double deAtan2 (double y, double x) { return atan2(y, x); }
deAtanOver(double yOverX)159 DE_INLINE double deAtanOver (double yOverX) { return atan(yOverX); }
deSinh(double a)160 DE_INLINE double deSinh (double a) { return sinh(a); }
deCosh(double a)161 DE_INLINE double deCosh (double a) { return cosh(a); }
deTanh(double a)162 DE_INLINE double deTanh (double a) { return tanh(a); }
deAsinh(double a)163 DE_INLINE double deAsinh (double a) { return deLog(a + deSqrt(a*a + 1)); }
deAcosh(double a)164 DE_INLINE double deAcosh (double a) { return deLog(a + deSqrt(a*a - 1)); }
deAtanh(double a)165 DE_INLINE double deAtanh (double a) { return 0.5*deLog((1.0+a)/(1.0-a)); }
166
167 /* Interpolation. */
168
deFloatMix(float a,float b,float t)169 DE_INLINE float deFloatMix (float a, float b, float t) { return a*(1.0f-t) + b*t; }
deFloatStep(float limit,float val)170 DE_INLINE float deFloatStep (float limit, float val) { return (val < limit) ? 0.0f : 1.0f; }
deFloatSmoothStep(float e0,float e1,float v)171 DE_INLINE float deFloatSmoothStep (float e0, float e1, float v)
172 {
173 float t;
174 if (v <= e0) return 0.0f;
175 if (v >= e1) return 1.0f;
176 t = (v - e0) / (e1 - e0);
177 return t * t * (3.0f - 2.0f * t);
178 }
179
deMix(double a,double b,double t)180 DE_INLINE double deMix (double a, double b, double t) { return a*(1.0-t) + b*t; }
deStep(double limit,double val)181 DE_INLINE double deStep (double limit, double val) { return (val < limit) ? 0.0 : 1.0; }
182
183 /* Comparison functions. */
184
deFloatCmpEQ(float a,float b)185 DE_INLINE deBool deFloatCmpEQ (float a, float b) { return (a == b); }
deFloatCmpNE(float a,float b)186 DE_INLINE deBool deFloatCmpNE (float a, float b) { return (a != b); }
deFloatCmpLT(float a,float b)187 DE_INLINE deBool deFloatCmpLT (float a, float b) { return (a < b); }
deFloatCmpLE(float a,float b)188 DE_INLINE deBool deFloatCmpLE (float a, float b) { return (a <= b); }
deFloatCmpGT(float a,float b)189 DE_INLINE deBool deFloatCmpGT (float a, float b) { return (a > b); }
deFloatCmpGE(float a,float b)190 DE_INLINE deBool deFloatCmpGE (float a, float b) { return (a >= b); }
191
192 /* Convert int to float. If the value cannot be represented exactly in native single precision format, return
193 * either the nearest lower or the nearest higher representable value, chosen in an implementation-defined manner.
194 *
195 * \note Choosing either nearest lower or nearest higher means that implementation could for example consistently
196 * choose the lower value, i.e. this function does not round towards nearest.
197 * \note Value returned is in native single precision format. For example with x86 extended precision, the value
198 * returned might not be representable in IEEE single precision float.
199 */
deInt32ToFloat(deInt32 x)200 DE_INLINE float deInt32ToFloat (deInt32 x) { return (float)x; }
201
202 /* Convert to float. If the value cannot be represented exactly in IEEE single precision floating point format,
203 * return the nearest lower (round towards negative inf). */
204 float deInt32ToFloatRoundToNegInf (deInt32 x);
205
206 /* Convert to float. If the value cannot be represented exactly IEEE single precision floating point format,
207 * return the nearest higher (round towards positive inf). */
208 float deInt32ToFloatRoundToPosInf (deInt32 x);
209
210 /* Conversion to integer. */
211
deChopFloatToInt32(float x)212 DE_INLINE deInt32 deChopFloatToInt32 (float x) { return (deInt32)x; }
deFloorFloatToInt32(float x)213 DE_INLINE deInt32 deFloorFloatToInt32 (float x) { return (deInt32)(deFloatFloor(x)); }
deCeilFloatToInt32(float x)214 DE_INLINE deInt32 deCeilFloatToInt32 (float x) { return (deInt32)(deFloatCeil(x)); }
215
deChopToInt32(double x)216 DE_INLINE deInt32 deChopToInt32 (double x) { return (deInt32)x; }
deFloorToInt32(double x)217 DE_INLINE deInt32 deFloorToInt32 (double x) { return (deInt32)(deFloor(x)); }
deCeilToInt32(double x)218 DE_INLINE deInt32 deCeilToInt32 (double x) { return (deInt32)(deCeil(x)); }
219
220 /* Arithmetic round */
deRoundFloatToInt16(float x)221 DE_INLINE deInt16 deRoundFloatToInt16 (float x) { if(x >= 0.0f) return (deInt16)(x + 0.5f); else return (deInt16)(x - 0.5f); }
deRoundFloatToInt32(float x)222 DE_INLINE deInt32 deRoundFloatToInt32 (float x) { if(x >= 0.0f) return (deInt32)(x + 0.5f); else return (deInt32)(x - 0.5f); }
deRoundFloatToInt64(float x)223 DE_INLINE deInt64 deRoundFloatToInt64 (float x) { if(x >= 0.0f) return (deInt64)(x + 0.5f); else return (deInt64)(x - 0.5f); }
224
deRoundToInt16(double x)225 DE_INLINE deInt16 deRoundToInt16 (double x) { if(x >= 0.0) return (deInt16)(x + 0.5); else return (deInt16)(x - 0.5); }
deRoundToInt32(double x)226 DE_INLINE deInt32 deRoundToInt32 (double x) { if(x >= 0.0) return (deInt32)(x + 0.5); else return (deInt32)(x - 0.5); }
deRoundToInt64(double x)227 DE_INLINE deInt64 deRoundToInt64 (double x) { if(x >= 0.0) return (deInt64)(x + 0.5); else return (deInt64)(x - 0.5); }
228
229 DE_END_EXTERN_C
230
231 #endif /* _DEMATH_H */
232