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:
47 return DE_ROUNDINGMODE_TO_ZERO;
48 case _RC_UP:
49 return DE_ROUNDINGMODE_TO_POSITIVE_INF;
50 case _RC_DOWN:
51 return DE_ROUNDINGMODE_TO_NEGATIVE_INF;
52 case _RC_NEAR:
53 return DE_ROUNDINGMODE_TO_NEAREST_EVEN;
54 default:
55 return DE_ROUNDINGMODE_LAST;
56 }
57 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG)
58 int mode = fegetround();
59 switch (mode)
60 {
61 case FE_TOWARDZERO:
62 return DE_ROUNDINGMODE_TO_ZERO;
63 case FE_UPWARD:
64 return DE_ROUNDINGMODE_TO_POSITIVE_INF;
65 case FE_DOWNWARD:
66 return DE_ROUNDINGMODE_TO_NEGATIVE_INF;
67 case FE_TONEAREST:
68 return DE_ROUNDINGMODE_TO_NEAREST_EVEN;
69 default:
70 return DE_ROUNDINGMODE_LAST;
71 }
72 #else
73 #error Implement deGetRoundingMode().
74 #endif
75 }
76
deSetRoundingMode(deRoundingMode mode)77 bool deSetRoundingMode(deRoundingMode mode)
78 {
79 #if (DE_COMPILER == DE_COMPILER_MSC)
80 unsigned int flag = 0;
81 unsigned int oldState;
82 int ret;
83
84 switch (mode)
85 {
86 case DE_ROUNDINGMODE_TO_ZERO:
87 flag = _RC_CHOP;
88 break;
89 case DE_ROUNDINGMODE_TO_POSITIVE_INF:
90 flag = _RC_UP;
91 break;
92 case DE_ROUNDINGMODE_TO_NEGATIVE_INF:
93 flag = _RC_DOWN;
94 break;
95 case DE_ROUNDINGMODE_TO_NEAREST_EVEN:
96 flag = _RC_NEAR;
97 break;
98 default:
99 DE_ASSERT(false);
100 }
101
102 ret = _controlfp_s(&oldState, flag, _MCW_RC);
103 return ret == 0;
104 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG)
105 int flag = 0;
106 int ret;
107
108 switch (mode)
109 {
110 case DE_ROUNDINGMODE_TO_ZERO:
111 flag = FE_TOWARDZERO;
112 break;
113 case DE_ROUNDINGMODE_TO_POSITIVE_INF:
114 flag = FE_UPWARD;
115 break;
116 case DE_ROUNDINGMODE_TO_NEGATIVE_INF:
117 flag = FE_DOWNWARD;
118 break;
119 case DE_ROUNDINGMODE_TO_NEAREST_EVEN:
120 flag = FE_TONEAREST;
121 break;
122 default:
123 DE_ASSERT(false);
124 }
125
126 ret = fesetround(flag);
127 return ret == 0;
128 #else
129 #error Implement deSetRoundingMode().
130 #endif
131 }
132
deFractExp(double x,int * exponent)133 double deFractExp(double x, int *exponent)
134 {
135 if (deIsInf(x))
136 {
137 *exponent = 0;
138 return x;
139 }
140 else
141 {
142 int tmpExp = 0;
143 double fract = frexp(x, &tmpExp);
144 *exponent = tmpExp - 1;
145 return fract * 2.0;
146 }
147 }
148
149 /* We could use frexpf, if available. */
deFloatFractExp(float x,int * exponent)150 float deFloatFractExp(float x, int *exponent)
151 {
152 return (float)deFractExp(x, exponent);
153 }
154
deRoundEven(double a)155 double deRoundEven(double a)
156 {
157 double integer;
158 double fract = modf(a, &integer);
159 if (fabs(fract) == 0.5)
160 return 2.0 * deRound(a / 2.0);
161 return deRound(a);
162 }
163
deInt32ToFloatRoundToNegInf(int32_t x)164 float deInt32ToFloatRoundToNegInf(int32_t x)
165 {
166 /* \note Sign bit is separate so the range is symmetric */
167 if (x >= -0xFFFFFF && x <= 0xFFFFFF)
168 {
169 /* 24 bits are representable (23 mantissa + 1 implicit). */
170 return (float)x;
171 }
172 else if (x != -0x7FFFFFFF - 1)
173 {
174 /* we are losing bits */
175 const int exponent = 31 - deClz32((uint32_t)deAbs32(x));
176 const int numLostBits = exponent - 23;
177 const uint32_t lostMask = deBitMask32(0, numLostBits);
178
179 DE_ASSERT(numLostBits > 0);
180
181 if (x > 0)
182 {
183 /* Mask out lost bits to floor to a representable value */
184 return (float)(int32_t)(~lostMask & (uint32_t)x);
185 }
186 else if ((lostMask & (uint32_t)-x) == 0u)
187 {
188 /* this was a representable value */
189 DE_ASSERT((int32_t)(float)x == x);
190 return (float)x;
191 }
192 else
193 {
194 /* not representable, choose the next lower */
195 const float nearestHigher = (float)-(int32_t)(~lostMask & (uint32_t)-x);
196 const float oneUlp = (float)(1u << (uint32_t)numLostBits);
197 const float nearestLower = nearestHigher - oneUlp;
198
199 /* check sanity */
200 DE_ASSERT((int32_t)(float)nearestHigher > (int32_t)(float)nearestLower);
201
202 return nearestLower;
203 }
204 }
205 else
206 return -(float)0x80000000u;
207 }
208
deInt32ToFloatRoundToPosInf(int32_t x)209 float deInt32ToFloatRoundToPosInf(int32_t x)
210 {
211 if (x == -0x7FFFFFFF - 1)
212 return -(float)0x80000000u;
213 else
214 return -deInt32ToFloatRoundToNegInf(-x);
215 }
216