1 /*-------------------------------------------------------------------------
2  * drawElements Base Portability Library
3  * -------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Basic mathematical operations.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "deMath.h"
25 #include "deInt32.h"
26 
27 #if (DE_COMPILER == DE_COMPILER_MSC)
28 #	include <float.h>
29 #endif
30 
31 #if (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG)
32 #	include <fenv.h>
33 #endif
34 
deGetRoundingMode(void)35 deRoundingMode deGetRoundingMode (void)
36 {
37 #if (DE_COMPILER == DE_COMPILER_MSC)
38 	unsigned int status = 0;
39 	int ret;
40 
41 	ret = _controlfp_s(&status, 0, 0);
42 	DE_ASSERT(ret == 0);
43 
44 	switch (status & _MCW_RC)
45 	{
46 		case _RC_CHOP:	return DE_ROUNDINGMODE_TO_ZERO;
47 		case _RC_UP:	return DE_ROUNDINGMODE_TO_POSITIVE_INF;
48 		case _RC_DOWN:	return DE_ROUNDINGMODE_TO_NEGATIVE_INF;
49 		case _RC_NEAR:	return DE_ROUNDINGMODE_TO_NEAREST;
50 		default:		return DE_ROUNDINGMODE_LAST;
51 	}
52 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG)
53 	int mode = fegetround();
54 	switch (mode)
55 	{
56 		case FE_TOWARDZERO:	return DE_ROUNDINGMODE_TO_ZERO;
57 		case FE_UPWARD:		return DE_ROUNDINGMODE_TO_POSITIVE_INF;
58 		case FE_DOWNWARD:	return DE_ROUNDINGMODE_TO_NEGATIVE_INF;
59 		case FE_TONEAREST:	return DE_ROUNDINGMODE_TO_NEAREST;
60 		default:			return DE_ROUNDINGMODE_LAST;
61 	}
62 #else
63 #	error Implement deGetRoundingMode().
64 #endif
65 }
66 
deSetRoundingMode(deRoundingMode mode)67 deBool deSetRoundingMode (deRoundingMode mode)
68 {
69 #if (DE_COMPILER == DE_COMPILER_MSC)
70 	unsigned int flag = 0;
71 	unsigned int oldState;
72 	int ret;
73 
74 	switch (mode)
75 	{
76 		case DE_ROUNDINGMODE_TO_ZERO:			flag = _RC_CHOP;	break;
77 		case DE_ROUNDINGMODE_TO_POSITIVE_INF:	flag = _RC_UP;		break;
78 		case DE_ROUNDINGMODE_TO_NEGATIVE_INF:	flag = _RC_DOWN;	break;
79 		case DE_ROUNDINGMODE_TO_NEAREST:		flag = _RC_NEAR;	break;
80 		default:
81 			DE_ASSERT(DE_FALSE);
82 	}
83 
84 	ret = _controlfp_s(&oldState, flag, _MCW_RC);
85 	return ret == 0;
86 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG)
87 	int flag = 0;
88 	int ret;
89 
90 	switch (mode)
91 	{
92 		case DE_ROUNDINGMODE_TO_ZERO:			flag = FE_TOWARDZERO;	break;
93 		case DE_ROUNDINGMODE_TO_POSITIVE_INF:	flag = FE_UPWARD;		break;
94 		case DE_ROUNDINGMODE_TO_NEGATIVE_INF:	flag = FE_DOWNWARD;		break;
95 		case DE_ROUNDINGMODE_TO_NEAREST:		flag = FE_TONEAREST;	break;
96 		default:
97 			DE_ASSERT(DE_FALSE);
98 	}
99 
100 	ret = fesetround(flag);
101 	return ret == 0;
102 #else
103 #	error Implement deSetRoundingMode().
104 #endif
105 }
106 
deFractExp(double x,int * exponent)107 double deFractExp (double x, int* exponent)
108 {
109 	if (deIsInf(x))
110 	{
111 		*exponent = 0;
112 		return x;
113 	}
114 	else
115 	{
116 		int		tmpExp	= 0;
117 		double	fract	= frexp(x, &tmpExp);
118 		*exponent = tmpExp - 1;
119 		return fract * 2.0;
120 	}
121 }
122 
123 /* We could use frexpf, if available. */
deFloatFractExp(float x,int * exponent)124 float deFloatFractExp (float x, int* exponent)
125 {
126 	return (float)deFractExp(x, exponent);
127 }
128 
deRoundEven(double a)129 double deRoundEven (double a)
130 {
131 	double integer;
132 	double fract = modf(a, &integer);
133 	if (fabs(fract) == 0.5)
134 		return 2.0 * deRound(a / 2.0);
135 	return deRound(a);
136 }
137 
deInt32ToFloatRoundToNegInf(deInt32 x)138 float deInt32ToFloatRoundToNegInf (deInt32 x)
139 {
140 	/* \note Sign bit is separate so the range is symmetric */
141 	if (x >= -0xFFFFFF && x <= 0xFFFFFF)
142 	{
143 		/* 24 bits are representable (23 mantissa + 1 implicit). */
144 		return (float)x;
145 	}
146 	else if (x != -0x7FFFFFFF - 1)
147 	{
148 		/* we are losing bits */
149 		const int		exponent	= 31 - deClz32((deUint32)deAbs32(x));
150 		const int		numLostBits	= exponent - 23;
151 		const deUint32	lostMask	= deBitMask32(0, numLostBits);
152 
153 		DE_ASSERT(numLostBits > 0);
154 
155 		if (x > 0)
156 		{
157 			/* Mask out lost bits to floor to a representable value */
158 			return (float)(deInt32)(~lostMask & (deUint32)x);
159 		}
160 		else if ((lostMask & (deUint32)-x) == 0u)
161 		{
162 			/* this was a representable value */
163 			DE_ASSERT( (deInt32)(float)x == x );
164 			return (float)x;
165 		}
166 		else
167 		{
168 			/* not representable, choose the next lower */
169 			const float nearestHigher	= (float)-(deInt32)(~lostMask & (deUint32)-x);
170 			const float oneUlp			= (float)(1u << (deUint32)numLostBits);
171 			const float nearestLower	= nearestHigher - oneUlp;
172 
173 			/* check sanity */
174 			DE_ASSERT((deInt32)(float)nearestHigher > (deInt32)(float)nearestLower);
175 
176 			return nearestLower;
177 		}
178 	}
179 	else
180 		return -(float)0x80000000u;
181 }
182 
deInt32ToFloatRoundToPosInf(deInt32 x)183 float deInt32ToFloatRoundToPosInf (deInt32 x)
184 {
185 	if (x == -0x7FFFFFFF - 1)
186 		return -(float)0x80000000u;
187 	else
188 		return -deInt32ToFloatRoundToNegInf(-x);
189 }
190