Add a more functional (i.e. fewer-stubs) implementation of System.Data.Linq.
[mono.git] / mono / metadata / sysmath.c
1 /*
2  * sysmath.c: these are based on bob smith's csharp routines 
3  *
4  * Author:
5  *      Mono Project (http://www.mono-project.com)
6  *
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>
14
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
22
23 static union { unsigned char __c[4]; float __d; } __nan_union = { __nan_bytes };
24 # define NAN    (__nan_union.__d)
25 #endif
26
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
38
39
40 gdouble ves_icall_System_Math_Floor (gdouble x) {
41         MONO_ARCH_SAVE_REGS;
42         return floor(x);
43 }
44
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++;
54         }
55         return int_part;
56 }
57
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;
63
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
95 }
96
97 gdouble 
98 ves_icall_System_Math_Sin (gdouble x)
99 {
100         MONO_ARCH_SAVE_REGS;
101
102         return sin (x);
103 }
104
105 gdouble 
106 ves_icall_System_Math_Cos (gdouble x)
107 {
108         MONO_ARCH_SAVE_REGS;
109
110         return cos (x);
111 }
112
113 gdouble 
114 ves_icall_System_Math_Tan (gdouble x)
115 {
116         MONO_ARCH_SAVE_REGS;
117
118         return tan (x);
119 }
120
121 gdouble 
122 ves_icall_System_Math_Sinh (gdouble x)
123 {
124         MONO_ARCH_SAVE_REGS;
125
126         return sinh (x);
127 }
128
129 gdouble 
130 ves_icall_System_Math_Cosh (gdouble x)
131 {
132         MONO_ARCH_SAVE_REGS;
133
134         return cosh (x);
135 }
136
137 gdouble 
138 ves_icall_System_Math_Tanh (gdouble x)
139 {
140         MONO_ARCH_SAVE_REGS;
141
142         return tanh (x);
143 }
144
145 gdouble 
146 ves_icall_System_Math_Acos (gdouble x)
147 {
148         MONO_ARCH_SAVE_REGS;
149
150         if (x < -1 || x > 1)
151                 return NAN;
152
153         return acos (x);
154 }
155
156 gdouble 
157 ves_icall_System_Math_Asin (gdouble x)
158 {
159         MONO_ARCH_SAVE_REGS;
160
161         if (x < -1 || x > 1)
162                 return NAN;
163
164         return asin (x);
165 }
166
167 gdouble 
168 ves_icall_System_Math_Atan (gdouble x)
169 {
170         MONO_ARCH_SAVE_REGS;
171
172         return atan (x);
173 }
174
175 gdouble 
176 ves_icall_System_Math_Atan2 (gdouble y, gdouble x)
177 {
178         double result;
179         MONO_ARCH_SAVE_REGS;
180
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;
186         }
187         result = atan2 (y, x);
188         return (result == -0)? 0: result;
189 }
190
191 gdouble 
192 ves_icall_System_Math_Exp (gdouble x)
193 {
194         MONO_ARCH_SAVE_REGS;
195
196         return exp (x);
197 }
198
199 gdouble 
200 ves_icall_System_Math_Log (gdouble x)
201 {
202         MONO_ARCH_SAVE_REGS;
203
204         if (x == 0)
205                 return -HUGE_VAL;
206         else if (x < 0)
207                 return NAN;
208
209         return log (x);
210 }
211
212 gdouble 
213 ves_icall_System_Math_Log10 (gdouble x)
214 {
215         MONO_ARCH_SAVE_REGS;
216
217         if (x == 0)
218                 return -HUGE_VAL;
219         else if (x < 0)
220                 return NAN;
221
222         return log10 (x);
223 }
224
225 gdouble 
226 ves_icall_System_Math_Pow (gdouble x, gdouble y)
227 {
228         double result;
229         MONO_ARCH_SAVE_REGS;
230
231         if (isnan(x) || isnan(y)) {
232                 return NAN;
233         }
234
235         if ((x == 1 || x == -1) && (y == HUGE_VAL || y == -HUGE_VAL)) {
236                 return NAN;
237         }
238
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;
246         }
247
248         result = pow (x, y);
249
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;
256         }
257
258         return (result == -0)? 0: result;
259 }
260
261 gdouble 
262 ves_icall_System_Math_Sqrt (gdouble x)
263 {
264         MONO_ARCH_SAVE_REGS;
265
266         if (x < 0)
267                 return NAN;
268
269         return sqrt (x);
270 }