diff --git a/decimal.js b/decimal.js index 6d58b0e..46358fc 100644 --- a/decimal.js +++ b/decimal.js @@ -317,7 +317,7 @@ external = false; // Initial estimate. - s = x.s * Math.pow(x.s * x, 1 / 3); + s = x.s * mathpow(x.s * x, 1 / 3); // Math.cbrt underflow/overflow? // Pass x to Math.pow as integer, then adjust the exponent of the result. @@ -327,7 +327,7 @@ // Adjust n exponent so it is a multiple of 3 away from x exponent. if (s = (e - n.length + 1) % 3) n += (s == 1 || s == -2 ? '0' : '00'); - s = Math.pow(n, 1 / 3); + s = mathpow(n, 1 / 3); // Rarely, e may be one less than the result exponent value. e = mathfloor((e + 1) / 3) - (e % 3 == (e < 0 ? -1 : 2)); @@ -546,7 +546,7 @@ // TODO? Estimation reused from cosine() and may not be optimal here. if (len < 32) { k = Math.ceil(len / 3); - n = Math.pow(4, -k).toString(); + n = (1 / tinyPow(4, k)).toString(); } else { k = 16; n = '2.3283064365386962890625e-10'; @@ -626,8 +626,7 @@ k = 1.4 * Math.sqrt(len); k = k > 16 ? 16 : k | 0; - x = x.times(Math.pow(5, -k)); - + x = x.times(1 / tinyPow(5, k)); x = taylorSeries(Ctor, 2, x, x, true); // Reverse argument reduction @@ -2638,7 +2637,7 @@ // Estimate the optimum number of times to use the argument reduction. if (len < 32) { k = Math.ceil(len / 3); - y = Math.pow(4, -k).toString(); + y = (1 / tinyPow(4, k)).toString(); } else { k = 16; y = '2.3283064365386962890625e-10'; @@ -3649,7 +3648,7 @@ if (isFloat) x = divide(x, divisor, len * 4); // Multiply by the binary exponent part if present. - if (p) x = x.times(Math.abs(p) < 54 ? Math.pow(2, p) : Decimal.pow(2, p)); + if (p) x = x.times(Math.abs(p) < 54 ? mathpow(2, p) : Decimal.pow(2, p)); external = true; return x; @@ -3675,8 +3674,7 @@ k = 1.4 * Math.sqrt(len); k = k > 16 ? 16 : k | 0; - // Max k before Math.pow precision loss is 22 - x = x.times(Math.pow(5, -k)); + x = x.times(1 / tinyPow(5, k)); x = taylorSeries(Ctor, 2, x, x); // Reverse argument reduction @@ -3729,6 +3727,14 @@ } + // Exponent e must be positive and non-zero. + function tinyPow(b, e) { + var n = b; + while (--e) n *= b; + return n; + } + + // Return the absolute value of `x` reduced to less than or equal to half pi. function toLessThanHalfPi(Ctor, x) { var t, diff --git a/decimal.mjs b/decimal.mjs index 36f3358..7948fad 100644 --- a/decimal.mjs +++ b/decimal.mjs @@ -313,7 +313,7 @@ P.cubeRoot = P.cbrt = function () { external = false; // Initial estimate. - s = x.s * Math.pow(x.s * x, 1 / 3); + s = x.s * mathpow(x.s * x, 1 / 3); // Math.cbrt underflow/overflow? // Pass x to Math.pow as integer, then adjust the exponent of the result. @@ -323,7 +323,7 @@ P.cubeRoot = P.cbrt = function () { // Adjust n exponent so it is a multiple of 3 away from x exponent. if (s = (e - n.length + 1) % 3) n += (s == 1 || s == -2 ? '0' : '00'); - s = Math.pow(n, 1 / 3); + s = mathpow(n, 1 / 3); // Rarely, e may be one less than the result exponent value. e = mathfloor((e + 1) / 3) - (e % 3 == (e < 0 ? -1 : 2)); @@ -542,7 +542,7 @@ P.hyperbolicCosine = P.cosh = function () { // TODO? Estimation reused from cosine() and may not be optimal here. if (len < 32) { k = Math.ceil(len / 3); - n = Math.pow(4, -k).toString(); + n = (1 / tinyPow(4, k)).toString(); } else { k = 16; n = '2.3283064365386962890625e-10'; @@ -622,8 +622,7 @@ P.hyperbolicSine = P.sinh = function () { k = 1.4 * Math.sqrt(len); k = k > 16 ? 16 : k | 0; - x = x.times(Math.pow(5, -k)); - + x = x.times(1 / tinyPow(5, k)); x = taylorSeries(Ctor, 2, x, x, true); // Reverse argument reduction @@ -2634,7 +2633,7 @@ function cosine(Ctor, x) { // Estimate the optimum number of times to use the argument reduction. if (len < 32) { k = Math.ceil(len / 3); - y = Math.pow(4, -k).toString(); + y = (1 / tinyPow(4, k)).toString(); } else { k = 16; y = '2.3283064365386962890625e-10'; @@ -3645,7 +3644,7 @@ function parseOther(x, str) { if (isFloat) x = divide(x, divisor, len * 4); // Multiply by the binary exponent part if present. - if (p) x = x.times(Math.abs(p) < 54 ? Math.pow(2, p) : Decimal.pow(2, p)); + if (p) x = x.times(Math.abs(p) < 54 ? mathpow(2, p) : Decimal.pow(2, p)); external = true; return x; @@ -3671,8 +3670,7 @@ function sine(Ctor, x) { k = 1.4 * Math.sqrt(len); k = k > 16 ? 16 : k | 0; - // Max k before Math.pow precision loss is 22 - x = x.times(Math.pow(5, -k)); + x = x.times(1 / tinyPow(5, k)); x = taylorSeries(Ctor, 2, x, x); // Reverse argument reduction @@ -3725,6 +3723,14 @@ function taylorSeries(Ctor, n, x, y, isHyperbolic) { } +// Exponent e must be positive and non-zero. +function tinyPow(b, e) { + var n = b; + while (--e) n *= b; + return n; +} + + // Return the absolute value of `x` reduced to less than or equal to half pi. function toLessThanHalfPi(Ctor, x) { var t,