MathInstance.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062
  1. using System;
  2. using Jint.Collections;
  3. using Jint.Native.Number;
  4. using Jint.Native.Object;
  5. using Jint.Native.Symbol;
  6. using Jint.Runtime;
  7. using Jint.Runtime.Descriptors;
  8. using Jint.Runtime.Interop;
  9. namespace Jint.Native.Math
  10. {
  11. public sealed class MathInstance : ObjectInstance
  12. {
  13. private Random _random;
  14. private MathInstance(Engine engine) : base(engine, ObjectClass.Math)
  15. {
  16. }
  17. public static MathInstance CreateMathObject(Engine engine)
  18. {
  19. var math = new MathInstance(engine)
  20. {
  21. _prototype = engine.Object.PrototypeObject
  22. };
  23. return math;
  24. }
  25. protected override void Initialize()
  26. {
  27. var properties = new PropertyDictionary(45, checkExistingKeys: false)
  28. {
  29. ["abs"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "abs", Abs, 1, PropertyFlag.Configurable), true, false, true),
  30. ["acos"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "acos", Acos, 1, PropertyFlag.Configurable), true, false, true),
  31. ["acosh"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "acosh", Acosh, 1, PropertyFlag.Configurable), true, false, true),
  32. ["asin"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "asin", Asin, 1, PropertyFlag.Configurable), true, false, true),
  33. ["asinh"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "asinh", Asinh, 1, PropertyFlag.Configurable), true, false, true),
  34. ["atan"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "atan", Atan, 1, PropertyFlag.Configurable), true, false, true),
  35. ["atanh"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "atanh", Atanh, 1, PropertyFlag.Configurable), true, false, true),
  36. ["atan2"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "atan2", Atan2, 2, PropertyFlag.Configurable), true, false, true),
  37. ["ceil"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "ceil", Ceil, 1, PropertyFlag.Configurable), true, false, true),
  38. ["cos"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "cos", Cos, 1, PropertyFlag.Configurable), true, false, true),
  39. ["cosh"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "cosh", Cosh, 1, PropertyFlag.Configurable), true, false, true),
  40. ["exp"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "exp", Exp, 1, PropertyFlag.Configurable), true, false, true),
  41. ["expm1"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "expm1", Expm1, 1, PropertyFlag.Configurable), true, false, true),
  42. ["floor"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "floor", Floor, 1, PropertyFlag.Configurable), true, false, true),
  43. ["log"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "log", Log, 1, PropertyFlag.Configurable), true, false, true),
  44. ["log1p"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "log1p", Log1p, 1, PropertyFlag.Configurable), true, false, true),
  45. ["log2"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "log2", Log2, 1, PropertyFlag.Configurable), true, false, true),
  46. ["log10"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "log10", Log10, 1, PropertyFlag.Configurable), true, false, true),
  47. ["max"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "max", Max, 2, PropertyFlag.Configurable), true, false, true),
  48. ["min"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "min", Min, 2, PropertyFlag.Configurable), true, false, true),
  49. ["pow"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "pow", Pow, 2, PropertyFlag.Configurable), true, false, true),
  50. ["random"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "random", Random, 0, PropertyFlag.Configurable), true, false, true),
  51. ["round"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "round", Round, 1, PropertyFlag.Configurable), true, false, true),
  52. ["fround"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "fround", Fround, 1, PropertyFlag.Configurable), true, false, true),
  53. ["sin"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "sin", Sin, 1, PropertyFlag.Configurable), true, false, true),
  54. ["sinh"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "sinh", Sinh, 1, PropertyFlag.Configurable), true, false, true),
  55. ["sqrt"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "sqrt", Sqrt, 1, PropertyFlag.Configurable), true, false, true),
  56. ["tan"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "tan", Tan, 1, PropertyFlag.Configurable), true, false, true),
  57. ["tanh"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "tanh", Tanh, 1, PropertyFlag.Configurable), true, false, true),
  58. ["trunc"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "trunc", Truncate, 1, PropertyFlag.Configurable), true, false, true),
  59. ["sign"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "sign", Sign, 1, PropertyFlag.Configurable), true, false, true),
  60. ["cbrt"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "cbrt", Cbrt, 1, PropertyFlag.Configurable), true, false, true),
  61. ["hypot"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "hypot", Hypot, 2, PropertyFlag.Configurable), true, false, true),
  62. ["imul"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "imul", Imul, 2, PropertyFlag.Configurable), true, false, true),
  63. ["clz32"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "clz32", Clz32, 1, PropertyFlag.Configurable), true, false, true),
  64. ["E"] = new PropertyDescriptor(System.Math.E, false, false, false),
  65. ["LN10"] = new PropertyDescriptor(System.Math.Log(10), false, false, false),
  66. ["LN2"] = new PropertyDescriptor(System.Math.Log(2), false, false, false),
  67. ["LOG2E"] = new PropertyDescriptor(System.Math.Log(System.Math.E, 2), false, false, false),
  68. ["LOG10E"] = new PropertyDescriptor(System.Math.Log(System.Math.E, 10), false, false, false),
  69. ["PI"] = new PropertyDescriptor(System.Math.PI, false, false, false),
  70. ["SQRT1_2"] = new PropertyDescriptor(System.Math.Sqrt(0.5), false, false, false),
  71. ["SQRT2"] = new PropertyDescriptor(System.Math.Sqrt(2), false, false, false)
  72. };
  73. SetProperties(properties);
  74. var symbols = new SymbolDictionary(1)
  75. {
  76. [GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor(new JsString("Math"), PropertyFlag.Configurable)
  77. };
  78. SetSymbols(symbols);
  79. }
  80. private static JsValue Abs(JsValue thisObject, JsValue[] arguments)
  81. {
  82. var x = TypeConverter.ToNumber(arguments.At(0));
  83. if (double.IsNaN(x))
  84. {
  85. return JsNumber.DoubleNaN;
  86. }
  87. else if (NumberInstance.IsNegativeZero(x))
  88. {
  89. return JsNumber.PositiveZero;
  90. }
  91. else if (double.IsInfinity(x))
  92. {
  93. return JsNumber.DoublePositiveInfinity;
  94. }
  95. return System.Math.Abs(x);
  96. }
  97. private static JsValue Acos(JsValue thisObject, JsValue[] arguments)
  98. {
  99. var x = TypeConverter.ToNumber(arguments.At(0));
  100. if (double.IsNaN(x) || (x > 1) || (x < -1))
  101. {
  102. return JsNumber.DoubleNaN;
  103. }
  104. else if (x == 1)
  105. {
  106. return 0;
  107. }
  108. return System.Math.Acos(x);
  109. }
  110. private static JsValue Acosh(JsValue thisObject, JsValue[] arguments)
  111. {
  112. var x = TypeConverter.ToNumber(arguments.At(0));
  113. if (double.IsNaN(x) || x < 1)
  114. {
  115. return JsNumber.DoubleNaN;
  116. }
  117. return System.Math.Log(x + System.Math.Sqrt(x * x - 1.0));
  118. }
  119. private static JsValue Asin(JsValue thisObject, JsValue[] arguments)
  120. {
  121. var x = TypeConverter.ToNumber(arguments.At(0));
  122. if (double.IsNaN(x) || (x > 1) || (x < -1))
  123. {
  124. return JsNumber.DoubleNaN;
  125. }
  126. else if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
  127. {
  128. return x;
  129. }
  130. return System.Math.Asin(x);
  131. }
  132. private static JsValue Asinh(JsValue thisObject, JsValue[] arguments)
  133. {
  134. var x = TypeConverter.ToNumber(arguments.At(0));
  135. if (double.IsInfinity(x) || NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
  136. {
  137. return x;
  138. }
  139. return System.Math.Log(x + System.Math.Sqrt(x * x + 1.0));
  140. }
  141. private static JsValue Atan(JsValue thisObject, JsValue[] arguments)
  142. {
  143. var x = TypeConverter.ToNumber(arguments.At(0));
  144. if (double.IsNaN(x))
  145. {
  146. return JsNumber.DoubleNaN;
  147. }
  148. else if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
  149. {
  150. return x;
  151. }
  152. else if (double.IsPositiveInfinity(x))
  153. {
  154. return System.Math.PI / 2;
  155. }
  156. else if (double.IsNegativeInfinity(x))
  157. {
  158. return -System.Math.PI / 2;
  159. }
  160. return System.Math.Atan(x);
  161. }
  162. private static JsValue Atanh(JsValue thisObject, JsValue[] arguments)
  163. {
  164. var x = TypeConverter.ToNumber(arguments.At(0));
  165. if (double.IsNaN(x))
  166. {
  167. return JsNumber.DoubleNaN;
  168. }
  169. if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
  170. {
  171. return x;
  172. }
  173. return 0.5 * System.Math.Log((1.0 + x) / (1.0 - x));
  174. }
  175. private static JsValue Atan2(JsValue thisObject, JsValue[] arguments)
  176. {
  177. var y = TypeConverter.ToNumber(arguments.At(0));
  178. var x = TypeConverter.ToNumber(arguments.At(1));
  179. // If either x or y is NaN, the result is NaN.
  180. if (double.IsNaN(x) || double.IsNaN(y))
  181. {
  182. return JsNumber.DoubleNaN;
  183. }
  184. if (y > 0 && x.Equals(0))
  185. {
  186. return System.Math.PI/2;
  187. }
  188. if (NumberInstance.IsPositiveZero(y))
  189. {
  190. // If y is +0 and x>0, the result is +0.
  191. if (x > 0)
  192. {
  193. return JsNumber.PositiveZero;
  194. }
  195. // If y is +0 and x is +0, the result is +0.
  196. if (NumberInstance.IsPositiveZero(x))
  197. {
  198. return JsNumber.PositiveZero;
  199. }
  200. // If y is +0 and x is −0, the result is an implementation-dependent approximation to +π.
  201. if (NumberInstance.IsNegativeZero(x))
  202. {
  203. return JsNumber.PI;
  204. }
  205. // If y is +0 and x<0, the result is an implementation-dependent approximation to +π.
  206. if (x < 0)
  207. {
  208. return JsNumber.PI;
  209. }
  210. }
  211. if (NumberInstance.IsNegativeZero(y))
  212. {
  213. // If y is −0 and x>0, the result is −0.
  214. if (x > 0)
  215. {
  216. return JsNumber.NegativeZero;
  217. }
  218. // If y is −0 and x is +0, the result is −0.
  219. if (NumberInstance.IsPositiveZero(x))
  220. {
  221. return JsNumber.NegativeZero;
  222. }
  223. // If y is −0 and x is −0, the result is an implementation-dependent approximation to −π.
  224. if (NumberInstance.IsNegativeZero(x))
  225. {
  226. return -System.Math.PI;
  227. }
  228. // If y is −0 and x<0, the result is an implementation-dependent approximation to −π.
  229. if (x < 0)
  230. {
  231. return -System.Math.PI;
  232. }
  233. }
  234. // If y<0 and x is +0, the result is an implementation-dependent approximation to −π/2.
  235. // If y<0 and x is −0, the result is an implementation-dependent approximation to −π/2.
  236. if (y < 0 && x.Equals(0))
  237. {
  238. return -System.Math.PI/2;
  239. }
  240. // If y>0 and y is finite and x is +∞, the result is +0.
  241. if (y > 0 && !double.IsInfinity(y))
  242. {
  243. if (double.IsPositiveInfinity(x))
  244. {
  245. return JsNumber.PositiveZero;
  246. }
  247. // If y>0 and y is finite and x is −∞, the result if an implementation-dependent approximation to +π.
  248. if (double.IsNegativeInfinity(x))
  249. {
  250. return JsNumber.PI;
  251. }
  252. }
  253. // If y<0 and y is finite and x is +∞, the result is −0.
  254. // If y<0 and y is finite and x is −∞, the result is an implementation-dependent approximation to −π.
  255. if (y < 0 && !double.IsInfinity(y))
  256. {
  257. if (double.IsPositiveInfinity(x))
  258. {
  259. return JsNumber.NegativeZero;
  260. }
  261. // If y>0 and y is finite and x is −∞, the result if an implementation-dependent approximation to +π.
  262. if (double.IsNegativeInfinity(x))
  263. {
  264. return -System.Math.PI;
  265. }
  266. }
  267. // If y is +∞ and x is finite, the result is an implementation-dependent approximation to +π/2.
  268. if (double.IsPositiveInfinity(y) && !double.IsInfinity(x))
  269. {
  270. return System.Math.PI/2;
  271. }
  272. // If y is −∞ and x is finite, the result is an implementation-dependent approximation to −π/2.
  273. if (double.IsNegativeInfinity(y) && !double.IsInfinity(x))
  274. {
  275. return -System.Math.PI / 2;
  276. }
  277. // If y is +∞ and x is +∞, the result is an implementation-dependent approximation to +π/4.
  278. if (double.IsPositiveInfinity(y) && double.IsPositiveInfinity(x))
  279. {
  280. return System.Math.PI/4;
  281. }
  282. // If y is +∞ and x is −∞, the result is an implementation-dependent approximation to +3π/4.
  283. if (double.IsPositiveInfinity(y) && double.IsNegativeInfinity(x))
  284. {
  285. return 3 * System.Math.PI / 4;
  286. }
  287. // If y is −∞ and x is +∞, the result is an implementation-dependent approximation to −π/4.
  288. if (double.IsNegativeInfinity(y) && double.IsPositiveInfinity(x))
  289. {
  290. return -System.Math.PI / 4;
  291. }
  292. // If y is −∞ and x is −∞, the result is an implementation-dependent approximation to −3π/4.
  293. if (double.IsNegativeInfinity(y) && double.IsNegativeInfinity(x))
  294. {
  295. return - 3 * System.Math.PI / 4;
  296. }
  297. return System.Math.Atan2(y, x);
  298. }
  299. private static JsValue Ceil(JsValue thisObject, JsValue[] arguments)
  300. {
  301. var x = TypeConverter.ToNumber(arguments.At(0));
  302. if (double.IsNaN(x))
  303. {
  304. return JsNumber.DoubleNaN;
  305. }
  306. else if (NumberInstance.IsPositiveZero(x))
  307. {
  308. return JsNumber.PositiveZero;
  309. }
  310. else if (NumberInstance.IsNegativeZero(x))
  311. {
  312. return JsNumber.NegativeZero;
  313. }
  314. else if (double.IsPositiveInfinity(x))
  315. {
  316. return JsNumber.DoublePositiveInfinity;
  317. }
  318. else if (double.IsNegativeInfinity(x))
  319. {
  320. return JsNumber.DoubleNegativeInfinity;
  321. }
  322. #if NETFRAMEWORK
  323. if (x < 0 && x > -1)
  324. {
  325. return JsNumber.NegativeZero;
  326. }
  327. #endif
  328. return System.Math.Ceiling(x);
  329. }
  330. private static JsValue Cos(JsValue thisObject, JsValue[] arguments)
  331. {
  332. var x = TypeConverter.ToNumber(arguments.At(0));
  333. if (double.IsNaN(x))
  334. {
  335. return JsNumber.DoubleNaN;
  336. }
  337. else if (NumberInstance.IsPositiveZero(x))
  338. {
  339. return 1;
  340. }
  341. else if (NumberInstance.IsNegativeZero(x))
  342. {
  343. return 1;
  344. }
  345. else if (double.IsInfinity(x))
  346. {
  347. return JsNumber.DoubleNaN;
  348. }
  349. return System.Math.Cos(x);
  350. }
  351. private static JsValue Cosh(JsValue thisObject, JsValue[] arguments)
  352. {
  353. var x = TypeConverter.ToNumber(arguments.At(0));
  354. if (double.IsNaN(x))
  355. {
  356. return JsNumber.DoubleNaN;
  357. }
  358. else if (NumberInstance.IsPositiveZero(x))
  359. {
  360. return 1;
  361. }
  362. else if (NumberInstance.IsNegativeZero(x))
  363. {
  364. return 1;
  365. }
  366. else if (double.IsInfinity(x))
  367. {
  368. return JsNumber.DoublePositiveInfinity;
  369. }
  370. return System.Math.Cosh(x);
  371. }
  372. private static JsValue Exp(JsValue thisObject, JsValue[] arguments)
  373. {
  374. var x = TypeConverter.ToNumber(arguments.At(0));
  375. if (double.IsNaN(x))
  376. {
  377. return JsNumber.DoubleNaN;
  378. }
  379. else if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
  380. {
  381. return 1;
  382. }
  383. else if (double.IsPositiveInfinity(x))
  384. {
  385. return JsNumber.DoublePositiveInfinity;
  386. }
  387. else if (double.IsNegativeInfinity(x))
  388. {
  389. return JsNumber.PositiveZero;
  390. }
  391. return System.Math.Exp(x);
  392. }
  393. private static JsValue Expm1(JsValue thisObject, JsValue[] arguments)
  394. {
  395. var x = TypeConverter.ToNumber(arguments.At(0));
  396. if (double.IsNaN(x) || NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x) || double.IsPositiveInfinity(x))
  397. {
  398. return arguments.At(0);
  399. }
  400. if (double.IsNegativeInfinity(x))
  401. {
  402. return JsNumber.DoubleNegativeOne;
  403. }
  404. return System.Math.Exp(x) - 1.0;
  405. }
  406. private static JsValue Floor(JsValue thisObject, JsValue[] arguments)
  407. {
  408. var x = TypeConverter.ToNumber(arguments.At(0));
  409. if (double.IsNaN(x))
  410. {
  411. return JsNumber.DoubleNaN;
  412. }
  413. else if (NumberInstance.IsPositiveZero(x))
  414. {
  415. return JsNumber.PositiveZero;
  416. }
  417. else if (NumberInstance.IsNegativeZero(x))
  418. {
  419. return JsNumber.NegativeZero;
  420. }
  421. else if (double.IsPositiveInfinity(x))
  422. {
  423. return JsNumber.DoublePositiveInfinity;
  424. }
  425. else if (double.IsNegativeInfinity(x))
  426. {
  427. return JsNumber.DoubleNegativeInfinity;
  428. }
  429. return System.Math.Floor(x);
  430. }
  431. private static JsValue Log(JsValue thisObject, JsValue[] arguments)
  432. {
  433. var x = TypeConverter.ToNumber(arguments.At(0));
  434. if (double.IsNaN(x))
  435. {
  436. return JsNumber.DoubleNaN;
  437. }
  438. if (x < 0)
  439. {
  440. return JsNumber.DoubleNaN;
  441. }
  442. else if (x == 0)
  443. {
  444. return JsNumber.DoubleNegativeInfinity;
  445. }
  446. else if (double.IsPositiveInfinity(x))
  447. {
  448. return JsNumber.DoublePositiveInfinity;
  449. }
  450. else if (x == 1)
  451. {
  452. return JsNumber.PositiveZero;
  453. }
  454. return System.Math.Log(x);
  455. }
  456. private static JsValue Log1p(JsValue thisObject, JsValue[] arguments)
  457. {
  458. var x = TypeConverter.ToNumber(arguments.At(0));
  459. if (double.IsNaN(x))
  460. {
  461. return JsNumber.DoubleNaN;
  462. }
  463. if (x < -1)
  464. {
  465. return JsNumber.DoubleNaN;
  466. }
  467. if (x == -1)
  468. {
  469. return JsNumber.DoubleNegativeInfinity;
  470. }
  471. if (x == 0 || double.IsPositiveInfinity(x))
  472. {
  473. return arguments.At(0);
  474. }
  475. return System.Math.Log(1 + x);
  476. }
  477. private static JsValue Log2(JsValue thisObject, JsValue[] arguments)
  478. {
  479. var x = TypeConverter.ToNumber(arguments.At(0));
  480. if (double.IsNaN(x))
  481. {
  482. return JsNumber.DoubleNaN;
  483. }
  484. if (x < 0)
  485. {
  486. return JsNumber.DoubleNaN;
  487. }
  488. else if (x == 0)
  489. {
  490. return JsNumber.DoubleNegativeInfinity;
  491. }
  492. else if (double.IsPositiveInfinity(x))
  493. {
  494. return JsNumber.DoublePositiveInfinity;
  495. }
  496. else if (x == 1)
  497. {
  498. return JsNumber.PositiveZero;
  499. }
  500. return System.Math.Log(x, 2);
  501. }
  502. private static JsValue Log10(JsValue thisObject, JsValue[] arguments)
  503. {
  504. var x = TypeConverter.ToNumber(arguments.At(0));
  505. if (double.IsNaN(x))
  506. {
  507. return JsNumber.DoubleNaN;
  508. }
  509. if (x < 0)
  510. {
  511. return JsNumber.DoubleNaN;
  512. }
  513. else if (x == 0)
  514. {
  515. return JsNumber.DoubleNegativeInfinity;
  516. }
  517. else if (double.IsPositiveInfinity(x))
  518. {
  519. return JsNumber.DoublePositiveInfinity;
  520. }
  521. else if (x == 1)
  522. {
  523. return JsNumber.PositiveZero;
  524. }
  525. return System.Math.Log10(x);
  526. }
  527. private static JsValue Max(JsValue thisObject, JsValue[] arguments)
  528. {
  529. if (arguments.Length == 0)
  530. {
  531. return JsNumber.DoubleNegativeInfinity;
  532. }
  533. double max = TypeConverter.ToNumber(arguments.At(0));
  534. if (double.IsNaN(max))
  535. {
  536. return JsNumber.DoubleNaN;
  537. }
  538. for (int i = 0; i < arguments.Length; i++)
  539. {
  540. var value = TypeConverter.ToNumber(arguments[i]);
  541. if (double.IsNaN(value))
  542. {
  543. return JsNumber.DoubleNaN;
  544. }
  545. if (max == 0 && value == 0)
  546. {
  547. max = NumberInstance.IsNegativeZero(value)
  548. ? max
  549. : value;
  550. }
  551. else
  552. {
  553. max = System.Math.Max(max, value);
  554. }
  555. }
  556. return max;
  557. }
  558. private static JsValue Min(JsValue thisObject, JsValue[] arguments)
  559. {
  560. if (arguments.Length == 0)
  561. {
  562. return JsNumber.DoublePositiveInfinity;
  563. }
  564. double min = TypeConverter.ToNumber(arguments.At(0));
  565. for (int i = 0; i < arguments.Length; i++)
  566. {
  567. var value = TypeConverter.ToNumber(arguments[i]);
  568. if (min == 0 && value == 0)
  569. {
  570. min = NumberInstance.IsNegativeZero(min)
  571. ? min
  572. : value;
  573. }
  574. else
  575. {
  576. min = System.Math.Min(min, value);
  577. }
  578. }
  579. return min;
  580. }
  581. private static JsValue Pow(JsValue thisObject, JsValue[] arguments)
  582. {
  583. var x = TypeConverter.ToNumber(arguments.At(0));
  584. var y = TypeConverter.ToNumber(arguments.At(1));
  585. // check easy case where values are valid
  586. if (x > 1 && y > 1 && x < int.MaxValue && y < int.MaxValue)
  587. {
  588. return System.Math.Pow(x, y);
  589. }
  590. if (y == 0)
  591. {
  592. return 1;
  593. }
  594. return HandlePowUnlikely(y, x);
  595. }
  596. private static JsValue HandlePowUnlikely(double y, double x)
  597. {
  598. if (double.IsNaN(y))
  599. {
  600. return JsNumber.DoubleNaN;
  601. }
  602. if (double.IsNaN(x))
  603. {
  604. return JsNumber.DoubleNaN;
  605. }
  606. var absX = System.Math.Abs(x);
  607. if (absX > 1)
  608. {
  609. if (double.IsPositiveInfinity(y))
  610. {
  611. return JsNumber.DoublePositiveInfinity;
  612. }
  613. if (double.IsNegativeInfinity(y))
  614. {
  615. return JsNumber.PositiveZero;
  616. }
  617. }
  618. if (absX == 1)
  619. {
  620. if (double.IsInfinity(y))
  621. {
  622. return JsNumber.DoubleNaN;
  623. }
  624. }
  625. if (absX < 1)
  626. {
  627. if (double.IsPositiveInfinity(y))
  628. {
  629. return 0;
  630. }
  631. if (double.IsNegativeInfinity(y))
  632. {
  633. return JsNumber.DoublePositiveInfinity;
  634. }
  635. }
  636. if (double.IsPositiveInfinity(x))
  637. {
  638. if (y > 0)
  639. {
  640. return JsNumber.DoublePositiveInfinity;
  641. }
  642. if (y < 0)
  643. {
  644. return JsNumber.PositiveZero;
  645. }
  646. }
  647. if (double.IsNegativeInfinity(x))
  648. {
  649. if (y > 0)
  650. {
  651. if (System.Math.Abs(y % 2).Equals(1))
  652. {
  653. return JsNumber.DoubleNegativeInfinity;
  654. }
  655. return JsNumber.DoublePositiveInfinity;
  656. }
  657. if (y < 0)
  658. {
  659. if (System.Math.Abs(y % 2).Equals(1))
  660. {
  661. return JsNumber.NegativeZero;
  662. }
  663. return JsNumber.PositiveZero;
  664. }
  665. }
  666. if (NumberInstance.IsPositiveZero(x))
  667. {
  668. // If x is +0 and y>0, the result is +0.
  669. if (y > 0)
  670. {
  671. return 0;
  672. }
  673. // If x is +0 and y<0, the result is +∞.
  674. if (y < 0)
  675. {
  676. return JsNumber.DoublePositiveInfinity;
  677. }
  678. }
  679. if (NumberInstance.IsNegativeZero(x))
  680. {
  681. if (y > 0)
  682. {
  683. // If x is −0 and y>0 and y is an odd integer, the result is −0.
  684. if (System.Math.Abs(y % 2).Equals(1))
  685. {
  686. return JsNumber.NegativeZero;
  687. }
  688. // If x is −0 and y>0 and y is not an odd integer, the result is +0.
  689. return JsNumber.PositiveZero;
  690. }
  691. if (y < 0)
  692. {
  693. // If x is −0 and y<0 and y is an odd integer, the result is −∞.
  694. if (System.Math.Abs(y % 2).Equals(1))
  695. {
  696. return JsNumber.DoubleNegativeInfinity;
  697. }
  698. // If x is −0 and y<0 and y is not an odd integer, the result is +∞.
  699. return JsNumber.DoublePositiveInfinity;
  700. }
  701. }
  702. // If x<0 and x is finite and y is finite and y is not an integer, the result is NaN.
  703. if (x < 0 && !double.IsInfinity(x) && !double.IsInfinity(y) && !y.Equals((int) y))
  704. {
  705. return JsNumber.DoubleNaN;
  706. }
  707. return System.Math.Pow(x, y);
  708. }
  709. private JsValue Random(JsValue thisObject, JsValue[] arguments)
  710. {
  711. if(_random == null)
  712. {
  713. _random = new Random();
  714. }
  715. return _random.NextDouble();
  716. }
  717. private static JsValue Round(JsValue thisObject, JsValue[] arguments)
  718. {
  719. var x = TypeConverter.ToNumber(arguments.At(0));
  720. var round = System.Math.Round(x);
  721. if (round.Equals(x - 0.5))
  722. {
  723. return round + 1;
  724. }
  725. return round;
  726. }
  727. private static JsValue Fround(JsValue thisObject, JsValue[] arguments)
  728. {
  729. var x = TypeConverter.ToNumber(arguments.At(0));
  730. return (double) (float) x;
  731. }
  732. private static JsValue Sin(JsValue thisObject, JsValue[] arguments)
  733. {
  734. var x = TypeConverter.ToNumber(arguments.At(0));
  735. if (double.IsNaN(x))
  736. {
  737. return JsNumber.DoubleNaN;
  738. }
  739. else if (NumberInstance.IsPositiveZero(x))
  740. {
  741. return JsNumber.PositiveZero;
  742. }
  743. else if (NumberInstance.IsNegativeZero(x))
  744. {
  745. return JsNumber.NegativeZero;
  746. }
  747. else if (double.IsInfinity(x))
  748. {
  749. return JsNumber.DoubleNaN;
  750. }
  751. return System.Math.Sin(x);
  752. }
  753. private static JsValue Sinh(JsValue thisObject, JsValue[] arguments)
  754. {
  755. var x = TypeConverter.ToNumber(arguments.At(0));
  756. if (double.IsNaN(x))
  757. {
  758. return JsNumber.DoubleNaN;
  759. }
  760. else if (NumberInstance.IsPositiveZero(x))
  761. {
  762. return JsNumber.PositiveZero;
  763. }
  764. else if (NumberInstance.IsNegativeZero(x))
  765. {
  766. return JsNumber.NegativeZero;
  767. }
  768. else if (double.IsNegativeInfinity(x))
  769. {
  770. return JsNumber.DoubleNegativeInfinity;
  771. }
  772. else if (double.IsPositiveInfinity(x))
  773. {
  774. return JsNumber.DoublePositiveInfinity;
  775. }
  776. return System.Math.Sinh(x);
  777. }
  778. private static JsValue Sqrt(JsValue thisObject, JsValue[] arguments)
  779. {
  780. var x = TypeConverter.ToNumber(arguments.At(0));
  781. return System.Math.Sqrt(x);
  782. }
  783. private static JsValue Tan(JsValue thisObject, JsValue[] arguments)
  784. {
  785. var x = TypeConverter.ToNumber(arguments.At(0));
  786. return System.Math.Tan(x);
  787. }
  788. private static JsValue Tanh(JsValue thisObject, JsValue[] arguments)
  789. {
  790. var x = TypeConverter.ToNumber(arguments.At(0));
  791. return System.Math.Tanh(x);
  792. }
  793. private static JsValue Truncate(JsValue thisObject, JsValue[] arguments)
  794. {
  795. var x = TypeConverter.ToNumber(arguments.At(0));
  796. if (double.IsNaN(x))
  797. {
  798. return JsNumber.DoubleNaN;
  799. }
  800. if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
  801. {
  802. return x;
  803. }
  804. if (double.IsPositiveInfinity(x))
  805. {
  806. return JsNumber.DoublePositiveInfinity;
  807. }
  808. if (double.IsNegativeInfinity(x))
  809. {
  810. return JsNumber.DoubleNegativeInfinity;
  811. }
  812. return System.Math.Truncate(x);
  813. }
  814. private static JsValue Sign(JsValue thisObject, JsValue[] arguments)
  815. {
  816. var x = TypeConverter.ToNumber(arguments.At(0));
  817. if (double.IsNaN(x))
  818. {
  819. return JsNumber.DoubleNaN;
  820. }
  821. if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
  822. {
  823. return x;
  824. }
  825. if (double.IsPositiveInfinity(x))
  826. {
  827. return 1;
  828. }
  829. if (double.IsNegativeInfinity(x))
  830. {
  831. return -1;
  832. }
  833. return System.Math.Sign(x);
  834. }
  835. private static JsValue Cbrt(JsValue thisObject, JsValue[] arguments)
  836. {
  837. var x = TypeConverter.ToNumber(arguments.At(0));
  838. if (double.IsNaN(x))
  839. {
  840. return JsNumber.DoubleNaN;
  841. }
  842. else if (NumberInstance.IsPositiveZero(x) || NumberInstance.IsNegativeZero(x))
  843. {
  844. return x;
  845. }
  846. else if (double.IsPositiveInfinity(x))
  847. {
  848. return JsNumber.DoublePositiveInfinity;
  849. }
  850. else if (double.IsNegativeInfinity(x))
  851. {
  852. return JsNumber.DoubleNegativeInfinity;
  853. }
  854. if (System.Math.Sign(x) >= 0)
  855. {
  856. return System.Math.Pow(x, 1.0/3.0);
  857. }
  858. return -1 * System.Math.Pow(System.Math.Abs(x), 1.0 / 3.0);
  859. }
  860. private static JsValue Hypot(JsValue thisObject, JsValue[] arguments)
  861. {
  862. double y = 0;
  863. for (int i = 0; i < arguments.Length; ++i)
  864. {
  865. var number = TypeConverter.ToNumber(arguments[i]);
  866. if (double.IsInfinity(number))
  867. {
  868. return JsNumber.DoublePositiveInfinity;
  869. }
  870. y += number * number;
  871. }
  872. return System.Math.Sqrt(y);
  873. }
  874. private static JsValue Imul(JsValue thisObject, JsValue[] arguments)
  875. {
  876. var x = TypeConverter.ToInt32(arguments.At(0));
  877. var y = TypeConverter.ToInt32(arguments.At(1));
  878. return x * y;
  879. }
  880. private static JsValue Clz32(JsValue thisObject, JsValue[] arguments)
  881. {
  882. var x = TypeConverter.ToInt32(arguments.At(0));
  883. if (x < 0)
  884. {
  885. return 0;
  886. }
  887. if (x == 0)
  888. {
  889. return 32;
  890. }
  891. var res = 0;
  892. var shift = 16;
  893. while (x > 1)
  894. {
  895. var temp = x >> shift;
  896. if (temp != 0)
  897. {
  898. x = temp;
  899. res += shift;
  900. }
  901. shift >>= 1;
  902. }
  903. return 31 - res;
  904. }
  905. }
  906. }