context: /*
   * This code is derived from rhino (http://github.com/mozilla/rhino)
   * 
   * This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/.
   */
  
  using System;
  using Rhino;
  using Sharpen;
  
  namespace Rhino
  {
  	/// <summary>This class implements the Math native object.</summary>
  	/// <remarks>
  	/// This class implements the Math native object.
  	/// See ECMA 15.8.
  	/// </remarks>
  	/// <author>Norris Boyd</author>
  	[System.Serializable]
  	internal sealed class NativeMath : IdScriptableObject
  	{
  		private static readonly object MATH_TAG = "Math";
  
  		internal static void Init(Scriptable scope, bool @sealed)
  		{
  			Rhino.NativeMath obj = new Rhino.NativeMath();
  			obj.ActivatePrototypeMap(MAX_ID);
  			obj.Prototype = GetObjectPrototype(scope);
  			obj.ParentScope = scope;
  			if (@sealed)
  			{
  				obj.SealObject();
  			}
  			ScriptableObject.DefineProperty(scope, "Math", obj, PropertyAttributes.DONTENUM);
  		}
  
  		private NativeMath()
  		{
  		}
  
  		public override string GetClassName()
  		{
  			return "Math";
  		}
  
  		protected internal override void InitPrototypeId(int id)
  		{
  			if (id <= LAST_METHOD_ID)
  			{
  				string name;
  				int arity;
  				switch (id)
  				{
  					case Id_toSource:
  					{
  						arity = 0;
  						name = "toSource";
  						break;
  					}
  
  					case Id_abs:
  					{
  						arity = 1;
  						name = "abs";
  						break;
  					}
  
  					case Id_acos:
  					{
  						arity = 1;
  						name = "acos";
  						break;
  					}
  
  					case Id_asin:
  					{
  						arity = 1;
  						name = "asin";
  						break;
  					}
  
  					case Id_atan:
  					{
  						arity = 1;
  						name = "atan";
  						break;
  					}
  
  					case Id_atan2:
  					{
  						arity = 2;
  						name = "atan2";
  						break;
  					}
  
  					case Id_ceil:
  					{
  						arity = 1;
  						name = "ceil";
  						break;
  					}
  
  					case Id_cos:
  					{
  						arity = 1;
  						name = "cos";
  						break;
  					}
  
  					case Id_exp:
  					{
  						arity = 1;
  						name = "exp";
  						break;
  					}
  
  					case Id_floor:
  					{
  						arity = 1;
  						name = "floor";
  						break;
  					}
  
  					case Id_log:
  					{
  						arity = 1;
  						name = "log";
  						break;
  					}
  
  					case Id_max:
  					{
  						arity = 2;
  						name = "max";
  						break;
  					}
  
  					case Id_min:
  					{
  						arity = 2;
  						name = "min";
  						break;
  					}
  
  					case Id_pow:
  					{
  						arity = 2;
  						name = "pow";
  						break;
  					}
  
  					case Id_random:
  					{
  						arity = 0;
  						name = "random";
  						break;
  					}
  
  					case Id_round:
  					{
  						arity = 1;
  						name = "round";
  						break;
  					}
  
  					case Id_sin:
  					{
  						arity = 1;
  						name = "sin";
  						break;
  					}
  
  					case Id_sqrt:
  					{
  						arity = 1;
  						name = "sqrt";
  						break;
  					}
  
  					case Id_tan:
  					{
  						arity = 1;
  						name = "tan";
  						break;
  					}
  
  					default:
  					{
  						throw new InvalidOperationException(id.ToString());
  					}
  				}
  				InitPrototypeMethod(MATH_TAG, id, name, arity);
  			}
  			else
  			{
  				string name;
  				double x;
  				switch (id)
  				{
  					case Id_E:
  					{
  						x = Math.E;
  						name = "E";
  						break;
  					}
  
  					case Id_PI:
  					{
  						x = Math.PI;
  						name = "PI";
  						break;
  					}
  
  					case Id_LN10:
  					{
  						x = 2.302585092994046;
  						name = "LN10";
  						break;
  					}
  
  					case Id_LN2:
  					{
  						x = 0.6931471805599453;
  						name = "LN2";
  						break;
  					}
  
  					case Id_LOG2E:
  					{
  						x = 1.4426950408889634;
  						name = "LOG2E";
  						break;
  					}
  
  					case Id_LOG10E:
  					{
  						x = 0.4342944819032518;
  						name = "LOG10E";
  						break;
  					}
  
  					case Id_SQRT1_2:
  					{
  						x = 0.7071067811865476;
  						name = "SQRT1_2";
  						break;
  					}
  
  					case Id_SQRT2:
  					{
  						x = 1.4142135623730951;
  						name = "SQRT2";
  						break;
  					}
  
  					default:
  					{
  						throw new InvalidOperationException(id.ToString());
  					}
  				}
  				InitPrototypeValue(id, name, x, PropertyAttributes.DONTENUM | PropertyAttributes.READONLY | PropertyAttributes.PERMANENT);
  			}
  		}
  
  		public override object ExecIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, object[] args)
  		{
  			if (!f.HasTag(MATH_TAG))
  			{
  				return base.ExecIdCall(f, cx, scope, thisObj, args);
  			}
  			double x;
  			int methodId = f.MethodId();
  			switch (methodId)
  			{
  				case Id_toSource:
  				{
  					return "Math";
  				}
  
  				case Id_abs:
  				{
  					x = ScriptRuntime.ToNumber(args, 0);
  					// abs(-0.0) should be 0.0, but -0.0 < 0.0 == false
  					x = (x == 0.0) ? 0.0 : (x < 0.0) ? -x : x;
  					break;
  				}
  
  				case Id_acos:
  				case Id_asin:
  				{
  					x = ScriptRuntime.ToNumber(args, 0);
  					if (!Double.IsNaN(x) && -1.0 <= x && x <= 1.0)
  					{
  						x = (methodId == Id_acos) ? Math.Acos(x) : Math.Asin(x);
  					}
  					else
  					{
  						x = double.NaN;
  					}
  					break;
  				}
  
  				case Id_atan:
  				{
  					x = ScriptRuntime.ToNumber(args, 0);
  					x = Math.Atan(x);
  					break;
  				}
  
  				case Id_atan2:
  				{
  					x = ScriptRuntime.ToNumber(args, 0);
  					x = Math.Atan2(x, ScriptRuntime.ToNumber(args, 1));
  					break;
  				}
  
  				case Id_ceil:
  				{
  					x = ScriptRuntime.ToNumber(args, 0);
  					x = System.Math.Ceiling(x);
  					break;
  				}
  
  				case Id_cos:
  				{
  					x = ScriptRuntime.ToNumber(args, 0);
  					x = (x == double.PositiveInfinity || x == double.NegativeInfinity) ? double.NaN : Math.Cos(x);
  					break;
  				}
  
  				case Id_exp:
  				{
  					x = ScriptRuntime.ToNumber(args, 0);
  					x = (x == double.PositiveInfinity) ? x : (x == double.NegativeInfinity) ? 0.0 : Math.Exp(x);
  					break;
  				}
  
  				case Id_floor:
  				{
  					x = ScriptRuntime.ToNumber(args, 0);
  					x = Math.Floor(x);
  					break;
  				}
  
  				case Id_log:
  				{
  					x = ScriptRuntime.ToNumber(args, 0);
  					// Java's log(<0) = -Infinity; we need NaN
  					x = (x < 0) ? double.NaN : Math.Log(x);
  					break;
  				}
  
  				case Id_max:
  				case Id_min:
  				{
  					x = (methodId == Id_max) ? double.NegativeInfinity : double.PositiveInfinity;
  					for (int i = 0; i != args.Length; ++i)
  					{
  						double d = ScriptRuntime.ToNumber(args[i]);
  						if (Double.IsNaN(d))
  						{
  							x = d;
  							// NaN
  							break;
  						}
  						if (methodId == Id_max)
  						{
  							// if (x < d) x = d; does not work due to -0.0 >= +0.0
  							x = Math.Max(x, d);
  						}
  						else
  						{
  							x = Math.Min(x, d);
  						}
  					}
  					break;
  				}
  
  				case Id_pow:
  				{
  					x = ScriptRuntime.ToNumber(args, 0);
  					x = Js_pow(x, ScriptRuntime.ToNumber(args, 1));
  					break;
  				}
  
  				case Id_random:
  				{
  					x = new Random().Next();
  					break;
  				}
  
  				case Id_round:
  				{
  					x = ScriptRuntime.ToNumber(args, 0);
  					if (!Double.IsNaN(x) && x != double.PositiveInfinity && x != double.NegativeInfinity)
  					{
  						// Round only finite x
  						long l = (long) Math.Round(x);
  
gt: 						if (l != 0)