This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mono / metadata / sysmath.c
index 8837c16a09514206dcb172b6289f8e1c8fdbfe6f..645d8ed0f3cca237a5472282ace6ba2398ef7b2d 100644 (file)
@@ -3,6 +3,7 @@
 #define __USE_ISOC99\r
 #include <math.h>\r
 #include <mono/metadata/sysmath.h>\r
+#include <mono/metadata/exception.h>\r
 \r
 #ifndef NAN\r
 # if G_BYTE_ORDER == G_BIG_ENDIAN\r
@@ -28,45 +29,98 @@ static __huge_val_t __huge_val = { __HUGE_VAL_bytes };
 #  define HUGE_VAL      (__huge_val.__d)\r
 #endif\r
 \r
+\r
+gdouble ves_icall_System_Math_Floor (gdouble x) {\r
+       MONO_ARCH_SAVE_REGS;\r
+       return floor(x);\r
+}\r
+\r
+gdouble ves_icall_System_Math_Round (gdouble x) {\r
+       double int_part, dec_part;\r
+       MONO_ARCH_SAVE_REGS;\r
+       int_part = floor(x);\r
+       dec_part = x - int_part;\r
+       if (((dec_part == 0.5) &&\r
+               ((2.0 * ((int_part / 2.0) - floor(int_part / 2.0))) != 0.0)) ||\r
+               (dec_part > 0.5)) {\r
+               int_part++;\r
+       }\r
+       return int_part;\r
+}\r
+\r
+gdouble ves_icall_System_Math_Round2 (gdouble value, gint32 digits) {\r
+       double p, int_part, dec_part;\r
+       MONO_ARCH_SAVE_REGS;\r
+       if (value == HUGE_VAL)\r
+               return HUGE_VAL;\r
+       if (value == -HUGE_VAL)\r
+               return -HUGE_VAL;\r
+       if (digits == 0)\r
+               return ves_icall_System_Math_Round(value);\r
+       p = pow(10, digits);\r
+       int_part = floor(value);\r
+       dec_part = value - int_part;\r
+       dec_part *= 1000000000000000ULL;\r
+       dec_part = floor(dec_part);\r
+       dec_part /= (1000000000000000ULL / p);\r
+       dec_part = ves_icall_System_Math_Round(dec_part);\r
+       dec_part /= p;\r
+       return int_part + dec_part;\r
+}\r
+\r
 gdouble \r
 ves_icall_System_Math_Sin (gdouble x)\r
 {\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
        return sin (x);\r
 }\r
 \r
 gdouble \r
 ves_icall_System_Math_Cos (gdouble x)\r
 {\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
        return cos (x);\r
 }\r
 \r
 gdouble \r
 ves_icall_System_Math_Tan (gdouble x)\r
 {\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
        return tan (x);\r
 }\r
 \r
 gdouble \r
 ves_icall_System_Math_Sinh (gdouble x)\r
 {\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
        return sinh (x);\r
 }\r
 \r
 gdouble \r
 ves_icall_System_Math_Cosh (gdouble x)\r
 {\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
        return cosh (x);\r
 }\r
 \r
 gdouble \r
 ves_icall_System_Math_Tanh (gdouble x)\r
 {\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
        return tanh (x);\r
 }\r
 \r
 gdouble \r
 ves_icall_System_Math_Acos (gdouble x)\r
 {\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
        if (x < -1 || x > 1)\r
                return NAN;\r
 \r
@@ -76,6 +130,8 @@ ves_icall_System_Math_Acos (gdouble x)
 gdouble \r
 ves_icall_System_Math_Asin (gdouble x)\r
 {\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
        if (x < -1 || x > 1)\r
                return NAN;\r
 \r
@@ -85,24 +141,40 @@ ves_icall_System_Math_Asin (gdouble x)
 gdouble \r
 ves_icall_System_Math_Atan (gdouble x)\r
 {\r
+       MONO_ARCH_SAVE_REGS;\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
+       double result;\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
+       if ((y == HUGE_VAL && x == HUGE_VAL) ||\r
+               (y == HUGE_VAL && x == -HUGE_VAL) ||\r
+               (y == -HUGE_VAL && x == HUGE_VAL) ||\r
+               (y == -HUGE_VAL && x == -HUGE_VAL)) {\r
+               return NAN;\r
+       }\r
+       result = atan2 (y, x);\r
+       return (result == -0)? 0: result;\r
 }\r
 \r
 gdouble \r
 ves_icall_System_Math_Exp (gdouble x)\r
 {\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
        return exp (x);\r
 }\r
 \r
 gdouble \r
 ves_icall_System_Math_Log (gdouble x)\r
 {\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
        if (x == 0)\r
                return -HUGE_VAL;\r
        else if (x < 0)\r
@@ -114,6 +186,8 @@ ves_icall_System_Math_Log (gdouble x)
 gdouble \r
 ves_icall_System_Math_Log10 (gdouble x)\r
 {\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
        if (x == 0)\r
                return -HUGE_VAL;\r
        else if (x < 0)\r
@@ -125,12 +199,44 @@ ves_icall_System_Math_Log10 (gdouble x)
 gdouble \r
 ves_icall_System_Math_Pow (gdouble x, gdouble y)\r
 {\r
-       return pow (x, y);\r
+       double result;\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
+       if (isnan(x) || isnan(y)) {\r
+               return NAN;\r
+       }\r
+\r
+       if ((x == 1 || x == -1) && (y == HUGE_VAL || y == -HUGE_VAL)) {\r
+               return NAN;\r
+       }\r
+\r
+       /* This code is for return the same results as MS.NET for certain\r
+        * limit values */\r
+       if (x < -9007199254740991.0) {\r
+               if (y > 9007199254740991.0)\r
+                       return HUGE_VAL;\r
+               if (y < -9007199254740991.0)\r
+                       return 0;\r
+       }\r
+\r
+       result = pow (x, y);\r
+\r
+       /* This code is for return the same results as MS.NET for certain\r
+        * limit values */\r
+       if (isnan(result) &&\r
+               (x == -1.0) &&\r
+               ((y > 9007199254740991.0) || (y < -9007199254740991.0))) {\r
+               return 1;\r
+       }\r
+\r
+       return (result == -0)? 0: result;\r
 }\r
 \r
 gdouble \r
 ves_icall_System_Math_Sqrt (gdouble x)\r
 {\r
+       MONO_ARCH_SAVE_REGS;\r
+\r
        if (x < 0)\r
                return NAN;\r
 \r