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