فهرست منبع

ES6 Math functions (#569)

Marko Lahma 6 سال پیش
والد
کامیت
e0701ca211

+ 4 - 12
Jint.Tests.Test262/MathTests.cs

@@ -4,18 +4,10 @@ namespace Jint.Tests.Test262
 {
     public class MathTests : Test262Test
     {
-        [Theory(DisplayName = "built-ins\\Math\\trunc")]
-        [MemberData(nameof(SourceFiles), "built-ins\\Math\\trunc", false)]
-        [MemberData(nameof(SourceFiles), "built-ins\\Math\\trunc", true, Skip = "Skipped")]
-        protected void Trunc(SourceFile sourceFile)
-        {
-            RunTestInternal(sourceFile);
-        }
-
-        [Theory(DisplayName = "built-ins\\Math\\sign")]
-        [MemberData(nameof(SourceFiles), "built-ins\\Math\\sign", false)]
-        [MemberData(nameof(SourceFiles), "built-ins\\Math\\sign", true, Skip = "Skipped")]
-        protected void Sign(SourceFile sourceFile)
+        [Theory(DisplayName = "built-ins\\Math")]
+        [MemberData(nameof(SourceFiles), "built-ins\\Math", false)]
+        [MemberData(nameof(SourceFiles), "built-ins\\Math", true, Skip = "Skipped")]
+        protected void Math(SourceFile sourceFile)
         {
             RunTestInternal(sourceFile);
         }

+ 1 - 1
Jint.Tests.Test262/SingleTest.cs

@@ -23,7 +23,7 @@ namespace Jint.Tests.Test262
         [RunnableInDebugOnly]
         public void TestSingle()
         {
-            const string Target = @"built-ins/String/prototype/repeat/repeat-string-n-times.js";
+            const string Target = @"built-ins/Math/pow/applying-the-exp-operator_A19.js";
             //const string Target = @"built-ins/Array/from/calling-from-valid-2.js";
             var sourceFile = SourceFiles("built-ins", false)
                 .SelectMany(x => x)

+ 4 - 0
Jint.Tests.Test262/test/skipped.json

@@ -357,5 +357,9 @@
   {
     "source": "language/expressions/call/trailing-comma.js",
     "reason": "Esprima problem"
+  },
+  {
+    "source": "built-ins/Math/pow/int32_min-exponent.js",
+    "reason": "const not implemented"
   }
 ]

+ 1 - 1
Jint/Native/Date/DateConstructor.cs

@@ -92,7 +92,7 @@ namespace Jint.Native.Date
                         if (!DateTime.TryParse(date, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out result))
                         {
                             // unrecognized dates should return NaN (15.9.4.2)
-                            return double.NaN;
+                            return JsNumber.DoubleNaN;
                         }
                     }
                 }

+ 21 - 21
Jint/Native/Date/DatePrototype.cs

@@ -130,7 +130,7 @@ namespace Jint.Native.Date
         {
             if (double.IsNaN(EnsureDateInstance(thisObj).PrimitiveValue))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return EnsureDateInstance(thisObj).PrimitiveValue;
@@ -141,7 +141,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return YearFromTime(LocalTime(t));
@@ -152,7 +152,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return YearFromTime(LocalTime(t)) - 1900;
@@ -163,7 +163,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return YearFromTime(t);
@@ -174,7 +174,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return MonthFromTime(LocalTime(t));
@@ -185,7 +185,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return MonthFromTime(t);
@@ -196,7 +196,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return DateFromTime(LocalTime(t));
@@ -207,7 +207,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return DateFromTime(t);
@@ -218,7 +218,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return WeekDay(LocalTime(t));
@@ -229,7 +229,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return WeekDay(t);
@@ -240,7 +240,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return HourFromTime(LocalTime(t));
@@ -251,7 +251,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return HourFromTime(t);
@@ -262,7 +262,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return MinFromTime(LocalTime(t));
@@ -273,7 +273,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return MinFromTime(t);
@@ -284,7 +284,7 @@ namespace Jint.Native.Date
             var t = thisObj.TryCast<DateInstance>().PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return SecFromTime(LocalTime(t));
@@ -295,7 +295,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return SecFromTime(t);
@@ -306,7 +306,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return MsFromTime(LocalTime(t));
@@ -317,7 +317,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return MsFromTime(t);
@@ -328,7 +328,7 @@ namespace Jint.Native.Date
             var t = EnsureDateInstance(thisObj).PrimitiveValue;
             if (double.IsNaN(t))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return (t - LocalTime(t))/MsPerMinute;
@@ -492,7 +492,7 @@ namespace Jint.Native.Date
             if (double.IsNaN(y))
             {
                 EnsureDateInstance(thisObj).PrimitiveValue = double.NaN;
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             var fy = TypeConverter.ToInteger(y);
@@ -654,7 +654,7 @@ namespace Jint.Native.Date
         {
             if (!AreFinite(t))
             {
-                return Double.NaN;
+                return double.NaN;
             }
 
             var sign = (t < 0) ? -1 : 1;

+ 4 - 4
Jint/Native/Global/GlobalObject.cs

@@ -110,7 +110,7 @@ namespace Jint.Native.Global
             }
             else if (radix < 2 || radix > 36)
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             else if (radix != 16)
             {
@@ -128,7 +128,7 @@ namespace Jint.Native.Global
             }
             catch
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
         }
@@ -201,7 +201,7 @@ namespace Jint.Native.Global
 
             if (trimmedString.StartsWith("NaN"))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             var separator = (char)0;
@@ -305,7 +305,7 @@ namespace Jint.Native.Global
 
             if (isNan)
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             for (var k = 1; k <= exp; k++)

+ 23 - 4
Jint/Native/JsNumber.cs

@@ -1,11 +1,15 @@
 using System;
 using System.Globalization;
+using System.Runtime.CompilerServices;
 using Jint.Runtime;
 
 namespace Jint.Native
 {
     public sealed class JsNumber : JsValue, IEquatable<JsNumber>
     {
+        // .NET double epsilon and JS epsilon have different values
+        internal const double JavaScriptEpsilon = 2.2204460492503130808472633361816E-16;
+
         internal readonly double _value;
 
         // how many decimals to check when determining if double is actually an int
@@ -19,11 +23,15 @@ namespace Jint.Native
         private static readonly JsNumber[] _doubleToJsValue = new JsNumber[NumbersMax];
         private static readonly JsNumber[] _intToJsValue = new JsNumber[NumbersMax];
 
-        private static readonly JsNumber DoubleNaN = new JsNumber(double.NaN);
-        private static readonly JsNumber DoubleNegativeOne = new JsNumber((double) -1);
-        private static readonly JsNumber DoublePositiveInfinity = new JsNumber(double.PositiveInfinity);
-        private static readonly JsNumber DoubleNegativeInfinity = new JsNumber(double.NegativeInfinity);
+        internal static readonly JsNumber DoubleNaN = new JsNumber(double.NaN);
+        internal static readonly JsNumber DoubleNegativeOne = new JsNumber((double) -1);
+        internal static readonly JsNumber DoublePositiveInfinity = new JsNumber(double.PositiveInfinity);
+        internal static readonly JsNumber DoubleNegativeInfinity = new JsNumber(double.NegativeInfinity);
         private static readonly JsNumber IntegerNegativeOne = new JsNumber(-1);
+        internal static readonly JsNumber NegativeZero = new JsNumber(-0d);
+        internal static readonly JsNumber PositiveZero = new JsNumber(+0);
+
+        internal static readonly JsNumber PI = new JsNumber(System.Math.PI);
 
         static JsNumber()
         {
@@ -69,6 +77,17 @@ namespace Jint.Native
                 return DoubleNegativeOne;
             }
 
+            if (value <= double.MaxValue && value >= double.MinValue)
+            {
+                return new JsNumber(value);
+            }
+
+            return CreateNumberUnlikely(value);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private static JsNumber CreateNumberUnlikely(double value)
+        {
             if (value == double.NegativeInfinity)
             {
                 return DoubleNegativeInfinity;

+ 377 - 89
Jint/Native/Math/MathInstance.cs

@@ -26,28 +26,42 @@ namespace Jint.Native.Math
 
         public void Configure()
         {
-            FastAddProperty("abs", new ClrFunctionInstance(Engine, "abs", Abs), true, false, true);
-            FastAddProperty("acos", new ClrFunctionInstance(Engine, "acos", Acos), true, false, true);
-            FastAddProperty("asin", new ClrFunctionInstance(Engine, "asin", Asin), true, false, true);
-            FastAddProperty("atan", new ClrFunctionInstance(Engine, "atan", Atan), true, false, true);
-            FastAddProperty("atan2", new ClrFunctionInstance(Engine, "atan2", Atan2), true, false, true);
-            FastAddProperty("ceil", new ClrFunctionInstance(Engine, "ceil", Ceil), true, false, true);
-            FastAddProperty("cos", new ClrFunctionInstance(Engine, "cos", Cos), true, false, true);
-            FastAddProperty("exp", new ClrFunctionInstance(Engine, "exp", Exp), true, false, true);
-            FastAddProperty("floor", new ClrFunctionInstance(Engine, "floor", Floor), true, false, true);
-            FastAddProperty("log", new ClrFunctionInstance(Engine, "log", Log), true, false, true);
-            FastAddProperty("max", new ClrFunctionInstance(Engine, "max", Max, 2), true, false, true);
-            FastAddProperty("min", new ClrFunctionInstance(Engine, "min", Min, 2), true, false, true);
-            FastAddProperty("pow", new ClrFunctionInstance(Engine, "pow", Pow, 2), true, false, true);
-            FastAddProperty("random", new ClrFunctionInstance(Engine, "random", Random), true, false, true);
-            FastAddProperty("round", new ClrFunctionInstance(Engine, "round", Round), true, false, true);
-            FastAddProperty("sin", new ClrFunctionInstance(Engine, "sin", Sin), true, false, true);
-            FastAddProperty("sqrt", new ClrFunctionInstance(Engine, "sqrt", Sqrt), true, false, true);
-            FastAddProperty("tan", new ClrFunctionInstance(Engine, "tan", Tan), true, false, true);
+            FastAddProperty("abs", new ClrFunctionInstance(Engine, "abs", Abs, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("acos", new ClrFunctionInstance(Engine, "acos", Acos, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("acosh", new ClrFunctionInstance(Engine, "acosh", Acosh, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("asin", new ClrFunctionInstance(Engine, "asin", Asin, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("asinh", new ClrFunctionInstance(Engine, "asinh", Asinh, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("atan", new ClrFunctionInstance(Engine, "atan", Atan, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("atanh", new ClrFunctionInstance(Engine, "atanh", Atanh, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("atan2", new ClrFunctionInstance(Engine, "atan2", Atan2, 2, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("ceil", new ClrFunctionInstance(Engine, "ceil", Ceil, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("cos", new ClrFunctionInstance(Engine, "cos", Cos, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("cosh", new ClrFunctionInstance(Engine, "cosh", Cosh, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("exp", new ClrFunctionInstance(Engine, "exp", Exp, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("expm1", new ClrFunctionInstance(Engine, "expm1", Expm1, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("floor", new ClrFunctionInstance(Engine, "floor", Floor, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("log", new ClrFunctionInstance(Engine, "log", Log, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("log1p", new ClrFunctionInstance(Engine, "log1p", Log1p, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("log2", new ClrFunctionInstance(Engine, "log2", Log2, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("log10", new ClrFunctionInstance(Engine, "log10", Log10, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("max", new ClrFunctionInstance(Engine, "max", Max, 2, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("min", new ClrFunctionInstance(Engine, "min", Min, 2, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("pow", new ClrFunctionInstance(Engine, "pow", Pow, 2, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("random", new ClrFunctionInstance(Engine, "random", Random, 0, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("round", new ClrFunctionInstance(Engine, "round", Round, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("fround", new ClrFunctionInstance(Engine, "fround", Fround, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("sin", new ClrFunctionInstance(Engine, "sin", Sin, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("sinh", new ClrFunctionInstance(Engine, "sinh", Sinh, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("sqrt", new ClrFunctionInstance(Engine, "sqrt", Sqrt, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("tan", new ClrFunctionInstance(Engine, "tan", Tan, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("tanh", new ClrFunctionInstance(Engine, "tanh", Tanh, 1, PropertyFlag.Configurable), true, false, true);
 
             FastAddProperty("trunc", new ClrFunctionInstance(Engine, "trunc", Truncate, 1, PropertyFlag.Configurable), true, false, true);
             FastAddProperty("sign", new ClrFunctionInstance(Engine, "sign", Sign, 1, PropertyFlag.Configurable), true, false, true);
             FastAddProperty("cbrt", new ClrFunctionInstance(Engine, "cbrt", Cbrt, 1, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("hypot", new ClrFunctionInstance(Engine, "hypot", Hypot, 2, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("imul", new ClrFunctionInstance(Engine, "imul", Imul, 2, PropertyFlag.Configurable), true, false, true);
+            FastAddProperty("clz32", new ClrFunctionInstance(Engine, "clz32", Clz32, 1, PropertyFlag.Configurable), true, false, true);
 
             FastAddProperty("E", System.Math.E, false, false, false);
             FastAddProperty("LN10", System.Math.Log(10), false, false, false);
@@ -66,15 +80,15 @@ namespace Jint.Native.Math
 
             if (double.IsNaN(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             else if (NumberInstance.IsNegativeZero(x))
             {
-                return +0;
+                return JsNumber.PositiveZero;
             }
             else if (double.IsInfinity(x))
             {
-                return double.PositiveInfinity;
+                return JsNumber.DoublePositiveInfinity;
             }
 
             return System.Math.Abs(x);
@@ -86,7 +100,7 @@ namespace Jint.Native.Math
 
             if (double.IsNaN(x) || (x > 1) || (x < -1))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             else if (x == 1)
             {
@@ -96,13 +110,25 @@ namespace Jint.Native.Math
             return System.Math.Acos(x);
         }
 
+        private static JsValue Acosh(JsValue thisObject, JsValue[] arguments)
+        {
+            var x = TypeConverter.ToNumber(arguments.At(0));
+
+            if (double.IsNaN(x) || x < 1)
+            {
+                return JsNumber.DoubleNaN;
+            }
+
+            return System.Math.Log(x + System.Math.Sqrt(x * x - 1.0));
+        }
+
         private static JsValue Asin(JsValue thisObject, JsValue[] arguments)
         {
             var x = TypeConverter.ToNumber(arguments.At(0));
 
             if (double.IsNaN(x) || (x > 1) || (x < -1))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             else if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
             {
@@ -112,13 +138,24 @@ namespace Jint.Native.Math
             return System.Math.Asin(x);
         }
 
+        private static JsValue Asinh(JsValue thisObject, JsValue[] arguments)
+        {
+            var x = TypeConverter.ToNumber(arguments.At(0));
+            if (double.IsInfinity(x) || NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
+            {
+                return x;
+            }
+
+            return System.Math.Log(x + System.Math.Sqrt(x * x + 1.0));
+        }
+
         private static JsValue Atan(JsValue thisObject, JsValue[] arguments)
         {
             var x = TypeConverter.ToNumber(arguments.At(0));
 
             if (double.IsNaN(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             else if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
             {
@@ -135,6 +172,22 @@ namespace Jint.Native.Math
 
             return System.Math.Atan(x);
         }
+        private static JsValue Atanh(JsValue thisObject, JsValue[] arguments)
+        {
+            var x = TypeConverter.ToNumber(arguments.At(0));
+
+            if (double.IsNaN(x))
+            {
+                return JsNumber.DoubleNaN;
+            }
+
+            if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
+            {
+                return x;
+            }
+
+            return 0.5 * System.Math.Log((1.0 + x) / (1.0 - x));
+        }
 
         private static JsValue Atan2(JsValue thisObject, JsValue[] arguments)
         {
@@ -144,7 +197,7 @@ namespace Jint.Native.Math
             // If either x or y is NaN, the result is NaN.
             if (double.IsNaN(x) || double.IsNaN(y))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             if (y > 0 && x.Equals(0))
@@ -157,25 +210,25 @@ namespace Jint.Native.Math
                 // If y is +0 and x>0, the result is +0.
                 if (x > 0)
                 {
-                    return +0;
+                    return JsNumber.PositiveZero;
                 }
 
                 // If y is +0 and x is +0, the result is +0.
                 if (NumberInstance.IsPositiveZero(x))
                 {
-                    return +0;
+                    return JsNumber.PositiveZero;
                 }
 
                 // If y is +0 and x is −0, the result is an implementation-dependent approximation to +π.
                 if (NumberInstance.IsNegativeZero(x))
                 {
-                    return System.Math.PI;
+                    return JsNumber.PI;
                 }
 
                 // If y is +0 and x<0, the result is an implementation-dependent approximation to +π.
                 if (x < 0)
                 {
-                    return System.Math.PI;
+                    return JsNumber.PI;
                 }
             }
 
@@ -184,13 +237,13 @@ namespace Jint.Native.Math
                 // If y is −0 and x>0, the result is −0.
                 if (x > 0)
                 {
-                    return -0;
+                    return JsNumber.NegativeZero;
                 }
 
                 // If y is −0 and x is +0, the result is −0.
                 if (NumberInstance.IsPositiveZero(x))
                 {
-                    return -0;
+                    return JsNumber.NegativeZero;
                 }
 
                 // If y is −0 and x is −0, the result is an implementation-dependent approximation to −π.
@@ -218,13 +271,13 @@ namespace Jint.Native.Math
             {
                 if (double.IsPositiveInfinity(x))
                 {
-                    return +0;
+                    return JsNumber.PositiveZero;
                 }
 
                 // If y>0 and y is finite and x is −∞, the result if an implementation-dependent approximation to +π.
                 if (double.IsNegativeInfinity(x))
                 {
-                    return System.Math.PI;
+                    return JsNumber.PI;
                 }
             }
 
@@ -235,7 +288,7 @@ namespace Jint.Native.Math
             {
                 if (double.IsPositiveInfinity(x))
                 {
-                    return -0;
+                    return JsNumber.NegativeZero;
                 }
 
                 // If y>0 and y is finite and x is −∞, the result if an implementation-dependent approximation to +π.
@@ -290,23 +343,23 @@ namespace Jint.Native.Math
 
             if (double.IsNaN(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             else if (NumberInstance.IsPositiveZero(x))
             {
-                return +0;
+                return JsNumber.PositiveZero;
             }
             else if (NumberInstance.IsNegativeZero(x))
             {
-                return -0;
+                return JsNumber.NegativeZero;
             }
             else if (double.IsPositiveInfinity(x))
             {
-                return double.PositiveInfinity;
+                return JsNumber.DoublePositiveInfinity;
             }
             else if (double.IsNegativeInfinity(x))
             {
-                return double.NegativeInfinity;
+                return JsNumber.DoubleNegativeInfinity;
             }
 
             return System.Math.Ceiling(x);
@@ -318,7 +371,7 @@ namespace Jint.Native.Math
 
             if (double.IsNaN(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             else if (NumberInstance.IsPositiveZero(x))
             {
@@ -330,19 +383,43 @@ namespace Jint.Native.Math
             }
             else if (double.IsInfinity(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return System.Math.Cos(x);
         }
 
+        private static JsValue Cosh(JsValue thisObject, JsValue[] arguments)
+        {
+            var x = TypeConverter.ToNumber(arguments.At(0));
+
+            if (double.IsNaN(x))
+            {
+                return JsNumber.DoubleNaN;
+            }
+            else if (NumberInstance.IsPositiveZero(x))
+            {
+                return 1;
+            }
+            else if (NumberInstance.IsNegativeZero(x))
+            {
+                return 1;
+            }
+            else if (double.IsInfinity(x))
+            {
+                return JsNumber.DoublePositiveInfinity;
+            }
+
+            return System.Math.Cosh(x);
+        }
+
         private static JsValue Exp(JsValue thisObject, JsValue[] arguments)
         {
             var x = TypeConverter.ToNumber(arguments.At(0));
 
             if (double.IsNaN(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             else if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
             {
@@ -350,39 +427,55 @@ namespace Jint.Native.Math
             }
             else if (double.IsPositiveInfinity(x))
             {
-                return double.PositiveInfinity;
+                return JsNumber.DoublePositiveInfinity;
             }
             else if (double.IsNegativeInfinity(x))
             {
-                return +0;
+                return JsNumber.PositiveZero;
             }
 
             return System.Math.Exp(x);
         }
 
+        private static JsValue Expm1(JsValue thisObject, JsValue[] arguments)
+        {
+            var x = TypeConverter.ToNumber(arguments.At(0));
+
+            if (double.IsNaN(x) || NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x) || double.IsPositiveInfinity(x))
+            {
+                return arguments.At(0);
+            }
+            if (double.IsNegativeInfinity(x))
+            {
+                return JsNumber.DoubleNegativeOne;
+            }
+
+            return System.Math.Exp(x) - 1.0;
+        }
+
         private static JsValue Floor(JsValue thisObject, JsValue[] arguments)
         {
             var x = TypeConverter.ToNumber(arguments.At(0));
 
             if (double.IsNaN(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             else if (NumberInstance.IsPositiveZero(x))
             {
-                return +0;
+                return JsNumber.PositiveZero;
             }
             else if (NumberInstance.IsNegativeZero(x))
             {
-                return -0;
+                return JsNumber.NegativeZero;
             }
             else if (double.IsPositiveInfinity(x))
             {
-                return double.PositiveInfinity;
+                return JsNumber.DoublePositiveInfinity;
             }
             else if (double.IsNegativeInfinity(x))
             {
-                return double.NegativeInfinity;
+                return JsNumber.DoubleNegativeInfinity;
             }
 
             return System.Math.Floor(x);
@@ -394,40 +487,123 @@ namespace Jint.Native.Math
 
             if (double.IsNaN(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             if (x < 0)
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             else if (x == 0)
             {
-                return double.NegativeInfinity;
+                return JsNumber.DoubleNegativeInfinity;
             }
             else if (double.IsPositiveInfinity(x))
             {
-                return double.PositiveInfinity;
+                return JsNumber.DoublePositiveInfinity;
             }
             else if (x == 1)
             {
-                return +0;
+                return JsNumber.PositiveZero;
             }
 
             return System.Math.Log(x);
         }
 
+        private static JsValue Log1p(JsValue thisObject, JsValue[] arguments)
+        {
+            var x = TypeConverter.ToNumber(arguments.At(0));
+
+            if (double.IsNaN(x))
+            {
+                return JsNumber.DoubleNaN;
+            }
+
+            if (x < -1)
+            {
+                return JsNumber.DoubleNaN;
+            }
+
+            if (x == -1)
+            {
+                return JsNumber.DoubleNegativeInfinity;
+            }
+
+            if (x == 0 || double.IsPositiveInfinity(x))
+            {
+                return arguments.At(0);
+            }
+
+            return System.Math.Log(1 + x);
+        }
+
+        private static JsValue Log2(JsValue thisObject, JsValue[] arguments)
+        {
+            var x = TypeConverter.ToNumber(arguments.At(0));
+
+            if (double.IsNaN(x))
+            {
+                return JsNumber.DoubleNaN;
+            }
+            if (x < 0)
+            {
+                return JsNumber.DoubleNaN;
+            }
+            else if (x == 0)
+            {
+                return JsNumber.DoubleNegativeInfinity;
+            }
+            else if (double.IsPositiveInfinity(x))
+            {
+                return JsNumber.DoublePositiveInfinity;
+            }
+            else if (x == 1)
+            {
+                return JsNumber.PositiveZero;
+            }
+
+            return System.Math.Log(x, 2);
+        }
+
+        private static JsValue Log10(JsValue thisObject, JsValue[] arguments)
+        {
+            var x = TypeConverter.ToNumber(arguments.At(0));
+
+            if (double.IsNaN(x))
+            {
+                return JsNumber.DoubleNaN;
+            }
+            if (x < 0)
+            {
+                return JsNumber.DoubleNaN;
+            }
+            else if (x == 0)
+            {
+                return JsNumber.DoubleNegativeInfinity;
+            }
+            else if (double.IsPositiveInfinity(x))
+            {
+                return JsNumber.DoublePositiveInfinity;
+            }
+            else if (x == 1)
+            {
+                return JsNumber.PositiveZero;
+            }
+
+            return System.Math.Log10(x);
+        }
+
         private static JsValue Max(JsValue thisObject, JsValue[] arguments)
         {
             if (arguments.Length == 0)
             {
-                return Double.NegativeInfinity;
+                return JsNumber.DoubleNegativeInfinity;
             }
 
             double max = TypeConverter.ToNumber(arguments.At(0));
 
             if (double.IsNaN(max))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             for (int i = 0; i < arguments.Length; i++)
@@ -436,10 +612,19 @@ namespace Jint.Native.Math
 
                 if (double.IsNaN(value))
                 {
-                    return double.NaN;
+                    return JsNumber.DoubleNaN;
                 }
 
-                max = System.Math.Max(max, value);
+                if (max == 0 && value == 0)
+                {
+                    max = NumberInstance.IsNegativeZero(value)
+                        ? max
+                        : value;
+                }
+                else
+                {
+                    max = System.Math.Max(max, value);
+                }
             }
             return max;
         }
@@ -448,13 +633,23 @@ namespace Jint.Native.Math
         {
             if (arguments.Length == 0)
             {
-                return Double.PositiveInfinity;
+                return JsNumber.DoublePositiveInfinity;
             }
 
             double min = TypeConverter.ToNumber(arguments.At(0));
             for (int i = 0; i < arguments.Length; i++)
             {
-                min = System.Math.Min(min, TypeConverter.ToNumber(arguments[i]));
+                var value = TypeConverter.ToNumber(arguments[i]);
+                if (min == 0 && value == 0)
+                {
+                    min = NumberInstance.IsNegativeZero(min)
+                        ? min
+                        : value;
+                }
+                else
+                {
+                    min = System.Math.Min(min, value);
+                }
             }
             return min;
         }
@@ -482,12 +677,12 @@ namespace Jint.Native.Math
         {
             if (double.IsNaN(y))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             if (double.IsNaN(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             var absX = System.Math.Abs(x);
@@ -495,12 +690,12 @@ namespace Jint.Native.Math
             {
                 if (double.IsPositiveInfinity(y))
                 {
-                    return double.PositiveInfinity;
+                    return JsNumber.DoublePositiveInfinity;
                 }
 
                 if (double.IsNegativeInfinity(y))
                 {
-                    return +0;
+                    return JsNumber.PositiveZero;
                 }
             }
 
@@ -508,7 +703,7 @@ namespace Jint.Native.Math
             {
                 if (double.IsInfinity(y))
                 {
-                    return double.NaN;
+                    return JsNumber.DoubleNaN;
                 }
             }
 
@@ -521,7 +716,7 @@ namespace Jint.Native.Math
 
                 if (double.IsNegativeInfinity(y))
                 {
-                    return double.PositiveInfinity;
+                    return JsNumber.DoublePositiveInfinity;
                 }
             }
 
@@ -529,12 +724,12 @@ namespace Jint.Native.Math
             {
                 if (y > 0)
                 {
-                    return double.PositiveInfinity;
+                    return JsNumber.DoublePositiveInfinity;
                 }
 
                 if (y < 0)
                 {
-                    return +0;
+                    return JsNumber.PositiveZero;
                 }
             }
 
@@ -544,20 +739,20 @@ namespace Jint.Native.Math
                 {
                     if (System.Math.Abs(y % 2).Equals(1))
                     {
-                        return double.NegativeInfinity;
+                        return JsNumber.DoubleNegativeInfinity;
                     }
 
-                    return double.PositiveInfinity;
+                    return JsNumber.DoublePositiveInfinity;
                 }
 
                 if (y < 0)
                 {
                     if (System.Math.Abs(y % 2).Equals(1))
                     {
-                        return -0;
+                        return JsNumber.NegativeZero;
                     }
 
-                    return +0;
+                    return JsNumber.PositiveZero;
                 }
             }
 
@@ -572,7 +767,7 @@ namespace Jint.Native.Math
                 // If x is +0 and y<0, the result is +∞.
                 if (y < 0)
                 {
-                    return double.PositiveInfinity;
+                    return JsNumber.DoublePositiveInfinity;
                 }
             }
 
@@ -584,11 +779,11 @@ namespace Jint.Native.Math
                     // If x is −0 and y>0 and y is an odd integer, the result is −0.
                     if (System.Math.Abs(y % 2).Equals(1))
                     {
-                        return -0;
+                        return JsNumber.NegativeZero;
                     }
 
                     // If x is −0 and y>0 and y is not an odd integer, the result is +0.
-                    return +0;
+                    return JsNumber.PositiveZero;
                 }
 
                 if (y < 0)
@@ -596,18 +791,18 @@ namespace Jint.Native.Math
                     // If x is −0 and y<0 and y is an odd integer, the result is −∞.
                     if (System.Math.Abs(y % 2).Equals(1))
                     {
-                        return double.NegativeInfinity;
+                        return JsNumber.DoubleNegativeInfinity;
                     }
 
                     // If x is −0 and y<0 and y is not an odd integer, the result is +∞.
-                    return double.PositiveInfinity;
+                    return JsNumber.DoublePositiveInfinity;
                 }
             }
 
             // If x<0 and x is finite and y is finite and y is not an integer, the result is NaN.
             if (x < 0 && !double.IsInfinity(x) && !double.IsInfinity(y) && !y.Equals((int) y))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return System.Math.Pow(x, y);
@@ -630,30 +825,64 @@ namespace Jint.Native.Math
             return round;
         }
 
+        private static JsValue Fround(JsValue thisObject, JsValue[] arguments)
+        {
+            var x = TypeConverter.ToNumber(arguments.At(0));
+            return (double) (float) x;
+        }
+
         private static JsValue Sin(JsValue thisObject, JsValue[] arguments)
         {
             var x = TypeConverter.ToNumber(arguments.At(0));
 
             if (double.IsNaN(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             else if (NumberInstance.IsPositiveZero(x))
             {
-                return +0;
+                return JsNumber.PositiveZero;
             }
             else if (NumberInstance.IsNegativeZero(x))
             {
-                return -0;
+                return JsNumber.NegativeZero;
             }
             else if (double.IsInfinity(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             return System.Math.Sin(x);
         }
 
+        private static JsValue Sinh(JsValue thisObject, JsValue[] arguments)
+        {
+            var x = TypeConverter.ToNumber(arguments.At(0));
+
+            if (double.IsNaN(x))
+            {
+                return JsNumber.DoubleNaN;
+            }
+            else if (NumberInstance.IsPositiveZero(x))
+            {
+                return JsNumber.PositiveZero;
+            }
+            else if (NumberInstance.IsNegativeZero(x))
+            {
+                return JsNumber.NegativeZero;
+            }
+            else if (double.IsNegativeInfinity(x))
+            {
+                return JsNumber.DoubleNegativeInfinity;
+            }
+            else if (double.IsPositiveInfinity(x))
+            {
+                return JsNumber.DoublePositiveInfinity;
+            }
+
+            return System.Math.Sinh(x);
+        }
+
         private static JsValue Sqrt(JsValue thisObject, JsValue[] arguments)
         {
             var x = TypeConverter.ToNumber(arguments.At(0));
@@ -666,13 +895,19 @@ namespace Jint.Native.Math
             return System.Math.Tan(x);
         }
 
+        private static JsValue Tanh(JsValue thisObject, JsValue[] arguments)
+        {
+            var x = TypeConverter.ToNumber(arguments.At(0));
+            return System.Math.Tanh(x);
+        }
+
         private static JsValue Truncate(JsValue thisObject, JsValue[] arguments)
         {
             var x = TypeConverter.ToNumber(arguments.At(0));
 
             if (double.IsNaN(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
@@ -682,12 +917,12 @@ namespace Jint.Native.Math
 
             if (double.IsPositiveInfinity(x))
             {
-                return double.PositiveInfinity;
+                return JsNumber.DoublePositiveInfinity;
             }
 
             if (double.IsNegativeInfinity(x))
             {
-                return double.NegativeInfinity;
+                return JsNumber.DoubleNegativeInfinity;
             }
 
             return System.Math.Truncate(x);
@@ -699,7 +934,7 @@ namespace Jint.Native.Math
 
             if (double.IsNaN(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
 
             if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
@@ -726,7 +961,7 @@ namespace Jint.Native.Math
 
             if (double.IsNaN(x))
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             else if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
             {
@@ -734,11 +969,11 @@ namespace Jint.Native.Math
             }
             else if (double.IsPositiveInfinity(x))
             {
-                return double.PositiveInfinity;
+                return JsNumber.DoublePositiveInfinity;
             }
             else if (double.IsNegativeInfinity(x))
             {
-                return double.NegativeInfinity;
+                return JsNumber.DoubleNegativeInfinity;
             }
 
             if (System.Math.Sign(x) >= 0)
@@ -748,5 +983,58 @@ namespace Jint.Native.Math
 
             return -1 * System.Math.Pow(System.Math.Abs(x), 1.0 / 3.0);
         }
+
+        private static JsValue Hypot(JsValue thisObject, JsValue[] arguments)
+        {
+            double y = 0;
+            for (int i = 0; i < arguments.Length; ++i)
+            {
+                var number = TypeConverter.ToNumber(arguments[i]);
+                if (double.IsInfinity(number))
+                {
+                    return JsNumber.DoublePositiveInfinity;
+                }
+                y += number * number;
+            }
+            return System.Math.Sqrt(y);
+        }
+
+        private static JsValue Imul(JsValue thisObject, JsValue[] arguments)
+        {
+            var x = TypeConverter.ToInt32(arguments.At(0));
+            var y = TypeConverter.ToInt32(arguments.At(1));
+
+            return x * y;
+        }
+
+        private static JsValue Clz32(JsValue thisObject, JsValue[] arguments)
+        {
+            var x = TypeConverter.ToInt32(arguments.At(0));
+            if (x < 0)
+            {
+                return 0;
+            }
+
+            if (x == 0)
+            {
+                return 32;
+            }
+
+            var res = 0;
+            var shift = 16;
+            while (x > 1)
+            {
+                var temp = x >> shift;
+                if (temp != 0)
+                {
+                    x = temp;
+                    res += shift;
+                }
+
+                shift >>= 1;
+            }
+
+            return 31 - res;
+        }
     }
 }

+ 1 - 1
Jint/Native/Number/NumberConstructor.cs

@@ -37,7 +37,7 @@ namespace Jint.Native.Number
             SetOwnProperty("NaN", new PropertyDescriptor(double.NaN, PropertyFlag.AllForbidden));
             SetOwnProperty("NEGATIVE_INFINITY", new PropertyDescriptor(double.NegativeInfinity, PropertyFlag.AllForbidden));
             SetOwnProperty("POSITIVE_INFINITY", new PropertyDescriptor(double.PositiveInfinity, PropertyFlag.AllForbidden));
-            SetOwnProperty("EPSILON", new PropertyDescriptor(double.Epsilon, PropertyFlag.AllForbidden));
+            SetOwnProperty("EPSILON", new PropertyDescriptor(JsNumber.JavaScriptEpsilon, PropertyFlag.AllForbidden));
         }
 
         public override JsValue Call(JsValue thisObject, JsValue[] arguments)

+ 1 - 1
Jint/Native/String/StringPrototype.cs

@@ -825,7 +825,7 @@ namespace Jint.Native.String
             var position = (int)TypeConverter.ToInteger(pos);
             if (position < 0 || position >= s.Length)
             {
-                return double.NaN;
+                return JsNumber.DoubleNaN;
             }
             return (double) s[position];
         }

+ 3 - 3
Jint/Runtime/Interpreter/Expressions/JintExpression.cs

@@ -136,12 +136,12 @@ namespace Jint.Runtime.Interpreter.Expressions
 
                 if (double.IsNaN(rN) || double.IsNaN(lN))
                 {
-                    return double.NaN;
+                    return JsNumber.DoubleNaN;
                 }
 
                 if (double.IsInfinity(lN) && double.IsInfinity(rN))
                 {
-                    return double.NaN;
+                    return JsNumber.DoubleNaN;
                 }
 
                 if (double.IsInfinity(lN) && rN == 0)
@@ -156,7 +156,7 @@ namespace Jint.Runtime.Interpreter.Expressions
 
                 if (lN == 0 && rN == 0)
                 {
-                    return double.NaN;
+                    return JsNumber.DoubleNaN;
                 }
 
                 if (rN == 0)

+ 1 - 1
README.md

@@ -170,7 +170,7 @@ ES6 features which are being implemented:
 - [x] [symbols](https://github.com/lukehoban/es6features/blob/master/README.md#symbols)
 - [ ] [subclassable built-ins](https://github.com/lukehoban/es6features/blob/master/README.md#subclassable-built-ins)
 - [ ] [promises](https://github.com/lukehoban/es6features/blob/master/README.md#promises)
-- [ ] [math APIs](https://github.com/lukehoban/es6features/blob/master/README.md#math--number--string--array--object-apis)
+- [x] [math APIs](https://github.com/lukehoban/es6features/blob/master/README.md#math--number--string--array--object-apis)
 - [ ] [number APIs](https://github.com/lukehoban/es6features/blob/master/README.md#math--number--string--array--object-apis)
 - [x] [string APIs](https://github.com/lukehoban/es6features/blob/master/README.md#math--number--string--array--object-apis)
 - [x] [array APIs](https://github.com/lukehoban/es6features/blob/master/README.md#math--number--string--array--object-apis)