2010-05-05 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / sysmath.c
blobd354c4d0cced1b6a82961e0078b0f1886057b3a4
1 /*
2 * sysmath.c: these are based on bob smith's csharp routines
4 * Author:
5 * Mono Project (http://www.mono-project.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 */
10 #define __USE_ISOC99
11 #include <math.h>
12 #include <mono/metadata/sysmath.h>
13 #include <mono/metadata/exception.h>
15 #ifndef NAN
16 # if G_BYTE_ORDER == G_BIG_ENDIAN
17 # define __nan_bytes { 0x7f, 0xc0, 0, 0 }
18 # endif
19 # if G_BYTE_ORDER == G_LITTLE_ENDIAN
20 # define __nan_bytes { 0, 0, 0xc0, 0x7f }
21 # endif
23 static union { unsigned char __c[4]; float __d; } __nan_union = { __nan_bytes };
24 # define NAN (__nan_union.__d)
25 #endif
27 #ifndef HUGE_VAL
28 #define __huge_val_t union { unsigned char __c[8]; double __d; }
29 # if G_BYTE_ORDER == G_BIG_ENDIAN
30 # define __HUGE_VAL_bytes { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }
31 # endif
32 # if G_BYTE_ORDER == G_LITTLE_ENDIAN
33 # define __HUGE_VAL_bytes { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }
34 # endif
35 static __huge_val_t __huge_val = { __HUGE_VAL_bytes };
36 # define HUGE_VAL (__huge_val.__d)
37 #endif
40 gdouble ves_icall_System_Math_Floor (gdouble x) {
41 MONO_ARCH_SAVE_REGS;
42 return floor(x);
45 gdouble ves_icall_System_Math_Round (gdouble x) {
46 double int_part, dec_part;
47 MONO_ARCH_SAVE_REGS;
48 int_part = floor(x);
49 dec_part = x - int_part;
50 if (((dec_part == 0.5) &&
51 ((2.0 * ((int_part / 2.0) - floor(int_part / 2.0))) != 0.0)) ||
52 (dec_part > 0.5)) {
53 int_part++;
55 return int_part;
58 gdouble ves_icall_System_Math_Round2 (gdouble value, gint32 digits, gboolean away_from_zero) {
59 #if !defined (HAVE_ROUND) || !defined (HAVE_RINT)
60 double int_part, dec_part;
61 #endif
62 double p;
64 MONO_ARCH_SAVE_REGS;
65 if (value == HUGE_VAL)
66 return HUGE_VAL;
67 if (value == -HUGE_VAL)
68 return -HUGE_VAL;
69 if (digits == 0)
70 return ves_icall_System_Math_Round(value);
71 p = pow(10, digits);
72 #if defined (HAVE_ROUND) && defined (HAVE_RINT)
73 if (away_from_zero)
74 return round (value * p) / p;
75 else
76 return rint (value * p) / p;
77 #else
78 dec_part = modf (value, &int_part);
79 dec_part *= 1000000000000000ULL;
80 if (away_from_zero && dec_part > 0)
81 dec_part = ceil (dec_part);
82 else
83 dec_part = floor (dec_part);
84 dec_part /= (1000000000000000ULL / p);
85 if (away_from_zero) {
86 if (dec_part > 0)
87 dec_part = floor (dec_part + 0.5);
88 else
89 dec_part = ceil (dec_part - 0.5);
90 } else
91 dec_part = ves_icall_System_Math_Round (dec_part);
92 dec_part /= p;
93 return ves_icall_System_Math_Round ((int_part + dec_part) * p) / p;
94 #endif
97 gdouble
98 ves_icall_System_Math_Sin (gdouble x)
100 MONO_ARCH_SAVE_REGS;
102 return sin (x);
105 gdouble
106 ves_icall_System_Math_Cos (gdouble x)
108 MONO_ARCH_SAVE_REGS;
110 return cos (x);
113 gdouble
114 ves_icall_System_Math_Tan (gdouble x)
116 MONO_ARCH_SAVE_REGS;
118 return tan (x);
121 gdouble
122 ves_icall_System_Math_Sinh (gdouble x)
124 MONO_ARCH_SAVE_REGS;
126 return sinh (x);
129 gdouble
130 ves_icall_System_Math_Cosh (gdouble x)
132 MONO_ARCH_SAVE_REGS;
134 return cosh (x);
137 gdouble
138 ves_icall_System_Math_Tanh (gdouble x)
140 MONO_ARCH_SAVE_REGS;
142 return tanh (x);
145 gdouble
146 ves_icall_System_Math_Acos (gdouble x)
148 MONO_ARCH_SAVE_REGS;
150 if (x < -1 || x > 1)
151 return NAN;
153 return acos (x);
156 gdouble
157 ves_icall_System_Math_Asin (gdouble x)
159 MONO_ARCH_SAVE_REGS;
161 if (x < -1 || x > 1)
162 return NAN;
164 return asin (x);
167 gdouble
168 ves_icall_System_Math_Atan (gdouble x)
170 MONO_ARCH_SAVE_REGS;
172 return atan (x);
175 gdouble
176 ves_icall_System_Math_Atan2 (gdouble y, gdouble x)
178 double result;
179 MONO_ARCH_SAVE_REGS;
181 if ((y == HUGE_VAL && x == HUGE_VAL) ||
182 (y == HUGE_VAL && x == -HUGE_VAL) ||
183 (y == -HUGE_VAL && x == HUGE_VAL) ||
184 (y == -HUGE_VAL && x == -HUGE_VAL)) {
185 return NAN;
187 result = atan2 (y, x);
188 return (result == -0)? 0: result;
191 gdouble
192 ves_icall_System_Math_Exp (gdouble x)
194 MONO_ARCH_SAVE_REGS;
196 return exp (x);
199 gdouble
200 ves_icall_System_Math_Log (gdouble x)
202 MONO_ARCH_SAVE_REGS;
204 if (x == 0)
205 return -HUGE_VAL;
206 else if (x < 0)
207 return NAN;
209 return log (x);
212 gdouble
213 ves_icall_System_Math_Log10 (gdouble x)
215 MONO_ARCH_SAVE_REGS;
217 if (x == 0)
218 return -HUGE_VAL;
219 else if (x < 0)
220 return NAN;
222 return log10 (x);
225 gdouble
226 ves_icall_System_Math_Pow (gdouble x, gdouble y)
228 double result;
229 MONO_ARCH_SAVE_REGS;
231 if (isnan(x) || isnan(y)) {
232 return NAN;
235 if ((x == 1 || x == -1) && (y == HUGE_VAL || y == -HUGE_VAL)) {
236 return NAN;
239 /* This code is for return the same results as MS.NET for certain
240 * limit values */
241 if (x < -9007199254740991.0) {
242 if (y > 9007199254740991.0)
243 return HUGE_VAL;
244 if (y < -9007199254740991.0)
245 return 0;
248 result = pow (x, y);
250 /* This code is for return the same results as MS.NET for certain
251 * limit values */
252 if (isnan(result) &&
253 (x == -1.0) &&
254 ((y > 9007199254740991.0) || (y < -9007199254740991.0))) {
255 return 1;
258 return (result == -0)? 0: result;
261 gdouble
262 ves_icall_System_Math_Sqrt (gdouble x)
264 MONO_ARCH_SAVE_REGS;
266 if (x < 0)
267 return NAN;
269 return sqrt (x);