New test.
[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) {
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         dec_part = floor(dec_part);
64         dec_part /= (1000000000000000ULL / p);
65         dec_part = ves_icall_System_Math_Round(dec_part);
66         dec_part /= p;
67         return int_part + dec_part;
68 }
69
70 gdouble 
71 ves_icall_System_Math_Sin (gdouble x)
72 {
73         MONO_ARCH_SAVE_REGS;
74
75         return sin (x);
76 }
77
78 gdouble 
79 ves_icall_System_Math_Cos (gdouble x)
80 {
81         MONO_ARCH_SAVE_REGS;
82
83         return cos (x);
84 }
85
86 gdouble 
87 ves_icall_System_Math_Tan (gdouble x)
88 {
89         MONO_ARCH_SAVE_REGS;
90
91         return tan (x);
92 }
93
94 gdouble 
95 ves_icall_System_Math_Sinh (gdouble x)
96 {
97         MONO_ARCH_SAVE_REGS;
98
99         return sinh (x);
100 }
101
102 gdouble 
103 ves_icall_System_Math_Cosh (gdouble x)
104 {
105         MONO_ARCH_SAVE_REGS;
106
107         return cosh (x);
108 }
109
110 gdouble 
111 ves_icall_System_Math_Tanh (gdouble x)
112 {
113         MONO_ARCH_SAVE_REGS;
114
115         return tanh (x);
116 }
117
118 gdouble 
119 ves_icall_System_Math_Acos (gdouble x)
120 {
121         MONO_ARCH_SAVE_REGS;
122
123         if (x < -1 || x > 1)
124                 return NAN;
125
126         return acos (x);
127 }
128
129 gdouble 
130 ves_icall_System_Math_Asin (gdouble x)
131 {
132         MONO_ARCH_SAVE_REGS;
133
134         if (x < -1 || x > 1)
135                 return NAN;
136
137         return asin (x);
138 }
139
140 gdouble 
141 ves_icall_System_Math_Atan (gdouble x)
142 {
143         MONO_ARCH_SAVE_REGS;
144
145         return atan (x);
146 }
147
148 gdouble 
149 ves_icall_System_Math_Atan2 (gdouble y, gdouble x)
150 {
151         double result;
152         MONO_ARCH_SAVE_REGS;
153
154         if ((y == HUGE_VAL && x == HUGE_VAL) ||
155                 (y == HUGE_VAL && x == -HUGE_VAL) ||
156                 (y == -HUGE_VAL && x == HUGE_VAL) ||
157                 (y == -HUGE_VAL && x == -HUGE_VAL)) {
158                 return NAN;
159         }
160         result = atan2 (y, x);
161         return (result == -0)? 0: result;
162 }
163
164 gdouble 
165 ves_icall_System_Math_Exp (gdouble x)
166 {
167         MONO_ARCH_SAVE_REGS;
168
169         return exp (x);
170 }
171
172 gdouble 
173 ves_icall_System_Math_Log (gdouble x)
174 {
175         MONO_ARCH_SAVE_REGS;
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         MONO_ARCH_SAVE_REGS;
189
190         if (x == 0)
191                 return -HUGE_VAL;
192         else if (x < 0)
193                 return NAN;
194
195         return log10 (x);
196 }
197
198 gdouble 
199 ves_icall_System_Math_Pow (gdouble x, gdouble y)
200 {
201         double result;
202         MONO_ARCH_SAVE_REGS;
203
204         if (isnan(x) || isnan(y)) {
205                 return NAN;
206         }
207
208         if ((x == 1 || x == -1) && (y == HUGE_VAL || y == -HUGE_VAL)) {
209                 return NAN;
210         }
211
212         /* This code is for return the same results as MS.NET for certain
213          * limit values */
214         if (x < -9007199254740991.0) {
215                 if (y > 9007199254740991.0)
216                         return HUGE_VAL;
217                 if (y < -9007199254740991.0)
218                         return 0;
219         }
220
221         result = pow (x, y);
222
223         /* This code is for return the same results as MS.NET for certain
224          * limit values */
225         if (isnan(result) &&
226                 (x == -1.0) &&
227                 ((y > 9007199254740991.0) || (y < -9007199254740991.0))) {
228                 return 1;
229         }
230
231         return (result == -0)? 0: result;
232 }
233
234 gdouble 
235 ves_icall_System_Math_Sqrt (gdouble x)
236 {
237         MONO_ARCH_SAVE_REGS;
238
239         if (x < 0)
240                 return NAN;
241
242         return sqrt (x);
243 }