math.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889
  1. var EPSILON = Number.EPSILON || 2.2204460492503130808472633361816e-16;
  2. var Assertion = expect().constructor;
  3. Assertion.prototype.almostEqual = function (obj, precision) {
  4. 'use strict';
  5. var allowedDiff = precision || 1e-11;
  6. return this.within(obj - allowedDiff, obj + allowedDiff);
  7. };
  8. Assertion.prototype.haveULPDistance = function (expected, distance) {
  9. var actual = this._obj;
  10. return this.above(Math.abs(1 - (actual / expected)) / EPSILON, distance);
  11. };
  12. describe('Math', function () {
  13. var functionsHaveNames = (function foo() {}).name === 'foo';
  14. var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit;
  15. var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it;
  16. var isPositiveZero = function (zero) {
  17. 'use strict';
  18. return zero === 0 && 1 / zero === Infinity;
  19. };
  20. var isNegativeZero = function (zero) {
  21. 'use strict';
  22. return zero === 0 && 1 / zero === -Infinity;
  23. };
  24. var numberIsNaN = Number.isNaN || function (value) {
  25. return value !== value;
  26. };
  27. var valueOfIsNaN = { valueOf: function () { return NaN; } };
  28. var valueOfIsInfinity = { valueOf: function () { return Infinity; } };
  29. ifShimIt('is on the exported object', function () {
  30. var exported = require('../');
  31. expect(exported.Math).to.equal(Math);
  32. });
  33. describe('.acosh()', function () {
  34. if (!Object.prototype.hasOwnProperty.call(Math, 'acosh')) {
  35. return it('exists', function () {
  36. expect(Math).to.have.property('acosh');
  37. });
  38. }
  39. ifFunctionsHaveNamesIt('has the right name', function () {
  40. expect(Math.acosh).to.have.property('name', 'acosh');
  41. });
  42. it('is not enumerable', function () {
  43. expect(Math).ownPropertyDescriptor('acosh').to.have.property('enumerable', false);
  44. });
  45. it('has the right arity', function () {
  46. expect(Math.acosh).to.have.property('length', 1);
  47. });
  48. it('should be correct', function () {
  49. expect(numberIsNaN(Math.acosh(NaN))).to.equal(true);
  50. expect(numberIsNaN(Math.acosh(0))).to.equal(true);
  51. expect(numberIsNaN(Math.acosh(0.9999999))).to.equal(true);
  52. expect(numberIsNaN(Math.acosh(-1e300))).to.equal(true);
  53. expect(Math.acosh(1e+99)).to.almostEqual(228.64907138697046);
  54. expect(isPositiveZero(Math.acosh(1))).to.equal(true);
  55. expect(Math.acosh(Infinity)).to.equal(Infinity);
  56. expect(Math.acosh(1234)).to.almostEqual(7.811163220849231);
  57. expect(Math.acosh(8.88)).to.almostEqual(2.8737631531629235);
  58. expect(Math.acosh(1e160)).to.almostEqual(369.10676205960726);
  59. expect(Math.acosh(Number.MAX_VALUE)).to.almostEqual(710.4758600739439);
  60. });
  61. it('works for EPSILON values near 1', function () {
  62. var result = Math.acosh(1 + EPSILON);
  63. var expected = Math.sqrt(2 * EPSILON);
  64. expect(result).to.almostEqual(expected);
  65. expect(result).to.haveULPDistance(expected, 8);
  66. });
  67. });
  68. describe('.asinh()', function () {
  69. if (!Object.prototype.hasOwnProperty.call(Math, 'asinh')) {
  70. return it('exists', function () {
  71. expect(Math).to.have.property('asinh');
  72. });
  73. }
  74. ifFunctionsHaveNamesIt('has the right name', function () {
  75. expect(Math.asinh).to.have.property('name', 'asinh');
  76. });
  77. it('is not enumerable', function () {
  78. expect(Math).ownPropertyDescriptor('asinh').to.have.property('enumerable', false);
  79. });
  80. it('has the right arity', function () {
  81. expect(Math.asinh).to.have.property('length', 1);
  82. });
  83. it('should be correct for NaN', function () {
  84. expect(numberIsNaN(Math.asinh(NaN))).to.equal(true);
  85. });
  86. it('should be correct for zeroes', function () {
  87. expect(isPositiveZero(Math.asinh(+0))).to.equal(true);
  88. expect(isNegativeZero(Math.asinh(-0))).to.equal(true);
  89. });
  90. it('should be correct for Infinities', function () {
  91. expect(Math.asinh(Infinity)).to.equal(Infinity);
  92. expect(Math.asinh(-Infinity)).to.equal(-Infinity);
  93. });
  94. it('should be correct', function () {
  95. expect(Math.asinh(1234)).to.almostEqual(7.811163549201245);
  96. expect(Math.asinh(9.99)).to.almostEqual(2.997227420191335);
  97. expect(Math.asinh(1e150)).to.almostEqual(346.0809111296668);
  98. expect(Math.asinh(1e7)).to.almostEqual(16.811242831518268);
  99. expect(Math.asinh(-1e7)).to.almostEqual(-16.811242831518268);
  100. });
  101. it('is correct for extreme non-infinities', function () {
  102. expect(Math.asinh(1e+300)).not.to.equal(Infinity);
  103. expect(Math.asinh(1e+300)).to.almostEqual(691.4686750787736);
  104. });
  105. });
  106. describe('.atanh()', function () {
  107. if (!Object.prototype.hasOwnProperty.call(Math, 'atanh')) {
  108. return it('exists', function () {
  109. expect(Math).to.have.property('atanh');
  110. });
  111. }
  112. ifFunctionsHaveNamesIt('has the right name', function () {
  113. expect(Math.atanh).to.have.property('name', 'atanh');
  114. });
  115. it('is not enumerable', function () {
  116. expect(Math).ownPropertyDescriptor('atanh').to.have.property('enumerable', false);
  117. });
  118. it('has the right arity', function () {
  119. expect(Math.atanh).to.have.property('length', 1);
  120. });
  121. it('should be correct', function () {
  122. expect(numberIsNaN(Math.atanh(NaN))).to.equal(true);
  123. expect(numberIsNaN(Math.atanh(-1.00000001))).to.equal(true);
  124. expect(numberIsNaN(Math.atanh(1.00000001))).to.equal(true);
  125. expect(numberIsNaN(Math.atanh(-1e300))).to.equal(true);
  126. expect(numberIsNaN(Math.atanh(1e300))).to.equal(true);
  127. expect(Math.atanh(-1)).to.equal(-Infinity);
  128. expect(Math.atanh(1)).to.equal(Infinity);
  129. expect(isPositiveZero(Math.atanh(+0))).to.equal(true);
  130. expect(isNegativeZero(Math.atanh(-0))).to.equal(true);
  131. expect(Math.atanh(0.5)).to.almostEqual(0.5493061443340549);
  132. expect(Math.atanh(-0.5)).to.almostEqual(-0.5493061443340549);
  133. expect(Math.atanh(-0.5)).to.almostEqual(-0.5493061443340549);
  134. expect(Math.atanh(0.444)).to.almostEqual(0.47720201260109457);
  135. });
  136. it('is correct for extreme non-infinities', function () {
  137. expect(Math.atanh(1e-300)).not.to.equal(0);
  138. expect(Math.atanh(1e-300)).to.almostEqual(1e-300);
  139. });
  140. });
  141. describe('.cbrt()', function () {
  142. if (!Object.prototype.hasOwnProperty.call(Math, 'cbrt')) {
  143. return it('exists', function () {
  144. expect(Math).to.have.property('cbrt');
  145. });
  146. }
  147. ifFunctionsHaveNamesIt('has the right name', function () {
  148. expect(Math.cbrt).to.have.property('name', 'cbrt');
  149. });
  150. it('is not enumerable', function () {
  151. expect(Math).ownPropertyDescriptor('cbrt').to.have.property('enumerable', false);
  152. });
  153. it('has the right arity', function () {
  154. expect(Math.cbrt).to.have.property('length', 1);
  155. });
  156. it('should be correct', function () {
  157. expect(isNaN(Math.cbrt(NaN))).to.equal(true);
  158. expect(isPositiveZero(Math.cbrt(+0))).to.equal(true);
  159. expect(isNegativeZero(Math.cbrt(-0))).to.equal(true);
  160. expect(Math.cbrt(Infinity)).to.equal(Infinity);
  161. expect(Math.cbrt(-Infinity)).to.equal(-Infinity);
  162. expect(Math.cbrt(-8)).to.almostEqual(-2);
  163. expect(Math.cbrt(8)).to.almostEqual(2);
  164. expect(Math.cbrt(-1000)).to.almostEqual(-10);
  165. expect(Math.cbrt(1000)).to.almostEqual(10);
  166. });
  167. it('is correct at extremes', function () {
  168. var result = Math.cbrt(1e-300);
  169. var expected = 1e-100;
  170. expect(result).to.almostEqual(expected);
  171. expect(result).to.haveULPDistance(expected, 8);
  172. expect(Math.cbrt(-1e-300)).to.almostEqual(-1e-100);
  173. expect(Math.cbrt(-1e+300)).to.almostEqual(-1e+100);
  174. expect(Math.cbrt(1e+300)).to.almostEqual(1e+100);
  175. });
  176. });
  177. describe('.clz32()', function () {
  178. if (!Object.prototype.hasOwnProperty.call(Math, 'clz32')) {
  179. return it('exists', function () {
  180. expect(Math).to.have.property('clz32');
  181. });
  182. }
  183. ifFunctionsHaveNamesIt('has the right name', function () {
  184. expect(Math.clz32).to.have.property('name', 'clz32');
  185. });
  186. it('is not enumerable', function () {
  187. expect(Math).ownPropertyDescriptor('clz32').to.have.property('enumerable', false);
  188. });
  189. it('has the right arity', function () {
  190. expect(Math.clz32).to.have.property('length', 1);
  191. });
  192. it('should have proper uint32 conversion', function () {
  193. var integers = [5295, -5295, -9007199254740991, 9007199254740991, 0, -0];
  194. var nonNumbers = [undefined, true, null, {}, [], 'str'];
  195. var nonIntegers = [-9007199254741992, 9007199254741992, 5.9];
  196. integers.forEach(function (item) {
  197. expect(Math.clz32(item)).to.be.within(0, 32);
  198. });
  199. nonIntegers.forEach(function (item) {
  200. expect(Math.clz32(item)).to.be.within(0, 32);
  201. });
  202. nonNumbers.forEach(function (item) {
  203. expect(Math.clz32(item)).to.equal(item === true ? 31 : 32);
  204. });
  205. expect(Math.clz32(true)).to.equal(Math.clz32(1));
  206. expect(Math.clz32('')).to.equal(Math.clz32(0));
  207. expect(Math.clz32('10')).to.equal(Math.clz32(10));
  208. expect(Math.clz32(0.1)).to.equal(32);
  209. expect(Math.clz32(-1)).to.equal(0);
  210. expect(Math.clz32(1)).to.equal(31);
  211. expect(Math.clz32(0xFFFFFFFF)).to.equal(0);
  212. expect(Math.clz32(0x1FFFFFFFF)).to.equal(0);
  213. expect(Math.clz32(0x111111111)).to.equal(3);
  214. expect(Math.clz32(0x11111111)).to.equal(3);
  215. });
  216. it('returns 32 for numbers that coerce to 0', function () {
  217. var zeroishes = [
  218. 0,
  219. -0,
  220. NaN,
  221. Infinity,
  222. -Infinity,
  223. 0x100000000,
  224. undefined,
  225. null,
  226. false,
  227. '',
  228. 'str',
  229. {},
  230. [],
  231. [1, 2]
  232. ];
  233. zeroishes.forEach(function (zeroish) {
  234. expect(Math.clz32(zeroish)).to.equal(32);
  235. });
  236. });
  237. });
  238. describe('.cosh()', function () {
  239. if (!Object.prototype.hasOwnProperty.call(Math, 'cosh')) {
  240. return it('exists', function () {
  241. expect(Math).to.have.property('cosh');
  242. });
  243. }
  244. ifFunctionsHaveNamesIt('has the right name', function () {
  245. expect(Math.cosh).to.have.property('name', 'cosh');
  246. });
  247. it('is not enumerable', function () {
  248. expect(Math).ownPropertyDescriptor('cosh').to.have.property('enumerable', false);
  249. });
  250. it('has the right arity', function () {
  251. expect(Math.cosh).to.have.property('length', 1);
  252. });
  253. it('should be correct for NaN', function () {
  254. expect(numberIsNaN(Math.cosh(NaN))).to.equal(true);
  255. });
  256. it('should be correct for Infinities', function () {
  257. expect(Math.cosh(Infinity)).to.equal(Infinity);
  258. expect(Math.cosh(-Infinity)).to.equal(Infinity);
  259. });
  260. it('should be correct for zeroes', function () {
  261. expect(Math.cosh(-0)).to.equal(1);
  262. expect(Math.cosh(+0)).to.equal(1);
  263. });
  264. it('should be correct', function () {
  265. // Overridden precision values here are for Chrome, as of v25.0.1364.172
  266. // Broadened slightly for Firefox 31
  267. expect(Math.cosh(12)).to.almostEqual(81377.39571257407, 9e-11);
  268. expect(Math.cosh(22)).to.almostEqual(1792456423.065795780980053377, 1e-5);
  269. expect(Math.cosh(-10)).to.almostEqual(11013.23292010332313972137);
  270. expect(Math.cosh(-23)).to.almostEqual(4872401723.1244513000, 1e-5);
  271. expect(Math.cosh(-2e-17)).to.equal(1);
  272. });
  273. it('is correct for extreme non-infinities', function () {
  274. expect(Math.cosh(710)).not.to.equal(Infinity);
  275. expect(Math.cosh(710) / 1e+308).to.almostEqual(1.1169973830808557);
  276. });
  277. });
  278. describe('.expm1()', function () {
  279. if (!Object.prototype.hasOwnProperty.call(Math, 'expm1')) {
  280. return it('exists', function () {
  281. expect(Math).to.have.property('expm1');
  282. });
  283. }
  284. ifFunctionsHaveNamesIt('has the right name', function () {
  285. expect(Math.expm1).to.have.property('name', 'expm1');
  286. });
  287. it('is not enumerable', function () {
  288. expect(Math).ownPropertyDescriptor('expm1').to.have.property('enumerable', false);
  289. });
  290. it('has the right arity', function () {
  291. expect(Math.expm1).to.have.property('length', 1);
  292. });
  293. it('should be correct for NaN', function () {
  294. expect(numberIsNaN(Math.expm1(NaN))).to.equal(true);
  295. });
  296. it('should be correct for zeroes', function () {
  297. expect(isPositiveZero(Math.expm1(+0))).to.equal(true);
  298. expect(isNegativeZero(Math.expm1(-0))).to.equal(true);
  299. });
  300. it('should be correct for Infinity', function () {
  301. expect(Math.expm1(Infinity)).to.equal(Infinity);
  302. expect(Math.expm1(-Infinity)).to.equal(-1);
  303. });
  304. it('should be correct for arbitrary numbers', function () {
  305. expect(Math.expm1(10)).to.almostEqual(22025.465794806716516957900645284244366353512618556781);
  306. expect(Math.expm1(-10)).to.almostEqual(-0.99995460007023751514846440848443944938976208191113);
  307. expect(Math.expm1(-2e-17)).to.almostEqual(-2e-17);
  308. });
  309. it('works with very negative numbers', function () {
  310. expect(Math.expm1(-38)).to.almostEqual(-1);
  311. expect(Math.expm1(-8675309)).to.almostEqual(-1);
  312. expect(Math.expm1(-4815162342)).to.almostEqual(-1);
  313. });
  314. });
  315. describe('.hypot()', function () {
  316. if (!Object.prototype.hasOwnProperty.call(Math, 'hypot')) {
  317. return it('exists', function () {
  318. expect(Math).to.have.property('hypot');
  319. });
  320. }
  321. ifFunctionsHaveNamesIt('has the right name', function () {
  322. expect(Math.hypot).to.have.property('name', 'hypot');
  323. });
  324. it('is not enumerable', function () {
  325. expect(Math).ownPropertyDescriptor('hypot').to.have.property('enumerable', false);
  326. });
  327. it('has the right arity', function () {
  328. expect(Math.hypot).to.have.property('length', 2);
  329. });
  330. it('should be correct', function () {
  331. expect(Math.hypot(Infinity)).to.equal(Infinity);
  332. expect(Math.hypot(-Infinity)).to.equal(Infinity);
  333. expect(Math.hypot(Infinity, NaN)).to.equal(Infinity);
  334. expect(Math.hypot(NaN, Infinity)).to.equal(Infinity);
  335. expect(Math.hypot(-Infinity, 'Hello')).to.equal(Infinity);
  336. expect(Math.hypot(1, 2, Infinity)).to.equal(Infinity);
  337. expect(numberIsNaN(Math.hypot(NaN, 1))).to.equal(true);
  338. expect(isPositiveZero(Math.hypot())).to.equal(true);
  339. expect(isPositiveZero(Math.hypot(0, 0, 0))).to.equal(true);
  340. expect(isPositiveZero(Math.hypot(0, -0, 0))).to.equal(true);
  341. expect(isPositiveZero(Math.hypot(-0, -0, -0))).to.equal(true);
  342. expect(Math.hypot(66, 66)).to.almostEqual(93.33809511662427);
  343. expect(Math.hypot(0.1, 100)).to.almostEqual(100.0000499999875);
  344. });
  345. it('should coerce to a number', function () {
  346. expect(Math.hypot('Infinity', 0)).to.equal(Infinity);
  347. expect(Math.hypot('3', '3', '3', '3')).to.equal(6);
  348. });
  349. it('should take more than 3 arguments', function () {
  350. expect(Math.hypot(66, 66, 66)).to.almostEqual(114.3153532995459);
  351. expect(Math.hypot(66, 66, 66, 66)).to.equal(132);
  352. });
  353. it('should have the right length', function () {
  354. expect(Math.hypot.length).to.equal(2);
  355. });
  356. it('works for very large or small numbers', function () {
  357. expect(Math.hypot(1e+300, 1e+300)).to.almostEqual(1.4142135623730952e+300);
  358. expect(Math.hypot(1e-300, 1e-300)).to.almostEqual(1.4142135623730952e-300);
  359. expect(Math.hypot(1e+300, 1e+300, 2, 3)).to.almostEqual(1.4142135623730952e+300);
  360. });
  361. });
  362. describe('.log2()', function () {
  363. if (!Object.prototype.hasOwnProperty.call(Math, 'log2')) {
  364. return it('exists', function () {
  365. expect(Math).to.have.property('log2');
  366. });
  367. }
  368. ifFunctionsHaveNamesIt('has the right name', function () {
  369. expect(Math.log2).to.have.property('name', 'log2');
  370. });
  371. it('is not enumerable', function () {
  372. expect(Math).ownPropertyDescriptor('log2').to.have.property('enumerable', false);
  373. });
  374. it('has the right arity', function () {
  375. expect(Math.log2).to.have.property('length', 1);
  376. });
  377. it('is correct for small numbers', function () {
  378. expect(numberIsNaN(Math.log2(-1e-50))).to.equal(true);
  379. });
  380. it('is correct for edge cases', function () {
  381. expect(numberIsNaN(Math.log2(NaN))).to.equal(true);
  382. expect(Math.log2(+0)).to.equal(-Infinity);
  383. expect(Math.log2(-0)).to.equal(-Infinity);
  384. expect(isPositiveZero(Math.log2(1))).to.equal(true);
  385. expect(Math.log2(Infinity)).to.equal(Infinity);
  386. });
  387. it('should have the right precision', function () {
  388. expect(Math.log2(5)).to.almostEqual(2.321928094887362);
  389. expect(Math.log2(32)).to.almostEqual(5);
  390. });
  391. });
  392. describe('.log10', function () {
  393. if (!Object.prototype.hasOwnProperty.call(Math, 'log10')) {
  394. return it('exists', function () {
  395. expect(Math).to.have.property('log10');
  396. });
  397. }
  398. ifFunctionsHaveNamesIt('has the right name', function () {
  399. expect(Math.log10).to.have.property('name', 'log10');
  400. });
  401. it('is not enumerable', function () {
  402. expect(Math).ownPropertyDescriptor('log10').to.have.property('enumerable', false);
  403. });
  404. it('has the right arity', function () {
  405. expect(Math.log10).to.have.property('length', 1);
  406. });
  407. it('should be correct for edge cases', function () {
  408. expect(numberIsNaN(Math.log10(NaN))).to.equal(true);
  409. expect(numberIsNaN(Math.log10(-1e-50))).to.equal(true);
  410. expect(Math.log10(+0)).to.equal(-Infinity);
  411. expect(Math.log10(-0)).to.equal(-Infinity);
  412. expect(isPositiveZero(Math.log10(1))).to.equal(true);
  413. expect(Math.log10(Infinity)).to.equal(Infinity);
  414. });
  415. it('should have the right precision', function () {
  416. expect(Math.log10(5)).to.almostEqual(0.698970004336018);
  417. expect(Math.log10(50)).to.almostEqual(1.6989700043360187);
  418. });
  419. });
  420. describe('.log1p', function () {
  421. if (!Object.prototype.hasOwnProperty.call(Math, 'log1p')) {
  422. return it('exists', function () {
  423. expect(Math).to.have.property('log1p');
  424. });
  425. }
  426. ifFunctionsHaveNamesIt('has the right name', function () {
  427. expect(Math.log1p).to.have.property('name', 'log1p');
  428. });
  429. it('is not enumerable', function () {
  430. expect(Math).ownPropertyDescriptor('log1p').to.have.property('enumerable', false);
  431. });
  432. it('has the right arity', function () {
  433. expect(Math.log1p).to.have.property('length', 1);
  434. });
  435. it('should be correct', function () {
  436. expect(numberIsNaN(Math.log1p(NaN))).to.equal(true);
  437. expect(numberIsNaN(Math.log1p(-1.000000001))).to.equal(true);
  438. expect(Math.log1p(-1)).to.equal(-Infinity);
  439. expect(isPositiveZero(Math.log1p(+0))).to.equal(true);
  440. expect(isNegativeZero(Math.log1p(-0))).to.equal(true);
  441. expect(Math.log1p(Infinity)).to.equal(Infinity);
  442. expect(Math.log1p(5)).to.almostEqual(1.791759469228055);
  443. expect(Math.log1p(50)).to.almostEqual(3.9318256327243257);
  444. expect(Math.log1p(-1e-17)).to.equal(-1e-17);
  445. expect(Math.log1p(-2e-17)).to.equal(-2e-17);
  446. });
  447. });
  448. describe('.sign()', function () {
  449. if (!Object.prototype.hasOwnProperty.call(Math, 'sign')) {
  450. return it('exists', function () {
  451. expect(Math).to.have.property('sign');
  452. });
  453. }
  454. ifFunctionsHaveNamesIt('has the right name', function () {
  455. expect(Math.sign).to.have.property('name', 'sign');
  456. });
  457. it('is not enumerable', function () {
  458. expect(Math).ownPropertyDescriptor('sign').to.have.property('enumerable', false);
  459. });
  460. it('has the right arity', function () {
  461. expect(Math.sign).to.have.property('length', 1);
  462. });
  463. it('should be correct', function () {
  464. // we also verify that [[ToNumber]] is being called
  465. [Infinity, 1].forEach(function (value) {
  466. expect(Math.sign(value)).to.equal(1);
  467. expect(Math.sign(String(value))).to.equal(1);
  468. });
  469. expect(Math.sign(true)).to.equal(1);
  470. [-Infinity, -1].forEach(function (value) {
  471. expect(Math.sign(value)).to.equal(-1);
  472. expect(Math.sign(String(value))).to.equal(-1);
  473. });
  474. expect(isPositiveZero(Math.sign(+0))).to.equal(true);
  475. expect(isPositiveZero(Math.sign('0'))).to.equal(true);
  476. expect(isPositiveZero(Math.sign('+0'))).to.equal(true);
  477. expect(isPositiveZero(Math.sign(''))).to.equal(true);
  478. expect(isPositiveZero(Math.sign(' '))).to.equal(true);
  479. expect(isPositiveZero(Math.sign(null))).to.equal(true);
  480. expect(isPositiveZero(Math.sign(false))).to.equal(true);
  481. expect(isNegativeZero(Math.sign(-0))).to.equal(true);
  482. expect(isNegativeZero(Math.sign('-0'))).to.equal(true);
  483. expect(numberIsNaN(Math.sign(NaN))).to.equal(true);
  484. expect(numberIsNaN(Math.sign('NaN'))).to.equal(true);
  485. expect(numberIsNaN(Math.sign(undefined))).to.equal(true);
  486. });
  487. });
  488. describe('.sinh()', function () {
  489. if (!Object.prototype.hasOwnProperty.call(Math, 'sinh')) {
  490. return it('exists', function () {
  491. expect(Math).to.have.property('sinh');
  492. });
  493. }
  494. ifFunctionsHaveNamesIt('has the right name', function () {
  495. expect(Math.sinh).to.have.property('name', 'sinh');
  496. });
  497. it('is not enumerable', function () {
  498. expect(Math).ownPropertyDescriptor('sinh').to.have.property('enumerable', false);
  499. });
  500. it('has the right arity', function () {
  501. expect(Math.sinh).to.have.property('length', 1);
  502. });
  503. it('should be correct', function () {
  504. expect(numberIsNaN(Math.sinh(NaN))).to.equal(true);
  505. expect(isPositiveZero(Math.sinh(+0))).to.equal(true);
  506. expect(isNegativeZero(Math.sinh(-0))).to.equal(true);
  507. expect(Math.sinh(Infinity)).to.equal(Infinity);
  508. expect(Math.sinh(-Infinity)).to.equal(-Infinity);
  509. expect(Math.sinh(-5)).to.almostEqual(-74.20321057778875);
  510. expect(Math.sinh(2)).to.almostEqual(3.6268604078470186);
  511. expect(Math.sinh(-2e-17)).to.equal(-2e-17);
  512. });
  513. it('is correct for extreme non-infinities', function () {
  514. expect(Math.sinh(710)).not.to.equal(Infinity);
  515. expect(Math.sinh(710) / 1e+308).to.almostEqual(1.1169973830808557);
  516. });
  517. });
  518. describe('.tanh()', function () {
  519. if (!Object.prototype.hasOwnProperty.call(Math, 'tanh')) {
  520. return it('exists', function () {
  521. expect(Math).to.have.property('tanh');
  522. });
  523. }
  524. ifFunctionsHaveNamesIt('has the right name', function () {
  525. expect(Math.tanh).to.have.property('name', 'tanh');
  526. });
  527. it('is not enumerable', function () {
  528. expect(Math).ownPropertyDescriptor('tanh').to.have.property('enumerable', false);
  529. });
  530. it('has the right arity', function () {
  531. expect(Math.tanh).to.have.property('length', 1);
  532. });
  533. it('should be correct', function () {
  534. expect(numberIsNaN(Math.tanh(NaN))).to.equal(true);
  535. expect(isPositiveZero(Math.tanh(+0))).to.equal(true);
  536. expect(isNegativeZero(Math.tanh(-0))).to.equal(true);
  537. expect(Math.tanh(Infinity)).to.equal(1);
  538. expect(Math.tanh(-Infinity)).to.equal(-1);
  539. expect(Math.tanh(19)).to.almostEqual(1);
  540. expect(Math.tanh(-19)).to.almostEqual(-1);
  541. expect(Math.tanh(20)).to.equal(1); // JS loses precision for true value at this integer
  542. expect(Math.tanh(-20)).to.equal(-1); // JS loses precision for true value at this integer
  543. expect(Math.tanh(10)).to.almostEqual(0.9999999958776927);
  544. expect(Math.tanh(-2e-17)).to.equal(-2e-17);
  545. });
  546. });
  547. describe('.trunc()', function () {
  548. if (!Object.prototype.hasOwnProperty.call(Math, 'trunc')) {
  549. return it('exists', function () {
  550. expect(Math).to.have.property('trunc');
  551. });
  552. }
  553. ifFunctionsHaveNamesIt('has the right name', function () {
  554. expect(Math.trunc).to.have.property('name', 'trunc');
  555. });
  556. it('is not enumerable', function () {
  557. expect(Math).ownPropertyDescriptor('trunc').to.have.property('enumerable', false);
  558. });
  559. it('has the right arity', function () {
  560. expect(Math.trunc).to.have.property('length', 1);
  561. });
  562. it('should be correct', function () {
  563. expect(numberIsNaN(Math.trunc(NaN))).to.equal(true);
  564. expect(isNegativeZero(Math.trunc(-0))).to.equal(true);
  565. expect(isPositiveZero(Math.trunc(+0))).to.equal(true);
  566. expect(Math.trunc(Infinity)).to.equal(Infinity);
  567. expect(Math.trunc(-Infinity)).to.equal(-Infinity);
  568. expect(Math.trunc(1.01)).to.equal(1);
  569. expect(Math.trunc(1.99)).to.equal(1);
  570. expect(Math.trunc(-555.555)).to.equal(-555);
  571. expect(Math.trunc(-1.99)).to.equal(-1);
  572. });
  573. it('should coerce to a number immediately', function () {
  574. expect(Math.trunc(valueOfIsInfinity)).to.equal(Infinity);
  575. expect(numberIsNaN(Math.trunc(valueOfIsNaN))).to.equal(true);
  576. });
  577. });
  578. describe('.imul()', function () {
  579. if (!Object.prototype.hasOwnProperty.call(Math, 'imul')) {
  580. return it('exists', function () {
  581. expect(Math).to.have.property('imul');
  582. });
  583. }
  584. ifFunctionsHaveNamesIt('has the right name', function () {
  585. expect(Math.imul).to.have.property('name', 'imul');
  586. });
  587. it('is not enumerable', function () {
  588. expect(Math).ownPropertyDescriptor('imul').to.have.property('enumerable', false);
  589. });
  590. it('has the right arity', function () {
  591. expect(Math.imul).to.have.property('length', 2);
  592. });
  593. var str = 'str';
  594. var obj = {};
  595. var arr = [];
  596. it('should be correct for non-numbers', function () {
  597. expect(Math.imul(false, 7)).to.equal(0);
  598. expect(Math.imul(7, false)).to.equal(0);
  599. expect(Math.imul(false, false)).to.equal(0);
  600. expect(Math.imul(true, 7)).to.equal(7);
  601. expect(Math.imul(7, true)).to.equal(7);
  602. expect(Math.imul(true, true)).to.equal(1);
  603. expect(Math.imul(undefined, 7)).to.equal(0);
  604. expect(Math.imul(7, undefined)).to.equal(0);
  605. expect(Math.imul(undefined, undefined)).to.equal(0);
  606. expect(Math.imul(str, 7)).to.equal(0);
  607. expect(Math.imul(7, str)).to.equal(0);
  608. expect(Math.imul(obj, 7)).to.equal(0);
  609. expect(Math.imul(7, obj)).to.equal(0);
  610. expect(Math.imul(arr, 7)).to.equal(0);
  611. expect(Math.imul(7, arr)).to.equal(0);
  612. });
  613. it('should be correct for hex values', function () {
  614. expect(Math.imul(0xffffffff, 5)).to.equal(-5);
  615. expect(Math.imul(0xfffffffe, 5)).to.equal(-10);
  616. });
  617. it('should be correct', function () {
  618. expect(Math.imul(2, 4)).to.equal(8);
  619. expect(Math.imul(-1, 8)).to.equal(-8);
  620. expect(Math.imul(-2, -2)).to.equal(4);
  621. expect(Math.imul(-0, 7)).to.equal(0);
  622. expect(Math.imul(7, -0)).to.equal(0);
  623. expect(Math.imul(0.1, 7)).to.equal(0);
  624. expect(Math.imul(7, 0.1)).to.equal(0);
  625. expect(Math.imul(0.9, 7)).to.equal(0);
  626. expect(Math.imul(7, 0.9)).to.equal(0);
  627. expect(Math.imul(1.1, 7)).to.equal(7);
  628. expect(Math.imul(7, 1.1)).to.equal(7);
  629. expect(Math.imul(1.9, 7)).to.equal(7);
  630. expect(Math.imul(7, 1.9)).to.equal(7);
  631. });
  632. it('should be correct for objects with valueOf', function () {
  633. var x = {
  634. x: 0,
  635. valueOf: function () { this.x += 1; return this.x; }
  636. };
  637. expect(Math.imul(x, 1)).to.equal(1);
  638. expect(Math.imul(1, x)).to.equal(2);
  639. expect(Math.imul(x, 1)).to.equal(3);
  640. expect(Math.imul(1, x)).to.equal(4);
  641. expect(Math.imul(x, 1)).to.equal(5);
  642. });
  643. });
  644. describe('.round()', function () {
  645. ifFunctionsHaveNamesIt('has the right name', function () {
  646. expect(Math.round).to.have.property('name', 'round');
  647. });
  648. it('is not enumerable', function () {
  649. expect(Math).ownPropertyDescriptor('round').to.have.property('enumerable', false);
  650. });
  651. it('has the right arity', function () {
  652. expect(Math.round).to.have.property('length', 1);
  653. });
  654. it('works for edge cases', function () {
  655. expect(numberIsNaN(Math.round(NaN))).to.equal(true);
  656. expect(isPositiveZero(Math.round(0))).to.equal(true);
  657. expect(isNegativeZero(Math.round(-0))).to.equal(true);
  658. expect(Math.round(Infinity)).to.equal(Infinity);
  659. expect(Math.round(-Infinity)).to.equal(-Infinity);
  660. });
  661. it('returns 0 for (0,0.5)', function () {
  662. expect(Math.round(0.5)).not.to.equal(0);
  663. expect(Math.round(0.5 - (EPSILON / 4))).to.equal(0);
  664. expect(Math.round(0 + (EPSILON / 4))).to.equal(0);
  665. });
  666. it('returns -0 for (-0.5,0)', function () {
  667. expect(Math.round(-0.5)).to.equal(0);
  668. expect(Math.round(-0.5 - (EPSILON / 3.99))).not.to.equal(0);
  669. expect(isNegativeZero(Math.round(-0.5 + (EPSILON / 3.99)))).to.equal(true);
  670. expect(isNegativeZero(Math.round(0 - (EPSILON / 3.99)))).to.equal(true);
  671. });
  672. it('returns 1 / Number.EPSILON + 1 for 1 / Number.EPSILON + 1', function () {
  673. var inverseEpsilonPlus1 = (1 / EPSILON) + 1;
  674. expect(Math.round(inverseEpsilonPlus1)).to.equal(inverseEpsilonPlus1);
  675. });
  676. it('returns 2 / Number.EPSILON - 1 for 2 / Number.EPSILON - 1', function () {
  677. var twiceInverseEpsilonMinus1 = (2 / EPSILON) - 1;
  678. expect(Math.round(twiceInverseEpsilonMinus1)).to.equal(twiceInverseEpsilonMinus1);
  679. });
  680. });
  681. describe('.fround()', function () {
  682. if (!Object.prototype.hasOwnProperty.call(Math, 'fround')) {
  683. return it('exists', function () {
  684. expect(Math).to.have.property('fround');
  685. });
  686. }
  687. ifFunctionsHaveNamesIt('has the right name', function () {
  688. expect(Math.fround).to.have.property('name', 'fround');
  689. });
  690. it('is not enumerable', function () {
  691. expect(Math).ownPropertyDescriptor('fround').to.have.property('enumerable', false);
  692. });
  693. it('has the right arity', function () {
  694. expect(Math.fround).to.have.property('length', 1);
  695. });
  696. // Mozilla's reference tests: https://bug900125.bugzilla.mozilla.org/attachment.cgi?id=793163
  697. it('returns NaN for undefined', function () {
  698. expect(numberIsNaN(Math.fround())).to.equal(true);
  699. });
  700. it('returns NaN for NaN', function () {
  701. expect(numberIsNaN(Math.fround(NaN))).to.equal(true);
  702. });
  703. it('works for zeroes and infinities', function () {
  704. expect(isPositiveZero(Math.fround(0))).to.equal(true);
  705. expect(isPositiveZero(Math.fround({ valueOf: function () { return 0; } }))).to.equal(true);
  706. expect(isNegativeZero(Math.fround(-0))).to.equal(true);
  707. expect(isNegativeZero(Math.fround({ valueOf: function () { return -0; } }))).to.equal(true);
  708. expect(Math.fround(Infinity)).to.equal(Infinity);
  709. expect(Math.fround({ valueOf: function () { return Infinity; } })).to.equal(Infinity);
  710. expect(Math.fround(-Infinity)).to.equal(-Infinity);
  711. expect(Math.fround({ valueOf: function () { return -Infinity; } })).to.equal(-Infinity);
  712. });
  713. it('returns infinity for large numbers', function () {
  714. expect(Math.fround(1.7976931348623157e+308)).to.equal(Infinity);
  715. expect(Math.fround(-1.7976931348623157e+308)).to.equal(-Infinity);
  716. expect(Math.fround(3.4028235677973366e+38)).to.equal(Infinity);
  717. });
  718. it('returns zero for really small numbers', function () {
  719. expect(Number.MIN_VALUE).to.equal(5e-324);
  720. expect(Math.fround(Number.MIN_VALUE)).to.equal(0);
  721. expect(Math.fround(-Number.MIN_VALUE)).to.equal(0);
  722. });
  723. it('rounds properly', function () {
  724. expect(Math.fround(3)).to.equal(3);
  725. expect(Math.fround(-3)).to.equal(-3);
  726. });
  727. it('rounds properly with the max float 32', function () {
  728. var maxFloat32 = 3.4028234663852886e+38;
  729. expect(Math.fround(maxFloat32)).to.equal(maxFloat32);
  730. expect(Math.fround(-maxFloat32)).to.equal(-maxFloat32);
  731. // round-nearest rounds down to maxFloat32
  732. expect(Math.fround(maxFloat32 + Math.pow(2, Math.pow(2, 8 - 1) - 1 - 23 - 2))).to.equal(maxFloat32);
  733. });
  734. it('rounds properly with the min float 32', function () {
  735. var minFloat32 = 1.401298464324817e-45;
  736. expect(Math.fround(minFloat32)).to.equal(minFloat32);
  737. expect(Math.fround(-minFloat32)).to.equal(-minFloat32);
  738. expect(Math.fround(minFloat32 / 2)).to.equal(0);
  739. expect(Math.fround(-minFloat32 / 2)).to.equal(0);
  740. expect(Math.fround((minFloat32 / 2) + Math.pow(2, -202))).to.equal(minFloat32);
  741. expect(Math.fround((-minFloat32 / 2) - Math.pow(2, -202))).to.equal(-minFloat32);
  742. });
  743. });
  744. });