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 26#if (DE_COMPILER == DE_COMPILER_MSC) 27# include <float.h> 28#endif 29 30#if (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG) 31# include <fenv.h> 32#endif 33 34deRoundingMode deGetRoundingMode (void) 35{ 36#if (DE_COMPILER == DE_COMPILER_MSC) 37 unsigned int status = 0; 38 int ret; 39 40 ret = _controlfp_s(&status, 0, 0); 41 DE_ASSERT(ret == 0); 42 43 switch (status & _MCW_RC) 44 { 45 case _RC_CHOP: return DE_ROUNDINGMODE_TO_ZERO; 46 case _RC_UP: return DE_ROUNDINGMODE_TO_POSITIVE_INF; 47 case _RC_DOWN: return DE_ROUNDINGMODE_TO_NEGATIVE_INF; 48 case _RC_NEAR: return DE_ROUNDINGMODE_TO_NEAREST; 49 default: return DE_ROUNDINGMODE_LAST; 50 } 51#elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG) 52 int mode = fegetround(); 53 switch (mode) 54 { 55 case FE_TOWARDZERO: return DE_ROUNDINGMODE_TO_ZERO; 56 case FE_UPWARD: return DE_ROUNDINGMODE_TO_POSITIVE_INF; 57 case FE_DOWNWARD: return DE_ROUNDINGMODE_TO_NEGATIVE_INF; 58 case FE_TONEAREST: return DE_ROUNDINGMODE_TO_NEAREST; 59 default: return DE_ROUNDINGMODE_LAST; 60 } 61#else 62# error Implement deGetRoundingMode(). 63#endif 64} 65 66deBool deSetRoundingMode (deRoundingMode mode) 67{ 68#if (DE_COMPILER == DE_COMPILER_MSC) 69 unsigned int flag = 0; 70 unsigned int oldState; 71 int ret; 72 73 switch (mode) 74 { 75 case DE_ROUNDINGMODE_TO_ZERO: flag = _RC_CHOP; break; 76 case DE_ROUNDINGMODE_TO_POSITIVE_INF: flag = _RC_UP; break; 77 case DE_ROUNDINGMODE_TO_NEGATIVE_INF: flag = _RC_DOWN; break; 78 case DE_ROUNDINGMODE_TO_NEAREST: flag = _RC_NEAR; break; 79 default: 80 DE_ASSERT(DE_FALSE); 81 } 82 83 ret = _controlfp_s(&oldState, flag, _MCW_RC); 84 return ret == 0; 85#elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG) 86 int flag = 0; 87 int ret; 88 89 switch (mode) 90 { 91 case DE_ROUNDINGMODE_TO_ZERO: flag = FE_TOWARDZERO; break; 92 case DE_ROUNDINGMODE_TO_POSITIVE_INF: flag = FE_UPWARD; break; 93 case DE_ROUNDINGMODE_TO_NEGATIVE_INF: flag = FE_DOWNWARD; break; 94 case DE_ROUNDINGMODE_TO_NEAREST: flag = FE_TONEAREST; break; 95 default: 96 DE_ASSERT(DE_FALSE); 97 } 98 99 ret = fesetround(flag); 100 return ret == 0; 101#else 102# error Implement deSetRoundingMode(). 103#endif 104} 105 106double deFractExp (double x, int* exponent) 107{ 108 if (deIsInf(x)) 109 { 110 *exponent = 0; 111 return x; 112 } 113 else 114 { 115 int tmpExp = 0; 116 double fract = frexp(x, &tmpExp); 117 *exponent = tmpExp - 1; 118 return fract * 2.0; 119 } 120} 121 122/* We could use frexpf, if available. */ 123float deFloatFractExp (float x, int* exponent) 124{ 125 return (float)deFractExp(x, exponent); 126} 127 128double deRoundEven (double a) 129{ 130 double integer; 131 double fract = modf(a, &integer); 132 if (fabs(fract) == 0.5) 133 return 2.0 * deRound(a / 2.0); 134 return deRound(a); 135} 136