MathObject.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2020-2023, Linus Groh <linusg@serenityos.org>
  4. * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include <AK/BuiltinWrappers.h>
  9. #include <AK/Function.h>
  10. #include <AK/Random.h>
  11. #include <LibJS/Runtime/GlobalObject.h>
  12. #include <LibJS/Runtime/MathObject.h>
  13. #include <math.h>
  14. namespace JS {
  15. MathObject::MathObject(Realm& realm)
  16. : Object(ConstructWithPrototypeTag::Tag, realm.intrinsics().object_prototype())
  17. {
  18. }
  19. ThrowCompletionOr<void> MathObject::initialize(Realm& realm)
  20. {
  21. auto& vm = this->vm();
  22. MUST_OR_THROW_OOM(Base::initialize(realm));
  23. u8 attr = Attribute::Writable | Attribute::Configurable;
  24. define_native_function(realm, vm.names.abs, abs, 1, attr);
  25. define_native_function(realm, vm.names.random, random, 0, attr);
  26. define_native_function(realm, vm.names.sqrt, sqrt, 1, attr);
  27. define_native_function(realm, vm.names.floor, floor, 1, attr);
  28. define_native_function(realm, vm.names.ceil, ceil, 1, attr);
  29. define_native_function(realm, vm.names.round, round, 1, attr);
  30. define_native_function(realm, vm.names.max, max, 2, attr);
  31. define_native_function(realm, vm.names.min, min, 2, attr);
  32. define_native_function(realm, vm.names.trunc, trunc, 1, attr);
  33. define_native_function(realm, vm.names.sin, sin, 1, attr);
  34. define_native_function(realm, vm.names.cos, cos, 1, attr);
  35. define_native_function(realm, vm.names.tan, tan, 1, attr);
  36. define_native_function(realm, vm.names.pow, pow, 2, attr);
  37. define_native_function(realm, vm.names.exp, exp, 1, attr);
  38. define_native_function(realm, vm.names.expm1, expm1, 1, attr);
  39. define_native_function(realm, vm.names.sign, sign, 1, attr);
  40. define_native_function(realm, vm.names.clz32, clz32, 1, attr);
  41. define_native_function(realm, vm.names.acos, acos, 1, attr);
  42. define_native_function(realm, vm.names.acosh, acosh, 1, attr);
  43. define_native_function(realm, vm.names.asin, asin, 1, attr);
  44. define_native_function(realm, vm.names.asinh, asinh, 1, attr);
  45. define_native_function(realm, vm.names.atan, atan, 1, attr);
  46. define_native_function(realm, vm.names.atanh, atanh, 1, attr);
  47. define_native_function(realm, vm.names.log1p, log1p, 1, attr);
  48. define_native_function(realm, vm.names.cbrt, cbrt, 1, attr);
  49. define_native_function(realm, vm.names.atan2, atan2, 2, attr);
  50. define_native_function(realm, vm.names.fround, fround, 1, attr);
  51. define_native_function(realm, vm.names.hypot, hypot, 2, attr);
  52. define_native_function(realm, vm.names.imul, imul, 2, attr);
  53. define_native_function(realm, vm.names.log, log, 1, attr);
  54. define_native_function(realm, vm.names.log2, log2, 1, attr);
  55. define_native_function(realm, vm.names.log10, log10, 1, attr);
  56. define_native_function(realm, vm.names.sinh, sinh, 1, attr);
  57. define_native_function(realm, vm.names.cosh, cosh, 1, attr);
  58. define_native_function(realm, vm.names.tanh, tanh, 1, attr);
  59. // 21.3.1 Value Properties of the Math Object, https://tc39.es/ecma262/#sec-value-properties-of-the-math-object
  60. define_direct_property(vm.names.E, Value(M_E), 0);
  61. define_direct_property(vm.names.LN2, Value(M_LN2), 0);
  62. define_direct_property(vm.names.LN10, Value(M_LN10), 0);
  63. define_direct_property(vm.names.LOG2E, Value(::log2(M_E)), 0);
  64. define_direct_property(vm.names.LOG10E, Value(::log10(M_E)), 0);
  65. define_direct_property(vm.names.PI, Value(M_PI), 0);
  66. define_direct_property(vm.names.SQRT1_2, Value(M_SQRT1_2), 0);
  67. define_direct_property(vm.names.SQRT2, Value(M_SQRT2), 0);
  68. // 21.3.1.9 Math [ @@toStringTag ], https://tc39.es/ecma262/#sec-math-@@tostringtag
  69. define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, vm.names.Math.as_string()), Attribute::Configurable);
  70. return {};
  71. }
  72. // 21.3.2.1 Math.abs ( x ), https://tc39.es/ecma262/#sec-math.abs
  73. JS_DEFINE_NATIVE_FUNCTION(MathObject::abs)
  74. {
  75. auto number = TRY(vm.argument(0).to_number(vm));
  76. if (number.is_nan())
  77. return js_nan();
  78. if (number.is_negative_zero())
  79. return Value(0);
  80. if (number.is_negative_infinity())
  81. return js_infinity();
  82. return Value(number.as_double() < 0 ? -number.as_double() : number.as_double());
  83. }
  84. // 21.3.2.27 Math.random ( ), https://tc39.es/ecma262/#sec-math.random
  85. JS_DEFINE_NATIVE_FUNCTION(MathObject::random)
  86. {
  87. double r = (double)get_random<u32>() / (double)UINT32_MAX;
  88. return Value(r);
  89. }
  90. // 21.3.2.32 Math.sqrt ( x ), https://tc39.es/ecma262/#sec-math.sqrt
  91. JS_DEFINE_NATIVE_FUNCTION(MathObject::sqrt)
  92. {
  93. auto number = TRY(vm.argument(0).to_number(vm));
  94. if (number.is_nan())
  95. return js_nan();
  96. return Value(::sqrt(number.as_double()));
  97. }
  98. // 21.3.2.16 Math.floor ( x ), https://tc39.es/ecma262/#sec-math.floor
  99. JS_DEFINE_NATIVE_FUNCTION(MathObject::floor)
  100. {
  101. auto number = TRY(vm.argument(0).to_number(vm));
  102. if (number.is_nan())
  103. return js_nan();
  104. return Value(::floor(number.as_double()));
  105. }
  106. // 21.3.2.10 Math.ceil ( x ), https://tc39.es/ecma262/#sec-math.ceil
  107. JS_DEFINE_NATIVE_FUNCTION(MathObject::ceil)
  108. {
  109. auto number = TRY(vm.argument(0).to_number(vm));
  110. if (number.is_nan())
  111. return js_nan();
  112. auto number_double = number.as_double();
  113. if (number_double < 0 && number_double > -1)
  114. return Value(-0.f);
  115. return Value(::ceil(number.as_double()));
  116. }
  117. // 21.3.2.28 Math.round ( x ), https://tc39.es/ecma262/#sec-math.round
  118. JS_DEFINE_NATIVE_FUNCTION(MathObject::round)
  119. {
  120. auto value = TRY(vm.argument(0).to_number(vm)).as_double();
  121. double integer = ::ceil(value);
  122. if (integer - 0.5 > value)
  123. integer--;
  124. return Value(integer);
  125. }
  126. // 21.3.2.24 Math.max ( ...args ), https://tc39.es/ecma262/#sec-math.max
  127. JS_DEFINE_NATIVE_FUNCTION(MathObject::max)
  128. {
  129. Vector<Value> coerced;
  130. for (size_t i = 0; i < vm.argument_count(); ++i)
  131. coerced.append(TRY(vm.argument(i).to_number(vm)));
  132. auto highest = js_negative_infinity();
  133. for (auto& number : coerced) {
  134. if (number.is_nan())
  135. return js_nan();
  136. if ((number.is_positive_zero() && highest.is_negative_zero()) || number.as_double() > highest.as_double())
  137. highest = number;
  138. }
  139. return highest;
  140. }
  141. // 21.3.2.25 Math.min ( ...args ), https://tc39.es/ecma262/#sec-math.min
  142. JS_DEFINE_NATIVE_FUNCTION(MathObject::min)
  143. {
  144. Vector<Value> coerced;
  145. for (size_t i = 0; i < vm.argument_count(); ++i)
  146. coerced.append(TRY(vm.argument(i).to_number(vm)));
  147. auto lowest = js_infinity();
  148. for (auto& number : coerced) {
  149. if (number.is_nan())
  150. return js_nan();
  151. if ((number.is_negative_zero() && lowest.is_positive_zero()) || number.as_double() < lowest.as_double())
  152. lowest = number;
  153. }
  154. return lowest;
  155. }
  156. // 21.3.2.35 Math.trunc ( x ), https://tc39.es/ecma262/#sec-math.trunc
  157. JS_DEFINE_NATIVE_FUNCTION(MathObject::trunc)
  158. {
  159. auto number = TRY(vm.argument(0).to_number(vm));
  160. if (number.is_nan())
  161. return js_nan();
  162. if (number.as_double() < 0)
  163. return MathObject::ceil(vm);
  164. return MathObject::floor(vm);
  165. }
  166. // 21.3.2.30 Math.sin ( x ), https://tc39.es/ecma262/#sec-math.sin
  167. JS_DEFINE_NATIVE_FUNCTION(MathObject::sin)
  168. {
  169. // 1. Let n be ? ToNumber(x).
  170. auto number = TRY(vm.argument(0).to_number(vm));
  171. // 2. If n is NaN, n is +0๐”ฝ, or n is -0๐”ฝ, return n.
  172. if (number.is_nan() || number.is_positive_zero() || number.is_negative_zero())
  173. return number;
  174. // 3. If n is +โˆž๐”ฝ or n is -โˆž๐”ฝ, return NaN.
  175. if (number.is_infinity())
  176. return js_nan();
  177. // 4. Return an implementation-approximated Number value representing the result of the sine of โ„(n).
  178. return Value(::sin(number.as_double()));
  179. }
  180. // 21.3.2.12 Math.cos ( x ), https://tc39.es/ecma262/#sec-math.cos
  181. JS_DEFINE_NATIVE_FUNCTION(MathObject::cos)
  182. {
  183. // 1. Let n be ? ToNumber(x).
  184. auto number = TRY(vm.argument(0).to_number(vm));
  185. // 2. If n is NaN, n is +โˆž๐”ฝ, or n is -โˆž๐”ฝ, return NaN.
  186. if (number.is_nan() || number.is_infinity())
  187. return js_nan();
  188. // 3. If n is +0๐”ฝ or n is -0๐”ฝ, return 1๐”ฝ.
  189. if (number.is_positive_zero() || number.is_negative_zero())
  190. return Value(1);
  191. // 4. Return an implementation-approximated Number value representing the result of the cosine of โ„(n).
  192. return Value(::cos(number.as_double()));
  193. }
  194. // 21.3.2.33 Math.tan ( x ), https://tc39.es/ecma262/#sec-math.tan
  195. JS_DEFINE_NATIVE_FUNCTION(MathObject::tan)
  196. {
  197. // Let n be ? ToNumber(x).
  198. auto number = TRY(vm.argument(0).to_number(vm));
  199. // 2. If n is NaN, n is +0๐”ฝ, or n is -0๐”ฝ, return n.
  200. if (number.is_nan() || number.is_positive_zero() || number.is_negative_zero())
  201. return number;
  202. // 3. If n is +โˆž๐”ฝ, or n is -โˆž๐”ฝ, return NaN.
  203. if (number.is_infinity())
  204. return js_nan();
  205. // 4. Return an implementation-approximated Number value representing the result of the tangent of โ„(n).
  206. return Value(::tan(number.as_double()));
  207. }
  208. // 21.3.2.26 Math.pow ( base, exponent ), https://tc39.es/ecma262/#sec-math.pow
  209. JS_DEFINE_NATIVE_FUNCTION(MathObject::pow)
  210. {
  211. auto base = TRY(vm.argument(0).to_number(vm));
  212. auto exponent = TRY(vm.argument(1).to_number(vm));
  213. return JS::exp(vm, base, exponent);
  214. }
  215. // 21.3.2.14 Math.exp ( x ), https://tc39.es/ecma262/#sec-math.exp
  216. JS_DEFINE_NATIVE_FUNCTION(MathObject::exp)
  217. {
  218. auto number = TRY(vm.argument(0).to_number(vm));
  219. if (number.is_nan())
  220. return js_nan();
  221. return Value(::exp(number.as_double()));
  222. }
  223. // 21.3.2.15 Math.expm1 ( x ), https://tc39.es/ecma262/#sec-math.expm1
  224. JS_DEFINE_NATIVE_FUNCTION(MathObject::expm1)
  225. {
  226. auto number = TRY(vm.argument(0).to_number(vm));
  227. if (number.is_nan())
  228. return js_nan();
  229. return Value(::expm1(number.as_double()));
  230. }
  231. // 21.3.2.29 Math.sign ( x ), https://tc39.es/ecma262/#sec-math.sign
  232. JS_DEFINE_NATIVE_FUNCTION(MathObject::sign)
  233. {
  234. auto number = TRY(vm.argument(0).to_number(vm));
  235. if (number.is_positive_zero())
  236. return Value(0);
  237. if (number.is_negative_zero())
  238. return Value(-0.0);
  239. if (number.as_double() > 0)
  240. return Value(1);
  241. if (number.as_double() < 0)
  242. return Value(-1);
  243. return js_nan();
  244. }
  245. // 21.3.2.11 Math.clz32 ( x ), https://tc39.es/ecma262/#sec-math.clz32
  246. JS_DEFINE_NATIVE_FUNCTION(MathObject::clz32)
  247. {
  248. auto number = TRY(vm.argument(0).to_u32(vm));
  249. if (number == 0)
  250. return Value(32);
  251. return Value(count_leading_zeroes(number));
  252. }
  253. // 21.3.2.2 Math.acos ( x ), https://tc39.es/ecma262/#sec-math.acos
  254. JS_DEFINE_NATIVE_FUNCTION(MathObject::acos)
  255. {
  256. auto number = TRY(vm.argument(0).to_number(vm));
  257. if (number.is_nan() || number.as_double() > 1 || number.as_double() < -1)
  258. return js_nan();
  259. if (number.as_double() == 1)
  260. return Value(0);
  261. return Value(::acos(number.as_double()));
  262. }
  263. // 21.3.2.3 Math.acosh ( x ), https://tc39.es/ecma262/#sec-math.acosh
  264. JS_DEFINE_NATIVE_FUNCTION(MathObject::acosh)
  265. {
  266. // 1. Let n be ? ToNumber(x).
  267. auto number = TRY(vm.argument(0).to_number(vm));
  268. // 2. If n is NaN or n is +โˆž๐”ฝ, return n.
  269. if (number.is_nan() || number.is_positive_infinity())
  270. return number;
  271. // 3. If n is 1๐”ฝ, return +0๐”ฝ.
  272. if (number.as_double() == 1.0)
  273. return Value(0.0);
  274. // 4. If n < 1๐”ฝ, return NaN.
  275. if (number.as_double() < 1)
  276. return js_nan();
  277. // 5. Return an implementation-approximated Number value representing the result of the inverse hyperbolic cosine of โ„(n).
  278. return Value(::acosh(number.as_double()));
  279. }
  280. // 21.3.2.4 Math.asin ( x ), https://tc39.es/ecma262/#sec-math.asin
  281. JS_DEFINE_NATIVE_FUNCTION(MathObject::asin)
  282. {
  283. // 1. Let n be ? ToNumber(x).
  284. auto number = TRY(vm.argument(0).to_number(vm));
  285. // 2. If n is NaN, n is +0๐”ฝ, or n is -0๐”ฝ, return n.
  286. if (number.is_nan() || number.is_positive_zero() || number.is_negative_zero())
  287. return number;
  288. // 3. If n > 1๐”ฝ or n < -1๐”ฝ, return NaN.
  289. if (number.as_double() > 1 || number.as_double() < -1)
  290. return js_nan();
  291. // 4. Return an implementation-approximated Number value representing the result of the inverse sine of โ„(n).
  292. return Value(::asin(number.as_double()));
  293. }
  294. // 21.3.2.5 Math.asinh ( x ), https://tc39.es/ecma262/#sec-math.asinh
  295. JS_DEFINE_NATIVE_FUNCTION(MathObject::asinh)
  296. {
  297. // 1. Let n be ? ToNumber(x).
  298. auto number = TRY(vm.argument(0).to_number(vm));
  299. // 2. If n is not finite or n is either +0๐”ฝ or -0๐”ฝ, return n.
  300. if (!number.is_finite_number() || number.is_positive_zero() || number.is_negative_zero())
  301. return number;
  302. // 3. Return an implementation-approximated Number value representing the result of the inverse hyperbolic sine of โ„(n).
  303. return Value(::asinh(number.as_double()));
  304. }
  305. // 21.3.2.6 Math.atan ( x ), https://tc39.es/ecma262/#sec-math.atan
  306. JS_DEFINE_NATIVE_FUNCTION(MathObject::atan)
  307. {
  308. auto number = TRY(vm.argument(0).to_number(vm));
  309. if (number.is_nan() || number.is_positive_zero() || number.is_negative_zero())
  310. return number;
  311. if (number.is_positive_infinity())
  312. return Value(M_PI_2);
  313. if (number.is_negative_infinity())
  314. return Value(-M_PI_2);
  315. return Value(::atan(number.as_double()));
  316. }
  317. // 21.3.2.7 Math.atanh ( x ), https://tc39.es/ecma262/#sec-math.atanh
  318. JS_DEFINE_NATIVE_FUNCTION(MathObject::atanh)
  319. {
  320. // 1. Let n be ? ToNumber(x).
  321. auto number = TRY(vm.argument(0).to_number(vm));
  322. // 2. If n is NaN, n is +0๐”ฝ, or n is -0๐”ฝ, return n.
  323. if (number.is_nan() || number.is_positive_zero() || number.is_negative_zero())
  324. return number;
  325. // 3. If n > 1๐”ฝ or n < -1๐”ฝ, return NaN.
  326. if (number.as_double() > 1. || number.as_double() < -1.)
  327. return js_nan();
  328. // 4. If n is 1๐”ฝ, return +โˆž๐”ฝ.
  329. if (number.as_double() == 1.)
  330. return js_infinity();
  331. // 5. If n is -1๐”ฝ, return -โˆž๐”ฝ.
  332. if (number.as_double() == -1.)
  333. return js_negative_infinity();
  334. // 6. Return an implementation-approximated Number value representing the result of the inverse hyperbolic tangent of โ„(n).
  335. return Value(::atanh(number.as_double()));
  336. }
  337. // 21.3.2.21 Math.log1p ( x ), https://tc39.es/ecma262/#sec-math.log1p
  338. JS_DEFINE_NATIVE_FUNCTION(MathObject::log1p)
  339. {
  340. // 1. Let n be ? ToNumber(x).
  341. auto number = TRY(vm.argument(0).to_number(vm));
  342. // 2. If n is NaN, n is +0๐”ฝ, n is -0๐”ฝ, or n is +โˆž๐”ฝ, return n.
  343. if (number.is_nan() || number.is_positive_zero() || number.is_negative_zero() || number.is_positive_infinity())
  344. return number;
  345. // 3. If n is -1๐”ฝ, return -โˆž๐”ฝ.
  346. if (number.as_double() == -1.)
  347. return js_negative_infinity();
  348. // 4. If n < -1๐”ฝ, return NaN.
  349. if (number.as_double() < -1.)
  350. return js_nan();
  351. // 5. Return an implementation-approximated Number value representing the result of the natural logarithm of 1 + โ„(n).
  352. return Value(::log1p(number.as_double()));
  353. }
  354. // 21.3.2.9 Math.cbrt ( x ), https://tc39.es/ecma262/#sec-math.cbrt
  355. JS_DEFINE_NATIVE_FUNCTION(MathObject::cbrt)
  356. {
  357. return Value(::cbrt(TRY(vm.argument(0).to_number(vm)).as_double()));
  358. }
  359. // 21.3.2.8 Math.atan2 ( y, x ), https://tc39.es/ecma262/#sec-math.atan2
  360. JS_DEFINE_NATIVE_FUNCTION(MathObject::atan2)
  361. {
  362. auto constexpr three_quarters_pi = M_PI_4 + M_PI_2;
  363. auto y = TRY(vm.argument(0).to_number(vm));
  364. auto x = TRY(vm.argument(1).to_number(vm));
  365. if (y.is_nan() || x.is_nan())
  366. return js_nan();
  367. if (y.is_positive_infinity()) {
  368. if (x.is_positive_infinity())
  369. return Value(M_PI_4);
  370. else if (x.is_negative_infinity())
  371. return Value(three_quarters_pi);
  372. else
  373. return Value(M_PI_2);
  374. }
  375. if (y.is_negative_infinity()) {
  376. if (x.is_positive_infinity())
  377. return Value(-M_PI_4);
  378. else if (x.is_negative_infinity())
  379. return Value(-three_quarters_pi);
  380. else
  381. return Value(-M_PI_2);
  382. }
  383. if (y.is_positive_zero()) {
  384. if (x.as_double() > 0 || x.is_positive_zero())
  385. return Value(0.0);
  386. else
  387. return Value(M_PI);
  388. }
  389. if (y.is_negative_zero()) {
  390. if (x.as_double() > 0 || x.is_positive_zero())
  391. return Value(-0.0);
  392. else
  393. return Value(-M_PI);
  394. }
  395. VERIFY(y.is_finite_number() && !y.is_positive_zero() && !y.is_negative_zero());
  396. if (y.as_double() > 0) {
  397. if (x.is_positive_infinity())
  398. return Value(0);
  399. else if (x.is_negative_infinity())
  400. return Value(M_PI);
  401. else if (x.is_positive_zero() || x.is_negative_zero())
  402. return Value(M_PI_2);
  403. }
  404. if (y.as_double() < 0) {
  405. if (x.is_positive_infinity())
  406. return Value(-0.0);
  407. else if (x.is_negative_infinity())
  408. return Value(-M_PI);
  409. else if (x.is_positive_zero() || x.is_negative_zero())
  410. return Value(-M_PI_2);
  411. }
  412. VERIFY(x.is_finite_number() && !x.is_positive_zero() && !x.is_negative_zero());
  413. return Value(::atan2(y.as_double(), x.as_double()));
  414. }
  415. // 21.3.2.17 Math.fround ( x ), https://tc39.es/ecma262/#sec-math.fround
  416. JS_DEFINE_NATIVE_FUNCTION(MathObject::fround)
  417. {
  418. auto number = TRY(vm.argument(0).to_number(vm));
  419. if (number.is_nan())
  420. return js_nan();
  421. return Value((float)number.as_double());
  422. }
  423. // 21.3.2.18 Math.hypot ( ...args ), https://tc39.es/ecma262/#sec-math.hypot
  424. JS_DEFINE_NATIVE_FUNCTION(MathObject::hypot)
  425. {
  426. Vector<Value> coerced;
  427. for (size_t i = 0; i < vm.argument_count(); ++i)
  428. coerced.append(TRY(vm.argument(i).to_number(vm)));
  429. for (auto& number : coerced) {
  430. if (number.is_positive_infinity() || number.is_negative_infinity())
  431. return js_infinity();
  432. }
  433. auto only_zero = true;
  434. double sum_of_squares = 0;
  435. for (auto& number : coerced) {
  436. if (number.is_nan() || number.is_positive_infinity())
  437. return number;
  438. if (number.is_negative_infinity())
  439. return js_infinity();
  440. if (!number.is_positive_zero() && !number.is_negative_zero())
  441. only_zero = false;
  442. sum_of_squares += number.as_double() * number.as_double();
  443. }
  444. if (only_zero)
  445. return Value(0);
  446. return Value(::sqrt(sum_of_squares));
  447. }
  448. // 21.3.2.19 Math.imul ( x, y ), https://tc39.es/ecma262/#sec-math.imul
  449. JS_DEFINE_NATIVE_FUNCTION(MathObject::imul)
  450. {
  451. auto a = TRY(vm.argument(0).to_u32(vm));
  452. auto b = TRY(vm.argument(1).to_u32(vm));
  453. return Value(static_cast<i32>(a * b));
  454. }
  455. // 21.3.2.20 Math.log ( x ), https://tc39.es/ecma262/#sec-math.log
  456. JS_DEFINE_NATIVE_FUNCTION(MathObject::log)
  457. {
  458. // 1. Let n be ? ToNumber(x).
  459. auto number = TRY(vm.argument(0).to_number(vm));
  460. // 2. If n is NaN or n is +โˆž๐”ฝ, return n.
  461. if (number.is_nan() || number.is_positive_infinity())
  462. return number;
  463. // 3. If n is 1๐”ฝ, return +0๐”ฝ.
  464. if (number.as_double() == 1.)
  465. return Value(0);
  466. // 4. If n is +0๐”ฝ or n is -0๐”ฝ, return -โˆž๐”ฝ.
  467. if (number.is_positive_zero() || number.is_negative_zero())
  468. return js_negative_infinity();
  469. // 5. If n < -0๐”ฝ, return NaN.
  470. if (number.as_double() < -0.)
  471. return js_nan();
  472. // 6. Return an implementation-approximated Number value representing the result of the natural logarithm of โ„(n).
  473. return Value(::log(number.as_double()));
  474. }
  475. // 21.3.2.23 Math.log2 ( x ), https://tc39.es/ecma262/#sec-math.log2
  476. JS_DEFINE_NATIVE_FUNCTION(MathObject::log2)
  477. {
  478. // 1. Let n be ? ToNumber(x).
  479. auto number = TRY(vm.argument(0).to_number(vm));
  480. // 2. If n is NaN or n is +โˆž๐”ฝ, return n.
  481. if (number.is_nan() || number.is_positive_infinity())
  482. return number;
  483. // 3. If n is 1๐”ฝ, return +0๐”ฝ.
  484. if (number.as_double() == 1.)
  485. return Value(0);
  486. // 4. If n is +0๐”ฝ or n is -0๐”ฝ, return -โˆž๐”ฝ.
  487. if (number.is_positive_zero() || number.is_negative_zero())
  488. return js_negative_infinity();
  489. // 5. If n < -0๐”ฝ, return NaN.
  490. if (number.as_double() < -0.)
  491. return js_nan();
  492. // 6. Return an implementation-approximated Number value representing the result of the base 2 logarithm of โ„(n).
  493. return Value(::log2(number.as_double()));
  494. }
  495. // 21.3.2.22 Math.log10 ( x ), https://tc39.es/ecma262/#sec-math.log10
  496. JS_DEFINE_NATIVE_FUNCTION(MathObject::log10)
  497. {
  498. // 1. Let n be ? ToNumber(x).
  499. auto number = TRY(vm.argument(0).to_number(vm));
  500. // 2. If n is NaN or n is +โˆž๐”ฝ, return n.
  501. if (number.is_nan() || number.is_positive_infinity())
  502. return number;
  503. // 3. If n is 1๐”ฝ, return +0๐”ฝ.
  504. if (number.as_double() == 1.)
  505. return Value(0);
  506. // 4. If n is +0๐”ฝ or n is -0๐”ฝ, return -โˆž๐”ฝ.
  507. if (number.is_positive_zero() || number.is_negative_zero())
  508. return js_negative_infinity();
  509. // 5. If n < -0๐”ฝ, return NaN.
  510. if (number.as_double() < -0.)
  511. return js_nan();
  512. // 6. Return an implementation-approximated Number value representing the result of the base 10 logarithm of โ„(n).
  513. return Value(::log10(number.as_double()));
  514. }
  515. // 21.3.2.31 Math.sinh ( x ), https://tc39.es/ecma262/#sec-math.sinh
  516. JS_DEFINE_NATIVE_FUNCTION(MathObject::sinh)
  517. {
  518. // 1. Let n be ? ToNumber(x).
  519. auto number = TRY(vm.argument(0).to_number(vm));
  520. // 2. If n is not finite or n is either +0๐”ฝ or -0๐”ฝ, return n.
  521. if (!number.is_finite_number() || number.is_positive_zero() || number.is_negative_zero())
  522. return number;
  523. // 3. Return an implementation-approximated Number value representing the result of the hyperbolic sine of โ„(n).
  524. return Value(::sinh(number.as_double()));
  525. }
  526. // 21.3.2.13 Math.cosh ( x ), https://tc39.es/ecma262/#sec-math.cosh
  527. JS_DEFINE_NATIVE_FUNCTION(MathObject::cosh)
  528. {
  529. // 1. Let n be ? ToNumber(x).
  530. auto number = TRY(vm.argument(0).to_number(vm));
  531. // 2. If n is NaN, return NaN.
  532. if (number.is_nan())
  533. return js_nan();
  534. // 3. If n is +โˆž๐”ฝ or n is -โˆž๐”ฝ, return +โˆž๐”ฝ.
  535. if (number.is_positive_infinity() || number.is_negative_infinity())
  536. return js_infinity();
  537. // 4. If n is +0๐”ฝ or n is -0๐”ฝ, return 1๐”ฝ.
  538. if (number.is_positive_zero() || number.is_negative_zero())
  539. return Value(1);
  540. // 5. Return an implementation-approximated Number value representing the result of the hyperbolic cosine of โ„(n).
  541. return Value(::cosh(number.as_double()));
  542. }
  543. // 21.3.2.34 Math.tanh ( x ), https://tc39.es/ecma262/#sec-math.tanh
  544. JS_DEFINE_NATIVE_FUNCTION(MathObject::tanh)
  545. {
  546. // 1. Let n be ? ToNumber(x).
  547. auto number = TRY(vm.argument(0).to_number(vm));
  548. // 2. If n is NaN, n is +0๐”ฝ, or n is -0๐”ฝ, return n.
  549. if (number.is_nan() || number.is_positive_zero() || number.is_negative_zero())
  550. return number;
  551. // 3. If n is +โˆž๐”ฝ, return 1๐”ฝ.
  552. if (number.is_positive_infinity())
  553. return Value(1);
  554. // 4. If n is -โˆž๐”ฝ, return -1๐”ฝ.
  555. if (number.is_negative_infinity())
  556. return Value(-1);
  557. // 5. Return an implementation-approximated Number value representing the result of the hyperbolic tangent of โ„(n).
  558. return Value(::tanh(number.as_double()));
  559. }
  560. }