MathInstance.cs 34 KB

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