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 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: 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; 51 } 52 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG) 53 int mode = fegetround(); 54 switch (mode) 55 { 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; 61 } 62 #else 63 # error Implement deGetRoundingMode(). 64 #endif 65 } 66 67 deBool deSetRoundingMode (deRoundingMode mode) 68 { 69 #if (DE_COMPILER == DE_COMPILER_MSC) 70 unsigned int flag = 0; 71 unsigned int oldState; 72 int ret; 73 74 switch (mode) 75 { 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; 80 default: 81 DE_ASSERT(DE_FALSE); 82 } 83 84 ret = _controlfp_s(&oldState, flag, _MCW_RC); 85 return ret == 0; 86 #elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG) 87 int flag = 0; 88 int ret; 89 90 switch (mode) 91 { 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; 96 default: 97 DE_ASSERT(DE_FALSE); 98 } 99 100 ret = fesetround(flag); 101 return ret == 0; 102 #else 103 # error Implement deSetRoundingMode(). 104 #endif 105 } 106 107 double deFractExp (double x, int* exponent) 108 { 109 if (deIsInf(x)) 110 { 111 *exponent = 0; 112 return x; 113 } 114 else 115 { 116 int tmpExp = 0; 117 double fract = frexp(x, &tmpExp); 118 *exponent = tmpExp - 1; 119 return fract * 2.0; 120 } 121 } 122 123 /* We could use frexpf, if available. */ 124 float deFloatFractExp (float x, int* exponent) 125 { 126 return (float)deFractExp(x, exponent); 127 } 128 129 double deRoundEven (double a) 130 { 131 double integer; 132 double fract = modf(a, &integer); 133 if (fabs(fract) == 0.5) 134 return 2.0 * deRound(a / 2.0); 135 return deRound(a); 136 } 137 138 float deInt32ToFloatRoundToNegInf (deInt32 x) 139 { 140 /* \note Sign bit is separate so the range is symmetric */ 141 if (x >= -0xFFFFFF && x <= 0xFFFFFF) 142 { 143 /* 24 bits are representable (23 mantissa + 1 implicit). */ 144 return (float)x; 145 } 146 else if (x != -0x7FFFFFFF - 1) 147 { 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); 152 153 DE_ASSERT(numLostBits > 0); 154 155 if (x > 0) 156 { 157 /* Mask out lost bits to floor to a representable value */ 158 return (float)(deInt32)(~lostMask & (deUint32)x); 159 } 160 else if ((lostMask & (deUint32)-x) == 0u) 161 { 162 /* this was a representable value */ 163 DE_ASSERT( (deInt32)(float)x == x ); 164 return (float)x; 165 } 166 else 167 { 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; 172 173 /* check sanity */ 174 DE_ASSERT((deInt32)(float)nearestHigher > (deInt32)(float)nearestLower); 175 176 return nearestLower; 177 } 178 } 179 else 180 return -(float)0x80000000u; 181 } 182 183 float deInt32ToFloatRoundToPosInf (deInt32 x) 184 { 185 if (x == -0x7FFFFFFF - 1) 186 return -(float)0x80000000u; 187 else 188 return -deInt32ToFloatRoundToNegInf(-x); 189 } 190