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