1 /*-------------------------------------------------------------------------
2 * drawElements Base Portability Library
3 * -------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Basic mathematical operations.
22 *//*--------------------------------------------------------------------*/
27 #if (DE_COMPILER == DE_COMPILER_MSC)
31 #if (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG)
35 deRoundingMode deGetRoundingMode (void)
37 #if (DE_COMPILER == DE_COMPILER_MSC)
38 unsigned int status = 0;
41 ret = _controlfp_s(&status, 0, 0);
44 switch (status & _MCW_RC)
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;
52 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG)
53 int mode = fegetround();
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;
63 # error Implement deGetRoundingMode().
67 deBool deSetRoundingMode (deRoundingMode mode)
69 #if (DE_COMPILER == DE_COMPILER_MSC)
70 unsigned int flag = 0;
71 unsigned int oldState;
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;
84 ret = _controlfp_s(&oldState, flag, _MCW_RC);
86 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG)
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;
100 ret = fesetround(flag);
103 # error Implement deSetRoundingMode().
107 double deFractExp (double x, int* exponent)
117 double fract = frexp(x, &tmpExp);
118 *exponent = tmpExp - 1;
123 /* We could use frexpf, if available. */
124 float deFloatFractExp (float x, int* exponent)
126 return (float)deFractExp(x, exponent);
129 double deRoundEven (double a)
132 double fract = modf(a, &integer);
133 if (fabs(fract) == 0.5)
134 return 2.0 * deRound(a / 2.0);
138 float deInt32ToFloatRoundToNegInf (deInt32 x)
140 /* \note Sign bit is separate so the range is symmetric */
141 if (x >= -0xFFFFFF && x <= 0xFFFFFF)
143 /* 24 bits are representable (23 mantissa + 1 implicit). */
146 else if (x != -0x7FFFFFFF - 1)
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);
153 DE_ASSERT(numLostBits > 0);
157 /* Mask out lost bits to floor to a representable value */
158 return (float)(deInt32)(~lostMask & (deUint32)x);
160 else if ((lostMask & (deUint32)-x) == 0u)
162 /* this was a representable value */
163 DE_ASSERT( (deInt32)(float)x == x );
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;
174 DE_ASSERT((deInt32)(float)nearestHigher > (deInt32)(float)nearestLower);
180 return -(float)0x80000000u;
183 float deInt32ToFloatRoundToPosInf (deInt32 x)
185 if (x == -0x7FFFFFFF - 1)
186 return -(float)0x80000000u;
188 return -deInt32ToFloatRoundToNegInf(-x);