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