/*-------------------------------------------------------------------------
* drawElements Base Portability Library
* -------------------------------------
*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Basic mathematical operations.
*//*--------------------------------------------------------------------*/
#include "deMath.h"
#if (DE_COMPILER == DE_COMPILER_MSC)
# include <float.h>
#endif
#if (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG)
# include <fenv.h>
#endif
deRoundingMode deGetRoundingMode (void)
{
#if (DE_COMPILER == DE_COMPILER_MSC)
unsigned int status = 0;
int ret;
ret = _controlfp_s(&status, 0, 0);
DE_ASSERT(ret == 0);
switch (status & _MCW_RC)
{
case _RC_CHOP: return DE_ROUNDINGMODE_TO_ZERO;
case _RC_UP: return DE_ROUNDINGMODE_TO_POSITIVE_INF;
case _RC_DOWN: return DE_ROUNDINGMODE_TO_NEGATIVE_INF;
case _RC_NEAR: return DE_ROUNDINGMODE_TO_NEAREST;
default: return DE_ROUNDINGMODE_LAST;
}
#elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG)
int mode = fegetround();
switch (mode)
{
case FE_TOWARDZERO: return DE_ROUNDINGMODE_TO_ZERO;
case FE_UPWARD: return DE_ROUNDINGMODE_TO_POSITIVE_INF;
case FE_DOWNWARD: return DE_ROUNDINGMODE_TO_NEGATIVE_INF;
case FE_TONEAREST: return DE_ROUNDINGMODE_TO_NEAREST;
default: return DE_ROUNDINGMODE_LAST;
}
#else
# error Implement deGetRoundingMode().
#endif
}
deBool deSetRoundingMode (deRoundingMode mode)
{
#if (DE_COMPILER == DE_COMPILER_MSC)
unsigned int flag = 0;
unsigned int oldState;
int ret;
switch (mode)
{
case DE_ROUNDINGMODE_TO_ZERO: flag = _RC_CHOP; break;
case DE_ROUNDINGMODE_TO_POSITIVE_INF: flag = _RC_UP; break;
case DE_ROUNDINGMODE_TO_NEGATIVE_INF: flag = _RC_DOWN; break;
case DE_ROUNDINGMODE_TO_NEAREST: flag = _RC_NEAR; break;
default:
DE_ASSERT(DE_FALSE);
}
ret = _controlfp_s(&oldState, flag, _MCW_RC);
return ret == 0;
#elif (DE_COMPILER == DE_COMPILER_GCC) || (DE_COMPILER == DE_COMPILER_CLANG)
int flag = 0;
int ret;
switch (mode)
{
case DE_ROUNDINGMODE_TO_ZERO: flag = FE_TOWARDZERO; break;
case DE_ROUNDINGMODE_TO_POSITIVE_INF: flag = FE_UPWARD; break;
case DE_ROUNDINGMODE_TO_NEGATIVE_INF: flag = FE_DOWNWARD; break;
case DE_ROUNDINGMODE_TO_NEAREST: flag = FE_TONEAREST; break;
default:
DE_ASSERT(DE_FALSE);
}
ret = fesetround(flag);
return ret == 0;
#else
# error Implement deSetRoundingMode().
#endif
}
double deFractExp (double x, int* exponent)
{
if (deIsInf(x))
{
*exponent = 0;
return x;
}
else
{
int tmpExp = 0;
double fract = frexp(x, &tmpExp);
*exponent = tmpExp - 1;
return fract * 2.0;
}
}
/* We could use frexpf, if available. */
float deFloatFractExp (float x, int* exponent)
{
return (float)deFractExp(x, exponent);
}
double deRoundEven (double a)
{
double integer;
double fract = modf(a, &integer);
if (fabs(fract) == 0.5)
return 2.0 * deRound(a / 2.0);
return deRound(a);
}