3 * these are based on bob smith's csharp routines
6 * Mono Project (http://www.mono-project.com)
7 * Ludovic Henry (ludovic@xamarin.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2015 Xamarin, Inc (https://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
16 // Copyright (c) Microsoft. All rights reserved.
17 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 // - src/classlibnative/float/floatnative.cpp
21 // - src/pal/src/cruntime/floatnative.cpp
23 // Ported from C++ to C and adjusted to Mono runtime
28 #include <mono/metadata/sysmath.h>
30 #include "number-ms.h"
31 #include "utils/mono-compiler.h"
33 static const MonoDouble_double NaN = { .s = { .sign = 0x0, .exp = 0x7FF, .mantHi = 0x80000, .mantLo = 0x0 } };
36 static const MonoDouble_double PInfinity = { .s = { .sign = 0x0, .exp = 0x7FF, .mantHi = 0x0, .mantLo = 0x0 } };
39 static const MonoDouble_double MInfinity = { .s = { .sign = 0x1, .exp = 0x7FF, .mantHi = 0x0, .mantLo = 0x0 } };
42 static const MonoDouble_double POne = { .s = { .sign = 0x0, .exp = 0x3FF, .mantHi = 0x0, .mantLo = 0x0 } };
45 static const MonoDouble_double MOne = { .s = { .sign = 0x1, .exp = 0x3FF, .mantHi = 0x0, .mantLo = 0x0 } };
47 static MONO_ALWAYS_INLINE gboolean
48 isplusinfinity (gdouble d)
50 return d == PInfinity.d;
53 static MONO_ALWAYS_INLINE gboolean
54 isminusinfinity (gdouble d)
56 return d == MInfinity.d;
59 static MONO_ALWAYS_INLINE gboolean
60 isinfinity (gdouble d)
62 return isplusinfinity (d) || isminusinfinity (d);
65 static MONO_ALWAYS_INLINE gboolean
71 static MONO_ALWAYS_INLINE gboolean
72 isminusone (gdouble d)
78 ves_icall_System_Math_Floor (gdouble x)
84 ves_icall_System_Math_Round (gdouble x)
86 gdouble tmp, floor_tmp;
88 /* If the number has no fractional part do nothing This shortcut is necessary
89 * to workaround precision loss in borderline cases on some platforms */
90 if (x == (gdouble)(gint64) x)
94 floor_tmp = floor (tmp);
96 if (floor_tmp == tmp) {
97 if (fmod (tmp, 2.0) != 0)
101 return copysign (floor_tmp, x);
105 ves_icall_System_Math_Sin (gdouble x)
111 ves_icall_System_Math_Cos (gdouble x)
117 ves_icall_System_Math_Tan (gdouble x)
123 ves_icall_System_Math_Sinh (gdouble x)
129 ves_icall_System_Math_Cosh (gdouble x)
135 ves_icall_System_Math_Tanh (gdouble x)
141 ves_icall_System_Math_Acos (gdouble x)
150 ves_icall_System_Math_Asin (gdouble x)
159 ves_icall_System_Math_Atan (gdouble x)
165 ves_icall_System_Math_Atan2 (gdouble y, gdouble x)
169 if (isinfinity (x) && isinfinity (y))
172 result = atan2 (y, x);
173 return result == -0.0 ? 0.0: result;
177 ves_icall_System_Math_Exp (gdouble x)
180 return x < 0 ? 0.0 : x;
186 ves_icall_System_Math_Log (gdouble x)
197 ves_icall_System_Math_Log10 (gdouble x)
208 ves_icall_System_Math_Pow (gdouble x, gdouble y)
217 if (isinfinity (y)) {
224 /* following are cases from PAL_pow which abstract the implementation of pow for posix and win32 platforms
225 * (https://github.com/dotnet/coreclr/blob/master/src/pal/src/cruntime/finite.cpp#L331) */
227 if (isplusinfinity (y) && !isnan (x)) {
228 if (isplusone (x) || isminusone (x))
230 else if (x > MOne.d && x < POne.d)
233 result = PInfinity.d;
234 } else if (isminusinfinity (y) && !isnan (x)) {
235 if (isplusone (x) || isminusone (x))
237 if (x > MOne.d && x < POne.d)
238 result = PInfinity.d;
241 } else if (x == 0.0 && y < 0.0) {
242 result = PInfinity.d;
243 } else if (y == 0.0 && isnan (x)) {
244 /* Windows returns NaN for pow(NaN, 0), but POSIX specifies
245 * a return value of 1 for that case. We need to return
246 * the same result as Windows. */
252 if (result == PInfinity.d && x < 0.0 && isfinite (x) && ceil (y / 2) != floor (y / 2))
253 result = MInfinity.d;
256 * The even/odd test in the if (this one and the one above) used to be ((long long) y % 2 == 0)
257 * on SPARC (long long) y for large y (>2**63) is always 0x7fffffff7fffffff, which
258 * is an odd number, so the test ((long long) y % 2 == 0) will always fail for
259 * large y. Since large double numbers are always even (e.g., the representation of
260 * 1E20+1 is the same as that of 1E20, the last .+1. is too insignificant to be part
261 * of the representation), this test will always return the wrong result for large y.
263 * The (ceil(y/2) == floor(y/2)) test is slower, but more robust.
265 if (result == MInfinity.d && x < 0.0 && isfinite (x) && ceil (y / 2) == floor (y / 2))
266 result = PInfinity.d;
268 #if defined (__linux__) && SIZEOF_VOID_P == 4
269 /* On Linux 32bits, some tests erroneously return NaN */
270 if (isnan (result)) {
271 if (isminusone (x) && (y > 9007199254740991.0 || y < -9007199254740991.0)) {
272 /* Math.Pow (-1, Double.MaxValue) and Math.Pow (-1, Double.MinValue) should return 1 */
274 } else if (x < -9007199254740991.0 && y < -9007199254740991.0) {
275 /* Math.Pow (Double.MinValue, Double.MinValue) should return 0 */
277 } else if (x < -9007199254740991.0 && y > 9007199254740991.0) {
278 /* Math.Pow (Double.MinValue, Double.MaxValue) should return Double.PositiveInfinity */
279 result = PInfinity.d;
284 return result == -0.0 ? 0 : result;
288 ves_icall_System_Math_Sqrt (gdouble x)
297 ves_icall_System_Math_Abs_double (gdouble v)
303 ves_icall_System_Math_Abs_single (gfloat v)
309 ves_icall_System_Math_Ceiling (gdouble v)
315 ves_icall_System_Math_SplitFractionDouble (gdouble *v)