• 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 deBool				deSetRoundingMode	(deRoundingMode mode);
60 
61 void				deMath_selfTest		(void);
62 
63 /* Float properties */
64 
65 /* \note The NaN test probably won't work with -ffast-math */
66 
deFloatIsInf(float x)67 DE_INLINE int		deFloatIsInf		(float x)		{ return (x > FLT_MAX) - (x < -FLT_MAX); }
deFloatIsNaN(float x)68 DE_INLINE deBool	deFloatIsNaN		(float x)		{ return (x != x); }
69 
deIsInf(double x)70 DE_INLINE int		deIsInf				(double x)		{ return (x > DBL_MAX) - (x < -DBL_MAX); }
deIsNaN(double x)71 DE_INLINE deBool	deIsNaN				(double x)		{ return (x != x); }
72 
deFloatBitsToUint32(float x)73 DE_INLINE deUint32 deFloatBitsToUint32(float x)
74 {
75 	deUint32 bits;
76 	deMemcpy((void *)&bits, (void *)&x, 4);
77 	return bits;
78 }
79 
deDoubleBitsToUint64(double x)80 DE_INLINE deUint64 deDoubleBitsToUint64(double x)
81 {
82 	deUint64 bits;
83 	deMemcpy((void *)&bits, (void *)&x, 8);
84 	return bits;
85 }
86 
deFloatIsPositiveZero(float x)87 DE_INLINE deBool deFloatIsPositiveZero(float x)
88 {
89 	return x == 0 && (deFloatBitsToUint32(x) >> 31) == 0;
90 }
91 
deDoubleIsPositiveZero(double x)92 DE_INLINE deBool deDoubleIsPositiveZero(double x)
93 {
94 	return x == 0 && (deDoubleBitsToUint64(x) >> 63) == 0;
95 }
96 
deFloatIsNegativeZero(float x)97 DE_INLINE deBool deFloatIsNegativeZero(float x)
98 {
99 	return x == 0 && (deFloatBitsToUint32(x) >> 31) != 0;
100 }
101 
deDoubleIsNegativeZero(double x)102 DE_INLINE deBool deDoubleIsNegativeZero(double x)
103 {
104 	return x == 0 && (deDoubleBitsToUint64(x) >> 63) != 0;
105 }
106 
deFloatIsIEEENaN(float x)107 DE_INLINE deBool deFloatIsIEEENaN(float x)
108 {
109 	deUint32 e = (deFloatBitsToUint32(x) & 0x7f800000u) >> 23;
110 	deUint32 m = (deFloatBitsToUint32(x) & 0x007fffffu);
111 	return e == 0xff && m != 0;
112 }
113 
deDoubleIsIEEENaN(double x)114 DE_INLINE deBool deDoubleIsIEEENaN(double x)
115 {
116 	deUint64 e = (deDoubleBitsToUint64(x) & 0x7ff0000000000000ull) >> 52;
117 	deUint64 m = (deDoubleBitsToUint64(x) & 0x000fffffffffffffull);
118 	return e == 0x7ff && m != 0;
119 }
120 
121 /* \note The definition used for signaling NaN here is valid for ARM and
122  * x86 but possibly not for other platforms.
123  *
124  * These are defined as overloads so that they can be used in templated
125  * code without risking a type conversion which would triggern an exception
126  * on a signaling NaN.  We don't use deIsNan in these helpers because they
127  * do a comparison operation which may also trigger exceptions.
128  */
deFloatIsSignalingNaN(float x)129 DE_INLINE deBool deFloatIsSignalingNaN(float x)
130 {
131 	return deFloatIsIEEENaN(x) && (deFloatBitsToUint32(x) & (1u << 22)) == 0;
132 }
133 
deDoubleIsSignalingNaN(double x)134 DE_INLINE deBool deDoubleIsSignalingNaN(double x)
135 {
136 	return deDoubleIsIEEENaN(x) && (deDoubleBitsToUint64(x) & (1ull << 51)) == 0;
137 }
138 
deFloatIsQuietNaN(float x)139 DE_INLINE deBool deFloatIsQuietNaN(float x)
140 {
141 	return deFloatIsIEEENaN(x) && (deFloatBitsToUint32(x) & (1u << 22)) != 0;
142 }
143 
deDoubleIsQuietNaN(double x)144 DE_INLINE deBool deDoubleIsQuietNaN(double x)
145 {
146 	return deDoubleIsIEEENaN(x) && (deDoubleBitsToUint64(x) & (1ull << 51)) != 0;
147 }
148 
149 /* Basic utilities. */
150 
deFloatAbs(float x)151 DE_INLINE float		deFloatAbs			(float x)						{ return (x >= 0.0f) ? x : -x; }
deFloatMin(float a,float b)152 DE_INLINE float		deFloatMin			(float a, float b)				{ return (a <= b) ? a : b; }
deFloatMax(float a,float b)153 DE_INLINE float		deFloatMax			(float a, float b)				{ return (a >= b) ? a : b; }
deFloatClamp(float x,float mn,float mx)154 DE_INLINE float		deFloatClamp		(float x, float mn, float mx)	{ return (x <= mn) ? mn : ((x >= mx) ? mx : x); }
155 
deAbs(double x)156 DE_INLINE double	deAbs				(double x)							{ return (x >= 0.0) ? x : -x; }
deMin(double a,double b)157 DE_INLINE double	deMin				(double a, double b)				{ return (a <= b) ? a : b; }
deMax(double a,double b)158 DE_INLINE double	deMax				(double a, double b)				{ return (a >= b) ? a : b; }
deClamp(double x,double mn,double mx)159 DE_INLINE double	deClamp				(double x, double mn, double mx)	{ return (x <= mn) ? mn : ((x >= mx) ? mx : x); }
160 
161 /* Utility functions. */
162 
deFloatSign(float a)163 DE_INLINE float		deFloatSign			(float a)					{ return (a == 0.0f) ? 0.0f : ((a > 0.0f) ? +1.0f : -1.0f); }
deFloatIntSign(float a)164 DE_INLINE int		deFloatIntSign		(float a)					{ return (a == 0.0f) ? 0 : ((a > 0.0f) ? +1 : -1); }
deFloatFloor(float a)165 DE_INLINE float		deFloatFloor		(float a)					{ return (float)floor(a); }
deFloatCeil(float a)166 DE_INLINE float		deFloatCeil			(float a)					{ return (float)ceil(a); }
deFloatRound(float a)167 DE_INLINE float		deFloatRound		(float a)					{ return deFloatFloor(a + 0.5f); }
deFloatFrac(float a)168 DE_INLINE float		deFloatFrac			(float a)					{ return a - deFloatFloor(a); }
deFloatMod(float a,float b)169 DE_INLINE float		deFloatMod			(float a, float b)			{ return (float)fmod(a, b); }
deFloatModf(float x,float * i)170 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)171 DE_INLINE float		deFloatMadd			(float a, float b, float c)	{ return (a*b) + c; }
deFloatTrunc(float a)172 DE_INLINE float		deFloatTrunc		(float a)					{ return deFloatSign(a) * deFloatFloor(deFloatAbs(a)); }
deFloatLdExp(float a,int exponent)173 DE_INLINE float		deFloatLdExp		(float a, int exponent)		{ return (float)ldexp(a, exponent); }
deFloatFrExp(float x,int * exponent)174 DE_INLINE float		deFloatFrExp		(float x, int* exponent)	{ return (float)frexp(x, exponent); }
175 float				deFloatFractExp		(float x, int* exponent);
176 
deSign(double x)177 DE_INLINE double	deSign				(double x)						{ return deIsNaN(x) ? x : (double)((x > 0.0) - (x < 0.0)); }
deIntSign(double x)178 DE_INLINE int		deIntSign			(double x)						{ return (x > 0.0) - (x < 0.0); }
deFloor(double a)179 DE_INLINE double	deFloor				(double a)						{ return floor(a); }
deCeil(double a)180 DE_INLINE double	deCeil				(double a)						{ return ceil(a); }
deRound(double a)181 DE_INLINE double	deRound				(double a)						{ return floor(a + 0.5); }
deFrac(double a)182 DE_INLINE double	deFrac				(double a)						{ return a - deFloor(a); }
deMod(double a,double b)183 DE_INLINE double	deMod				(double a, double b)			{ return fmod(a, b); }
deModf(double x,double * i)184 DE_INLINE double	deModf				(double x, double* i)			{ return modf(x, i); }
deMadd(double a,double b,double c)185 DE_INLINE double	deMadd				(double a, double b, double c)	{ return (a*b) + c; }
deTrunc(double a)186 DE_INLINE double	deTrunc				(double a)						{ return deSign(a) * floor(fabs(a)); }
deLdExp(double a,int exponent)187 DE_INLINE double	deLdExp				(double a, int exponent)		{ return ldexp(a, exponent); }
188 double				deRoundEven			(double a);
deFrExp(double x,int * exponent)189 DE_INLINE double	deFrExp				(double x, int* exponent)		{ return frexp(x, exponent); }
190 /* Like frexp, except the returned fraction is in range [1.0, 2.0) */
191 double				deFractExp			(double x, int* exponent);
192 
193 /* Exponential functions. */
194 
deFloatPow(float a,float b)195 DE_INLINE float		deFloatPow			(float a, float b)			{ return (float)pow(a, b); }
deFloatExp(float a)196 DE_INLINE float		deFloatExp			(float a)					{ return (float)exp(a); }
deFloatLog(float a)197 DE_INLINE float		deFloatLog			(float a)					{ return (float)log(a); }
deFloatExp2(float a)198 DE_INLINE float		deFloatExp2			(float a)					{ return (float)exp(a * DE_LOG_2); }
deFloatLog2(float a)199 DE_INLINE float		deFloatLog2			(float a)					{ return (float)log(a) * DE_INV_LOG_2; }
deFloatSqrt(float a)200 DE_INLINE float		deFloatSqrt			(float a)					{ return (float)sqrt(a); }
deFloatRcp(float a)201 DE_INLINE float		deFloatRcp			(float a)					{ return (1.0f / a); }
deFloatRsq(float a)202 DE_INLINE float		deFloatRsq			(float a)					{ float s = (float)sqrt(a); return (s == 0.0f) ? 0.0f : (1.0f / s); }
203 
dePow(double a,double b)204 DE_INLINE double	dePow				(double a, double b)		{ return pow(a, b); }
deExp(double a)205 DE_INLINE double	deExp				(double a)					{ return exp(a); }
deLog(double a)206 DE_INLINE double	deLog				(double a)					{ return log(a); }
deExp2(double a)207 DE_INLINE double	deExp2				(double a)					{ return exp(a * log(2.0)); }
deLog2(double a)208 DE_INLINE double	deLog2				(double a)					{ return log(a) / log(2.0); }
deSqrt(double a)209 DE_INLINE double	deSqrt				(double a)					{ return sqrt(a); }
deCbrt(double a)210 DE_INLINE double	deCbrt				(double a)					{ return deSign(a) * dePow(deAbs(a), 1.0 / 3.0); }
211 
212 /* Geometric functions. */
213 
deFloatRadians(float a)214 DE_INLINE float		deFloatRadians		(float a)					{ return a * (DE_PI / 180.0f); }
deFloatDegrees(float a)215 DE_INLINE float		deFloatDegrees		(float a)					{ return a * (180.0f / DE_PI); }
deFloatSin(float a)216 DE_INLINE float		deFloatSin			(float a)					{ return (float)sin(a); }
deFloatCos(float a)217 DE_INLINE float		deFloatCos			(float a)					{ return (float)cos(a); }
deFloatTan(float a)218 DE_INLINE float		deFloatTan			(float a)					{ return (float)tan(a); }
deFloatAsin(float a)219 DE_INLINE float		deFloatAsin			(float a)					{ return (float)asin(a); }
deFloatAcos(float a)220 DE_INLINE float		deFloatAcos			(float a)					{ return (float)acos(a); }
deFloatAtan2(float y,float x)221 DE_INLINE float		deFloatAtan2		(float y, float x)			{ return (float)atan2(y, x); }
deFloatAtanOver(float yOverX)222 DE_INLINE float		deFloatAtanOver		(float yOverX)				{ return (float)atan(yOverX); }
deFloatSinh(float a)223 DE_INLINE float		deFloatSinh			(float a)					{ return (float)sinh(a); }
deFloatCosh(float a)224 DE_INLINE float		deFloatCosh			(float a)					{ return (float)cosh(a); }
deFloatTanh(float a)225 DE_INLINE float		deFloatTanh			(float a)					{ return (float)tanh(a); }
deFloatAsinh(float a)226 DE_INLINE float		deFloatAsinh		(float a)					{ return deFloatLog(a + deFloatSqrt(a*a + 1)); }
deFloatAcosh(float a)227 DE_INLINE float		deFloatAcosh		(float a)					{ return deFloatLog(a + deFloatSqrt(a*a - 1)); }
deFloatAtanh(float a)228 DE_INLINE float		deFloatAtanh		(float a)					{ return 0.5f*deFloatLog((1.0f+a)/(1.0f-a)); }
229 
deSin(double a)230 DE_INLINE double	deSin			(double a)						{ return sin(a); }
deCos(double a)231 DE_INLINE double	deCos			(double a)						{ return cos(a); }
deTan(double a)232 DE_INLINE double	deTan			(double a)						{ return tan(a); }
deAsin(double a)233 DE_INLINE double	deAsin			(double a)						{ return asin(a); }
deAcos(double a)234 DE_INLINE double	deAcos			(double a)						{ return acos(a); }
deAtan2(double y,double x)235 DE_INLINE double	deAtan2			(double y, double x)			{ return atan2(y, x); }
deAtanOver(double yOverX)236 DE_INLINE double	deAtanOver		(double yOverX)					{ return atan(yOverX); }
deSinh(double a)237 DE_INLINE double	deSinh			(double a)						{ return sinh(a); }
deCosh(double a)238 DE_INLINE double	deCosh			(double a)						{ return cosh(a); }
deTanh(double a)239 DE_INLINE double	deTanh			(double a)						{ return tanh(a); }
deAsinh(double a)240 DE_INLINE double	deAsinh			(double a)						{ return deLog(a + deSqrt(a*a + 1)); }
deAcosh(double a)241 DE_INLINE double	deAcosh			(double a)						{ return deLog(a + deSqrt(a*a - 1)); }
deAtanh(double a)242 DE_INLINE double	deAtanh			(double a)						{ return 0.5*deLog((1.0+a)/(1.0-a)); }
243 
244 /* Interpolation. */
245 
deFloatMix(float a,float b,float t)246 DE_INLINE float		deFloatMix			(float a, float b, float t)	{ return a*(1.0f-t) + b*t; }
deFloatStep(float limit,float val)247 DE_INLINE float		deFloatStep			(float limit, float val)	{ return (val < limit) ? 0.0f : 1.0f; }
deFloatSmoothStep(float e0,float e1,float v)248 DE_INLINE float		deFloatSmoothStep	(float e0, float e1, float v)
249 {
250 	float t;
251 	if (v <= e0) return 0.0f;
252 	if (v >= e1) return 1.0f;
253 	t = (v - e0) / (e1 - e0);
254 	return t * t * (3.0f - 2.0f * t);
255 }
256 
deMix(double a,double b,double t)257 DE_INLINE double	deMix				(double a, double b, double t)	{ return a*(1.0-t) + b*t; }
deStep(double limit,double val)258 DE_INLINE double	deStep				(double limit, double val)		{ return (val < limit) ? 0.0 : 1.0; }
259 
260 /* Comparison functions. */
261 
deFloatCmpEQ(float a,float b)262 DE_INLINE deBool	deFloatCmpEQ		(float a, float b)			{ return (a == b); }
deFloatCmpNE(float a,float b)263 DE_INLINE deBool	deFloatCmpNE		(float a, float b)			{ return (a != b); }
deFloatCmpLT(float a,float b)264 DE_INLINE deBool	deFloatCmpLT		(float a, float b)			{ return (a < b);  }
deFloatCmpLE(float a,float b)265 DE_INLINE deBool	deFloatCmpLE		(float a, float b)			{ return (a <= b); }
deFloatCmpGT(float a,float b)266 DE_INLINE deBool	deFloatCmpGT		(float a, float b)			{ return (a > b);  }
deFloatCmpGE(float a,float b)267 DE_INLINE deBool	deFloatCmpGE		(float a, float b)			{ return (a >= b); }
268 
269 /* Convert int to float. If the value cannot be represented exactly in native single precision format, return
270  * either the nearest lower or the nearest higher representable value, chosen in an implementation-defined manner.
271  *
272  * \note Choosing either nearest lower or nearest higher means that implementation could for example consistently
273  *       choose the lower value, i.e. this function does not round towards nearest.
274  * \note Value returned is in native single precision format. For example with x86 extended precision, the value
275  *       returned might not be representable in IEEE single precision float.
276  */
deInt32ToFloat(deInt32 x)277 DE_INLINE float		deInt32ToFloat				(deInt32 x)					{ return (float)x; }
278 
279 /* Convert to float. If the value cannot be represented exactly in IEEE single precision floating point format,
280  * return the nearest lower (round towards negative inf). */
281 float				deInt32ToFloatRoundToNegInf	(deInt32 x);
282 
283 /* Convert to float. If the value cannot be represented exactly IEEE single precision floating point format,
284  * return the nearest higher (round towards positive inf). */
285 float				deInt32ToFloatRoundToPosInf	(deInt32 x);
286 
287 /* Conversion to integer. */
288 
deChopFloatToInt32(float x)289 DE_INLINE deInt32	deChopFloatToInt32		(float x)				{ return (deInt32)x; }
deFloorFloatToInt32(float x)290 DE_INLINE deInt32	deFloorFloatToInt32		(float x)				{ return (deInt32)(deFloatFloor(x)); }
deCeilFloatToInt32(float x)291 DE_INLINE deInt32	deCeilFloatToInt32		(float x)				{ return (deInt32)(deFloatCeil(x)); }
292 
deChopToInt32(double x)293 DE_INLINE deInt32	deChopToInt32			(double x)				{ return (deInt32)x; }
deFloorToInt32(double x)294 DE_INLINE deInt32	deFloorToInt32			(double x)				{ return (deInt32)(deFloor(x)); }
deCeilToInt32(double x)295 DE_INLINE deInt32	deCeilToInt32			(double x)				{ return (deInt32)(deCeil(x)); }
296 
297 /* Arithmetic round */
deRoundFloatToInt16(float x)298 DE_INLINE deInt16	deRoundFloatToInt16		(float x)				{ if(x >= 0.0f) return (deInt16)(x + 0.5f); else return (deInt16)(x - 0.5f); }
deRoundFloatToInt32(float x)299 DE_INLINE deInt32	deRoundFloatToInt32		(float x)				{ if(x >= 0.0f) return (deInt32)(x + 0.5f); else return (deInt32)(x - 0.5f); }
deRoundFloatToInt64(float x)300 DE_INLINE deInt64	deRoundFloatToInt64		(float x)				{ if(x >= 0.0f) return (deInt64)(x + 0.5f); else return (deInt64)(x - 0.5f); }
301 
deRoundToInt16(double x)302 DE_INLINE deInt16	deRoundToInt16			(double x)				{ if(x >= 0.0) return (deInt16)(x + 0.5); else return (deInt16)(x - 0.5); }
deRoundToInt32(double x)303 DE_INLINE deInt32	deRoundToInt32			(double x)				{ if(x >= 0.0) return (deInt32)(x + 0.5); else return (deInt32)(x - 0.5); }
deRoundToInt64(double x)304 DE_INLINE deInt64	deRoundToInt64			(double x)				{ if(x >= 0.0) return (deInt64)(x + 0.5); else return (deInt64)(x - 0.5); }
305 
306 DE_END_EXTERN_C
307 
308 #endif /* _DEMATH_H */
309