Home | History | Annotate | Download | only in debase
      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_EVEN;
     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_EVEN;
     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_EVEN:	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_EVEN:	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