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
deGetRoundingMode(void)34 deRoundingMode 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
deSetRoundingMode(deRoundingMode mode)66 deBool 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
deFractExp(double x,int * exponent)106 double 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. */
deFloatFractExp(float x,int * exponent)123 float deFloatFractExp (float x, int* exponent)
124 {
125 return (float)deFractExp(x, exponent);
126 }
127
deRoundEven(double a)128 double 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