xref: /aosp_15_r20/external/deqp/framework/delibs/debase/deMath.c (revision 35238bce31c2a825756842865a792f8cf7f89930)
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