-/* math.c - these are based on bob smith's csharp routines */\r
-\r
-#define __USE_ISOC99\r
-#include <math.h>\r
-#include <mono/metadata/sysmath.h>\r
-\r
-#ifndef NAN\r
-# if G_BYTE_ORDER == G_BIG_ENDIAN\r
-# define __nan_bytes { 0x7f, 0xc0, 0, 0 }\r
-# endif\r
-# if G_BYTE_ORDER == G_LITTLE_ENDIAN\r
-# define __nan_bytes { 0, 0, 0xc0, 0x7f }\r
-# endif\r
-\r
-static union { unsigned char __c[4]; float __d; } __nan_union = { __nan_bytes };\r
-# define NAN (__nan_union.__d)\r
-#endif\r
-\r
-#ifndef HUGE_VAL\r
-#define __huge_val_t union { unsigned char __c[8]; double __d; }\r
-# if G_BYTE_ORDER == G_BIG_ENDIAN\r
-# define __HUGE_VAL_bytes { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }\r
-# endif\r
-# if G_BYTE_ORDER == G_LITTLE_ENDIAN\r
-# define __HUGE_VAL_bytes { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }\r
-# endif\r
-static __huge_val_t __huge_val = { __HUGE_VAL_bytes };\r
-# define HUGE_VAL (__huge_val.__d)\r
-#endif\r
-\r
-gdouble \r
-ves_icall_System_Math_Sin (gdouble x)\r
-{\r
- return sin (x);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Cos (gdouble x)\r
-{\r
- return cos (x);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Tan (gdouble x)\r
-{\r
- return tan (x);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Sinh (gdouble x)\r
-{\r
- return sinh (x);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Cosh (gdouble x)\r
-{\r
- return cosh (x);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Tanh (gdouble x)\r
-{\r
- return tanh (x);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Acos (gdouble x)\r
-{\r
- if (x < -1 || x > 1)\r
- return NAN;\r
-\r
- return acos (x);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Asin (gdouble x)\r
-{\r
- if (x < -1 || x > 1)\r
- return NAN;\r
-\r
- return asin (x);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Atan (gdouble x)\r
-{\r
- return atan (x);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Atan2 (gdouble y, gdouble x)\r
-{\r
- return atan2 (y, x);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Exp (gdouble x)\r
-{\r
- return exp (x);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Log (gdouble x)\r
-{\r
- if (x == 0)\r
- return -HUGE_VAL;\r
- else if (x < 0)\r
- return NAN;\r
-\r
- return log (x);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Log10 (gdouble x)\r
-{\r
- if (x == 0)\r
- return -HUGE_VAL;\r
- else if (x < 0)\r
- return NAN;\r
-\r
- return log10 (x);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Pow (gdouble x, gdouble y)\r
-{\r
- return pow (x, y);\r
-}\r
-\r
-gdouble \r
-ves_icall_System_Math_Sqrt (gdouble x)\r
-{\r
- if (x < 0)\r
- return NAN;\r
-\r
- return sqrt (x);\r
-}\r
+/*
+ * sysmath.c: these are based on bob smith's csharp routines
+ *
+ * Author:
+ * Mono Project (http://www.mono-project.com)
+ * Ludovic Henry (ludovic@xamarin.com)
+ *
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2015 Xamarin, Inc (https://www.xamarin.com)
+ */
+
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+// Files:
+// - src/classlibnative/float/floatnative.cpp
+// - src/pal/src/cruntime/floatnative.cpp
+//
+// Ported from C++ to C and adjusted to Mono runtime
+
+#define __USE_ISOC99
+
+#include <math.h>
+#include <mono/metadata/sysmath.h>
+
+#include "number-ms.h"
+#include "utils/mono-compiler.h"
+
+static const MonoDouble_double NaN = { .s = { .sign = 0x0, .exp = 0x7FF, .mantHi = 0x80000, .mantLo = 0x0 } };
+
+/* +Infinity */
+static const MonoDouble_double PInfinity = { .s = { .sign = 0x0, .exp = 0x7FF, .mantHi = 0x0, .mantLo = 0x0 } };
+
+/* -Infinity */
+static const MonoDouble_double MInfinity = { .s = { .sign = 0x1, .exp = 0x7FF, .mantHi = 0x0, .mantLo = 0x0 } };
+
+/* +1 */
+static const MonoDouble_double POne = { .s = { .sign = 0x0, .exp = 0x3FF, .mantHi = 0x0, .mantLo = 0x0 } };
+
+/* -1 */
+static const MonoDouble_double MOne = { .s = { .sign = 0x1, .exp = 0x3FF, .mantHi = 0x0, .mantLo = 0x0 } };
+
+static MONO_ALWAYS_INLINE gboolean
+isplusinfinity (gdouble d)
+{
+ return d == PInfinity.d;
+}
+
+static MONO_ALWAYS_INLINE gboolean
+isminusinfinity (gdouble d)
+{
+ return d == MInfinity.d;
+}
+
+static MONO_ALWAYS_INLINE gboolean
+isinfinity (gdouble d)
+{
+ return isplusinfinity (d) || isminusinfinity (d);
+}
+
+static MONO_ALWAYS_INLINE gboolean
+isplusone (gdouble d)
+{
+ return d == POne.d;
+}
+
+static MONO_ALWAYS_INLINE gboolean
+isminusone (gdouble d)
+{
+ return d == MOne.d;
+}
+
+gdouble
+ves_icall_System_Math_Floor (gdouble x)
+{
+ return floor(x);
+}
+
+gdouble
+ves_icall_System_Math_Round (gdouble x)
+{
+ gdouble tmp, floor_tmp;
+
+ /* If the number has no fractional part do nothing This shortcut is necessary
+ * to workaround precision loss in borderline cases on some platforms */
+ if (x == (gdouble)(gint64) x)
+ return x;
+
+ tmp = x + 0.5;
+ floor_tmp = floor (tmp);
+
+ if (floor_tmp == tmp) {
+ if (fmod (tmp, 2.0) != 0)
+ floor_tmp -= 1.0;
+ }
+
+ return copysign (floor_tmp, x);
+}
+
+gdouble
+ves_icall_System_Math_Sin (gdouble x)
+{
+ return sin (x);
+}
+
+gdouble
+ves_icall_System_Math_Cos (gdouble x)
+{
+ return cos (x);
+}
+
+gdouble
+ves_icall_System_Math_Tan (gdouble x)
+{
+ return tan (x);
+}
+
+gdouble
+ves_icall_System_Math_Sinh (gdouble x)
+{
+ return sinh (x);
+}
+
+gdouble
+ves_icall_System_Math_Cosh (gdouble x)
+{
+ return cosh (x);
+}
+
+gdouble
+ves_icall_System_Math_Tanh (gdouble x)
+{
+ return tanh (x);
+}
+
+gdouble
+ves_icall_System_Math_Acos (gdouble x)
+{
+ if (x < -1 || x > 1)
+ return NaN.d;
+
+ return acos (x);
+}
+
+gdouble
+ves_icall_System_Math_Asin (gdouble x)
+{
+ if (x < -1 || x > 1)
+ return NaN.d;
+
+ return asin (x);
+}
+
+gdouble
+ves_icall_System_Math_Atan (gdouble x)
+{
+ return atan (x);
+}
+
+gdouble
+ves_icall_System_Math_Atan2 (gdouble y, gdouble x)
+{
+ gdouble result;
+
+ if (isinfinity (x) && isinfinity (y))
+ return NaN.d;
+
+ result = atan2 (y, x);
+ return result == -0.0 ? 0.0: result;
+}
+
+gdouble
+ves_icall_System_Math_Exp (gdouble x)
+{
+ if (isinfinity (x))
+ return x < 0 ? 0.0 : x;
+
+ return exp (x);
+}
+
+gdouble
+ves_icall_System_Math_Log (gdouble x)
+{
+ if (x == 0)
+ return MInfinity.d;
+ else if (x < 0)
+ return NaN.d;
+
+ return log (x);
+}
+
+gdouble
+ves_icall_System_Math_Log10 (gdouble x)
+{
+ if (x == 0)
+ return MInfinity.d;
+ else if (x < 0)
+ return NaN.d;
+
+ return log10 (x);
+}
+
+gdouble
+ves_icall_System_Math_Pow (gdouble x, gdouble y)
+{
+ gdouble result;
+
+ if (isnan (y))
+ return y;
+ if (isnan (x))
+ return x;
+
+ if (isinfinity (y)) {
+ if (isplusone (x))
+ return x;
+ if (isminusone (x))
+ return NaN.d;
+ }
+
+ /* following are cases from PAL_pow which abstract the implementation of pow for posix and win32 platforms
+ * (https://github.com/dotnet/coreclr/blob/master/src/pal/src/cruntime/finite.cpp#L331) */
+
+ if (isplusinfinity (y) && !isnan (x)) {
+ if (isplusone (x) || isminusone (x))
+ result = NaN.d;
+ else if (x > MOne.d && x < POne.d)
+ result = 0.0;
+ else
+ result = PInfinity.d;
+ } else if (isminusinfinity (y) && !isnan (x)) {
+ if (isplusone (x) || isminusone (x))
+ result = NaN.d;
+ if (x > MOne.d && x < POne.d)
+ result = PInfinity.d;
+ else
+ result = 0.0;
+ } else if (x == 0.0 && y < 0.0) {
+ result = PInfinity.d;
+ } else if (y == 0.0 && isnan (x)) {
+ /* Windows returns NaN for pow(NaN, 0), but POSIX specifies
+ * a return value of 1 for that case. We need to return
+ * the same result as Windows. */
+ result = NaN.d;
+ } else {
+ result = pow (x, y);
+ }
+
+ if (result == PInfinity.d && x < 0.0 && isfinite (x) && ceil (y / 2) != floor (y / 2))
+ result = MInfinity.d;
+
+ /*
+ * The even/odd test in the if (this one and the one above) used to be ((long long) y % 2 == 0)
+ * on SPARC (long long) y for large y (>2**63) is always 0x7fffffff7fffffff, which
+ * is an odd number, so the test ((long long) y % 2 == 0) will always fail for
+ * large y. Since large double numbers are always even (e.g., the representation of
+ * 1E20+1 is the same as that of 1E20, the last .+1. is too insignificant to be part
+ * of the representation), this test will always return the wrong result for large y.
+ *
+ * The (ceil(y/2) == floor(y/2)) test is slower, but more robust.
+ */
+ if (result == MInfinity.d && x < 0.0 && isfinite (x) && ceil (y / 2) == floor (y / 2))
+ result = PInfinity.d;
+
+ return result == -0.0 ? 0 : result;
+}
+
+gdouble
+ves_icall_System_Math_Sqrt (gdouble x)
+{
+ if (x < 0)
+ return NaN.d;
+
+ return sqrt (x);
+}
+
+gdouble
+ves_icall_System_Math_Abs_double (gdouble v)
+{
+ return fabs (v);
+}
+
+gfloat
+ves_icall_System_Math_Abs_single (gfloat v)
+{
+ return fabsf (v);
+}
+
+gdouble
+ves_icall_System_Math_Ceiling (gdouble v)
+{
+ return ceil (v);
+}
+
+gdouble
+ves_icall_System_Math_SplitFractionDouble (gdouble *v)
+{
+ return modf (*v, v);
+}