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