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