/
sysmath.c
238 lines (202 loc) · 4.44 KB
/
sysmath.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/*
* sysmath.c: these are based on bob smith's csharp routines
*
* Author:
* Mono Project (http://www.mono-project.com)
*
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
*/
#define __USE_ISOC99
#include <math.h>
#include <mono/metadata/sysmath.h>
#include <mono/metadata/exception.h>
#ifndef NAN
# if G_BYTE_ORDER == G_BIG_ENDIAN
# define __nan_bytes { 0x7f, 0xc0, 0, 0 }
# endif
# if G_BYTE_ORDER == G_LITTLE_ENDIAN
# define __nan_bytes { 0, 0, 0xc0, 0x7f }
# endif
static union { unsigned char __c[4]; float __d; } __nan_union = { __nan_bytes };
# define NAN (__nan_union.__d)
#endif
#ifndef HUGE_VAL
#define __huge_val_t union { unsigned char __c[8]; double __d; }
# if G_BYTE_ORDER == G_BIG_ENDIAN
# define __HUGE_VAL_bytes { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }
# endif
# if G_BYTE_ORDER == G_LITTLE_ENDIAN
# define __HUGE_VAL_bytes { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }
# endif
static __huge_val_t __huge_val = { __HUGE_VAL_bytes };
# define HUGE_VAL (__huge_val.__d)
#endif
gdouble ves_icall_System_Math_Floor (gdouble x) {
return floor(x);
}
gdouble ves_icall_System_Math_Round (gdouble x) {
double int_part, dec_part;
int_part = floor(x);
dec_part = x - int_part;
if (((dec_part == 0.5) &&
((2.0 * ((int_part / 2.0) - floor(int_part / 2.0))) != 0.0)) ||
(dec_part > 0.5)) {
int_part++;
}
return int_part;
}
gdouble ves_icall_System_Math_Round2 (gdouble value, gint32 digits, gboolean away_from_zero) {
#if !defined (HAVE_ROUND) || !defined (HAVE_RINT)
double int_part, dec_part;
#endif
double p;
if (value == HUGE_VAL)
return HUGE_VAL;
if (value == -HUGE_VAL)
return -HUGE_VAL;
p = pow(10, digits);
#if defined (HAVE_ROUND) && defined (HAVE_RINT)
if (away_from_zero)
return round (value * p) / p;
else
return rint (value * p) / p;
#else
dec_part = modf (value, &int_part);
dec_part *= 1000000000000000ULL;
if (away_from_zero && dec_part > 0)
dec_part = ceil (dec_part);
else
dec_part = floor (dec_part);
dec_part /= (1000000000000000ULL / p);
if (away_from_zero) {
if (dec_part > 0)
dec_part = floor (dec_part + 0.5);
else
dec_part = ceil (dec_part - 0.5);
} else
dec_part = ves_icall_System_Math_Round (dec_part);
dec_part /= p;
return ves_icall_System_Math_Round ((int_part + dec_part) * p) / p;
#endif
}
gdouble
ves_icall_System_Math_Sin (gdouble x)
{
return sin (x);
}
gdouble
ves_icall_System_Math_Cos (gdouble x)
{
return cos (x);
}
gdouble
ves_icall_System_Math_Tan (gdouble x)
{
return tan (x);
}
gdouble
ves_icall_System_Math_Sinh (gdouble x)
{
return sinh (x);
}
gdouble
ves_icall_System_Math_Cosh (gdouble x)
{
return cosh (x);
}
gdouble
ves_icall_System_Math_Tanh (gdouble x)
{
return tanh (x);
}
gdouble
ves_icall_System_Math_Acos (gdouble x)
{
if (x < -1 || x > 1)
return NAN;
return acos (x);
}
gdouble
ves_icall_System_Math_Asin (gdouble x)
{
if (x < -1 || x > 1)
return NAN;
return asin (x);
}
gdouble
ves_icall_System_Math_Atan (gdouble x)
{
return atan (x);
}
gdouble
ves_icall_System_Math_Atan2 (gdouble y, gdouble x)
{
double result;
if ((y == HUGE_VAL && x == HUGE_VAL) ||
(y == HUGE_VAL && x == -HUGE_VAL) ||
(y == -HUGE_VAL && x == HUGE_VAL) ||
(y == -HUGE_VAL && x == -HUGE_VAL)) {
return NAN;
}
result = atan2 (y, x);
return (result == -0)? 0: result;
}
gdouble
ves_icall_System_Math_Exp (gdouble x)
{
return exp (x);
}
gdouble
ves_icall_System_Math_Log (gdouble x)
{
if (x == 0)
return -HUGE_VAL;
else if (x < 0)
return NAN;
return log (x);
}
gdouble
ves_icall_System_Math_Log10 (gdouble x)
{
if (x == 0)
return -HUGE_VAL;
else if (x < 0)
return NAN;
return log10 (x);
}
gdouble
ves_icall_System_Math_Pow (gdouble x, gdouble y)
{
double result;
if (isnan(x) || isnan(y)) {
return NAN;
}
if ((x == 1 || x == -1) && (y == HUGE_VAL || y == -HUGE_VAL)) {
return NAN;
}
/* This code is for return the same results as MS.NET for certain
* limit values */
if (x < -9007199254740991.0) {
if (y > 9007199254740991.0)
return HUGE_VAL;
if (y < -9007199254740991.0)
return 0;
}
result = pow (x, y);
/* This code is for return the same results as MS.NET for certain
* limit values */
if (isnan(result) &&
(x == -1.0) &&
((y > 9007199254740991.0) || (y < -9007199254740991.0))) {
return 1;
}
return (result == -0)? 0: result;
}
gdouble
ves_icall_System_Math_Sqrt (gdouble x)
{
if (x < 0)
return NAN;
return sqrt (x);
}