[runtime] Further removed code that doubted IMT
[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         return floor(x);
42 }
43
44 gdouble ves_icall_System_Math_Round (gdouble x) {
45         double int_part, dec_part;
46
47         int_part = floor(x);
48         dec_part = x - int_part;
49         if (((dec_part == 0.5) &&
50                 ((2.0 * ((int_part / 2.0) - floor(int_part / 2.0))) != 0.0)) ||
51                 (dec_part > 0.5)) {
52                 int_part++;
53         }
54         return int_part;
55 }
56
57 gdouble ves_icall_System_Math_Round2 (gdouble value, gint32 digits, gboolean away_from_zero) {
58 #if !defined (HAVE_ROUND) || !defined (HAVE_RINT)
59         double int_part, dec_part;
60 #endif
61         double p;
62
63         if (value == HUGE_VAL)
64                 return HUGE_VAL;
65         if (value == -HUGE_VAL)
66                 return -HUGE_VAL;
67         p = pow(10, digits);
68 #if defined (HAVE_ROUND) && defined (HAVE_RINT)
69         if (away_from_zero)
70                 return round (value * p) / p;
71         else
72                 return rint (value * p) / p;
73 #else
74         dec_part = modf (value, &int_part);
75         dec_part *= 1000000000000000ULL;
76         if (away_from_zero && dec_part > 0)
77                 dec_part = ceil (dec_part);
78         else
79                 dec_part = floor (dec_part);
80         dec_part /= (1000000000000000ULL / p);
81         if (away_from_zero) {
82                 if (dec_part > 0)
83                         dec_part = floor (dec_part + 0.5);
84                 else
85                         dec_part = ceil (dec_part - 0.5);
86         } else
87                 dec_part = ves_icall_System_Math_Round (dec_part);
88         dec_part /= p;
89         return ves_icall_System_Math_Round ((int_part + dec_part) * p) / p;
90 #endif
91 }
92
93 gdouble 
94 ves_icall_System_Math_Sin (gdouble x)
95 {
96         return sin (x);
97 }
98
99 gdouble 
100 ves_icall_System_Math_Cos (gdouble x)
101 {
102         return cos (x);
103 }
104
105 gdouble 
106 ves_icall_System_Math_Tan (gdouble x)
107 {
108         return tan (x);
109 }
110
111 gdouble 
112 ves_icall_System_Math_Sinh (gdouble x)
113 {
114         return sinh (x);
115 }
116
117 gdouble 
118 ves_icall_System_Math_Cosh (gdouble x)
119 {
120         return cosh (x);
121 }
122
123 gdouble 
124 ves_icall_System_Math_Tanh (gdouble x)
125 {
126         return tanh (x);
127 }
128
129 gdouble 
130 ves_icall_System_Math_Acos (gdouble x)
131 {
132         if (x < -1 || x > 1)
133                 return NAN;
134
135         return acos (x);
136 }
137
138 gdouble 
139 ves_icall_System_Math_Asin (gdouble x)
140 {
141         if (x < -1 || x > 1)
142                 return NAN;
143
144         return asin (x);
145 }
146
147 gdouble 
148 ves_icall_System_Math_Atan (gdouble x)
149 {
150         return atan (x);
151 }
152
153 gdouble 
154 ves_icall_System_Math_Atan2 (gdouble y, gdouble x)
155 {
156         double result;
157
158         if ((y == HUGE_VAL && x == HUGE_VAL) ||
159                 (y == HUGE_VAL && x == -HUGE_VAL) ||
160                 (y == -HUGE_VAL && x == HUGE_VAL) ||
161                 (y == -HUGE_VAL && x == -HUGE_VAL)) {
162                 return NAN;
163         }
164         result = atan2 (y, x);
165         return (result == -0)? 0: result;
166 }
167
168 gdouble 
169 ves_icall_System_Math_Exp (gdouble x)
170 {
171         return exp (x);
172 }
173
174 gdouble 
175 ves_icall_System_Math_Log (gdouble x)
176 {
177         if (x == 0)
178                 return -HUGE_VAL;
179         else if (x < 0)
180                 return NAN;
181
182         return log (x);
183 }
184
185 gdouble 
186 ves_icall_System_Math_Log10 (gdouble x)
187 {
188         if (x == 0)
189                 return -HUGE_VAL;
190         else if (x < 0)
191                 return NAN;
192
193         return log10 (x);
194 }
195
196 gdouble 
197 ves_icall_System_Math_Pow (gdouble x, gdouble y)
198 {
199         double result;
200
201         if (isnan(x) || isnan(y)) {
202                 return NAN;
203         }
204
205         if ((x == 1 || x == -1) && (y == HUGE_VAL || y == -HUGE_VAL)) {
206                 return NAN;
207         }
208
209         /* This code is for return the same results as MS.NET for certain
210          * limit values */
211         if (x < -9007199254740991.0) {
212                 if (y > 9007199254740991.0)
213                         return HUGE_VAL;
214                 if (y < -9007199254740991.0)
215                         return 0;
216         }
217
218         result = pow (x, y);
219
220         /* This code is for return the same results as MS.NET for certain
221          * limit values */
222         if (isnan(result) &&
223                 (x == -1.0) &&
224                 ((y > 9007199254740991.0) || (y < -9007199254740991.0))) {
225                 return 1;
226         }
227
228         return (result == -0)? 0: result;
229 }
230
231 gdouble 
232 ves_icall_System_Math_Sqrt (gdouble x)
233 {
234         if (x < 0)
235                 return NAN;
236
237         return sqrt (x);
238 }