0.2.5-dev: merge PR #519 by Cloudnyco — detmath powi: a zero base keeps Math.pow's exact results ((-
This commit is contained in:
commit
6e8103e733
2 files changed
+5
-1
No files matched your search
@@ -67,13 +67,15 @@ function mul2(ah, al, bh, bl, out) {
|
|||||||
/**
|
/**
|
||||||
* xⁿ for an integer n (the sim's powers are stack counts, chain bounces …). The square-and-multiply runs in
|
* xⁿ for an integer n (the sim's powers are stack counts, chain bounces …). The square-and-multiply runs in
|
||||||
* double-double and rounds once, so the result is correctly rounded in practice; a non-integer exponent or a huge
|
* double-double and rounds once, so the result is correctly rounded in practice; a non-integer exponent or a huge
|
||||||
* base falls back to Math.pow.
|
* base falls back to Math.pow. A zero base takes Math.pow's exact results: an odd power keeps the sign of −0, which
|
||||||
|
* the double-double sum would lose ((−0)¹ = −0, (−0)⁻¹ = −∞).
|
||||||
* @param {number} x
|
* @param {number} x
|
||||||
* @param {number} n
|
* @param {number} n
|
||||||
*/
|
*/
|
||||||
export function powi(x, n) {
|
export function powi(x, n) {
|
||||||
// eslint-disable-next-line no-restricted-properties -- outside the integer domain only (never in the sim)
|
// eslint-disable-next-line no-restricted-properties -- outside the integer domain only (never in the sim)
|
||||||
if (!Number.isInteger(n) || !Number.isFinite(x) || Math.abs(x) > P500) return Math.pow(x, n);
|
if (!Number.isInteger(n) || !Number.isFinite(x) || Math.abs(x) > P500) return Math.pow(x, n);
|
||||||
|
if (x === 0) { const odd = n % 2 !== 0; return n === 0 ? 1 : n > 0 ? (odd ? x : 0) : (odd ? 1 / x : Infinity); }
|
||||||
if (n < 0) return 1 / powi(x, -n);
|
if (n < 0) return 1 / powi(x, -n);
|
||||||
ACC[0] = 1; ACC[1] = 0; BASE[0] = x; BASE[1] = 0;
|
ACC[0] = 1; ACC[1] = 0; BASE[0] = x; BASE[1] = 0;
|
||||||
let k = n;
|
let k = n;
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ test('special values follow ECMA-262', () => {
|
|||||||
for (const [y, x, want] of table) same(atan2(y, x), want, `atan2(${y}, ${x})`);
|
for (const [y, x, want] of table) same(atan2(y, x), want, `atan2(${y}, ${x})`);
|
||||||
same(powi(2, 0), 1, 'x^0'); same(powi(0, 0), 1, '0^0'); same(powi(0, 3), 0, '0^3'); same(powi(-2, 3), -8, '(-2)^3');
|
same(powi(2, 0), 1, 'x^0'); same(powi(0, 0), 1, '0^0'); same(powi(0, 3), 0, '0^3'); same(powi(-2, 3), -8, '(-2)^3');
|
||||||
same(powi(2, -2), 0.25, 'x^-n'); same(powi(Infinity, 2), Infinity, '∞²'); same(powi(NaN, 0), 1, 'NaN^0');
|
same(powi(2, -2), 0.25, 'x^-n'); same(powi(Infinity, 2), Infinity, '∞²'); same(powi(NaN, 0), 1, 'NaN^0');
|
||||||
|
// a zero base: Math.pow's exact results, the sign of −0 kept by odd powers
|
||||||
|
for (const z of [0, -0]) for (let n = -3; n <= 3; n++) same(powi(z, n), Math.pow(z, n), `(${Object.is(z, -0) ? '-0' : '0'})^${n}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// exact references: x = M·2^E with M an integer
|
// exact references: x = M·2^E with M an integer
|
||||||
|
|||||||
Reference in new issue
Block a user