mirror of
https://github.com/MikeMcl/decimal.js.git
synced 2024-10-27 20:34:12 +00:00
Bugfix: #58 pow sometimes throws when result is Infinity
This commit is contained in:
parent
32f0a63095
commit
22ac9377c6
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* decimal.js v7.2.2
|
* decimal.js v7.2.3
|
||||||
* An arbitrary-precision Decimal type for JavaScript.
|
* An arbitrary-precision Decimal type for JavaScript.
|
||||||
* https://github.com/MikeMcl/decimal.js
|
* https://github.com/MikeMcl/decimal.js
|
||||||
* Copyright (c) 2017 Michael Mclaughlin <M8ch88l@gmail.com>
|
* Copyright (c) 2017 Michael Mclaughlin <M8ch88l@gmail.com>
|
||||||
@ -2247,13 +2247,13 @@ P.toOctal = function (sd, rm) {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
P.toPower = P.pow = function (y) {
|
P.toPower = P.pow = function (y) {
|
||||||
var e, k, pr, r, rm, sign, yIsInt,
|
var e, k, pr, r, rm, s,
|
||||||
x = this,
|
x = this,
|
||||||
Ctor = x.constructor,
|
Ctor = x.constructor,
|
||||||
yn = +(y = new Ctor(y));
|
yn = +(y = new Ctor(y));
|
||||||
|
|
||||||
// Either ±Infinity, NaN or ±0?
|
// Either ±Infinity, NaN or ±0?
|
||||||
if (!x.d || !y.d || !x.d[0] || !y.d[0]) return new Ctor(mathpow(+x, yn));
|
if (!x.d || !y.d || !x.d[0] || !y.d[0]) return new Ctor(mathpow(+x, yn));
|
||||||
|
|
||||||
x = new Ctor(x);
|
x = new Ctor(x);
|
||||||
|
|
||||||
@ -2264,26 +2264,31 @@ P.toPower = P.pow = function (y) {
|
|||||||
|
|
||||||
if (y.eq(1)) return finalise(x, pr, rm);
|
if (y.eq(1)) return finalise(x, pr, rm);
|
||||||
|
|
||||||
|
// y exponent
|
||||||
e = mathfloor(y.e / LOG_BASE);
|
e = mathfloor(y.e / LOG_BASE);
|
||||||
k = y.d.length - 1;
|
|
||||||
yIsInt = e >= k;
|
|
||||||
sign = x.s;
|
|
||||||
|
|
||||||
if (!yIsInt) {
|
|
||||||
if (sign < 0) return new Ctor(NaN);
|
|
||||||
|
|
||||||
// If y is a small integer use the 'exponentiation by squaring' algorithm.
|
// If y is a small integer use the 'exponentiation by squaring' algorithm.
|
||||||
} else if ((k = yn < 0 ? -yn : yn) <= MAX_SAFE_INTEGER) {
|
if (e >= y.d.length - 1 && (k = yn < 0 ? -yn : yn) <= MAX_SAFE_INTEGER) {
|
||||||
r = intPow(Ctor, x, k, pr);
|
r = intPow(Ctor, x, k, pr);
|
||||||
return y.s < 0 ? new Ctor(1).div(r) : finalise(r, pr, rm);
|
return y.s < 0 ? new Ctor(1).div(r) : finalise(r, pr, rm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result is negative if x is negative and the last digit of integer y is odd.
|
s = x.s;
|
||||||
sign = sign < 0 && y.d[Math.max(e, k)] & 1 ? -1 : 1;
|
|
||||||
|
|
||||||
if (x.eq(-1)) {
|
// if x is negative
|
||||||
x.s = sign;
|
if (s < 0) {
|
||||||
return x;
|
|
||||||
|
// if y is not an integer
|
||||||
|
if (e < y.d.length - 1) return new Ctor(NaN);
|
||||||
|
|
||||||
|
// Result is positive if x is negative and the last digit of integer y is even.
|
||||||
|
if ((y.d[e] & 1) == 0) s = 1;
|
||||||
|
|
||||||
|
// if x.eq(-1)
|
||||||
|
if (x.e == 0 && x.d[0] == 1 && x.d.length == 1) {
|
||||||
|
x.s = s;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estimate result exponent.
|
// Estimate result exponent.
|
||||||
@ -2295,10 +2300,10 @@ P.toPower = P.pow = function (y) {
|
|||||||
? mathfloor(yn * (Math.log('0.' + digitsToString(x.d)) / Math.LN10 + x.e + 1))
|
? mathfloor(yn * (Math.log('0.' + digitsToString(x.d)) / Math.LN10 + x.e + 1))
|
||||||
: new Ctor(k + '').e;
|
: new Ctor(k + '').e;
|
||||||
|
|
||||||
// Estimate may be incorrect e.g. x: 0.999999999999999999, y: 2.29, e: 0, r.e: -1.
|
// Exponent estimate may be incorrect e.g. x: 0.999999999999999999, y: 2.29, e: 0, r.e: -1.
|
||||||
|
|
||||||
// Overflow/underflow?
|
// Overflow/underflow?
|
||||||
if (e > Ctor.maxE + 1 || e < Ctor.minE - 1) return new Ctor(e > 0 ? sign / 0 : 0);
|
if (e > Ctor.maxE + 1 || e < Ctor.minE - 1) return new Ctor(e > 0 ? s / 0 : 0);
|
||||||
|
|
||||||
external = false;
|
external = false;
|
||||||
Ctor.rounding = x.s = 1;
|
Ctor.rounding = x.s = 1;
|
||||||
@ -2312,24 +2317,28 @@ P.toPower = P.pow = function (y) {
|
|||||||
// r = x^y = exp(y*ln(x))
|
// r = x^y = exp(y*ln(x))
|
||||||
r = naturalExponential(y.times(naturalLogarithm(x, pr + k)), pr);
|
r = naturalExponential(y.times(naturalLogarithm(x, pr + k)), pr);
|
||||||
|
|
||||||
// Truncate to the required precision plus five rounding digits.
|
// r may be Infinity, e.g. (0.9999999999999999).pow(-1e+40)
|
||||||
r = finalise(r, pr + 5, 1);
|
if (r.d) {
|
||||||
|
|
||||||
// If the rounding digits are [49]9999 or [50]0000 increase the precision by 10 and recalculate
|
// Truncate to the required precision plus five rounding digits.
|
||||||
// the result.
|
r = finalise(r, pr + 5, 1);
|
||||||
if (checkRoundingDigits(r.d, pr, rm)) {
|
|
||||||
e = pr + 10;
|
|
||||||
|
|
||||||
// Truncate to the increased precision plus five rounding digits.
|
// If the rounding digits are [49]9999 or [50]0000 increase the precision by 10 and recalculate
|
||||||
r = finalise(naturalExponential(y.times(naturalLogarithm(x, e + k)), e), e + 5, 1);
|
// the result.
|
||||||
|
if (checkRoundingDigits(r.d, pr, rm)) {
|
||||||
|
e = pr + 10;
|
||||||
|
|
||||||
// Check for 14 nines from the 2nd rounding digit (the first rounding digit may be 4 or 9).
|
// Truncate to the increased precision plus five rounding digits.
|
||||||
if (+digitsToString(r.d).slice(pr + 1, pr + 15) + 1 == 1e14) {
|
r = finalise(naturalExponential(y.times(naturalLogarithm(x, e + k)), e), e + 5, 1);
|
||||||
r = finalise(r, pr + 1, 0);
|
|
||||||
|
// Check for 14 nines from the 2nd rounding digit (the first rounding digit may be 4 or 9).
|
||||||
|
if (+digitsToString(r.d).slice(pr + 1, pr + 15) + 1 == 1e14) {
|
||||||
|
r = finalise(r, pr + 1, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.s = sign;
|
r.s = s;
|
||||||
external = true;
|
external = true;
|
||||||
Ctor.rounding = rm;
|
Ctor.rounding = rm;
|
||||||
|
|
||||||
|
70
decimal.js
70
decimal.js
@ -1,10 +1,10 @@
|
|||||||
/*! decimal.js v7.2.2 https://github.com/MikeMcl/decimal.js/LICENCE */
|
/*! decimal.js v7.2.3 https://github.com/MikeMcl/decimal.js/LICENCE */
|
||||||
;(function (globalScope) {
|
;(function (globalScope) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* decimal.js v7.2.2
|
* decimal.js v7.2.3
|
||||||
* An arbitrary-precision Decimal type for JavaScript.
|
* An arbitrary-precision Decimal type for JavaScript.
|
||||||
* https://github.com/MikeMcl/decimal.js
|
* https://github.com/MikeMcl/decimal.js
|
||||||
* Copyright (c) 2017 Michael Mclaughlin <M8ch88l@gmail.com>
|
* Copyright (c) 2017 Michael Mclaughlin <M8ch88l@gmail.com>
|
||||||
@ -2249,13 +2249,13 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
P.toPower = P.pow = function (y) {
|
P.toPower = P.pow = function (y) {
|
||||||
var e, k, pr, r, rm, sign, yIsInt,
|
var e, k, pr, r, rm, s,
|
||||||
x = this,
|
x = this,
|
||||||
Ctor = x.constructor,
|
Ctor = x.constructor,
|
||||||
yn = +(y = new Ctor(y));
|
yn = +(y = new Ctor(y));
|
||||||
|
|
||||||
// Either ±Infinity, NaN or ±0?
|
// Either ±Infinity, NaN or ±0?
|
||||||
if (!x.d || !y.d || !x.d[0] || !y.d[0]) return new Ctor(mathpow(+x, yn));
|
if (!x.d || !y.d || !x.d[0] || !y.d[0]) return new Ctor(mathpow(+x, yn));
|
||||||
|
|
||||||
x = new Ctor(x);
|
x = new Ctor(x);
|
||||||
|
|
||||||
@ -2266,26 +2266,31 @@
|
|||||||
|
|
||||||
if (y.eq(1)) return finalise(x, pr, rm);
|
if (y.eq(1)) return finalise(x, pr, rm);
|
||||||
|
|
||||||
|
// y exponent
|
||||||
e = mathfloor(y.e / LOG_BASE);
|
e = mathfloor(y.e / LOG_BASE);
|
||||||
k = y.d.length - 1;
|
|
||||||
yIsInt = e >= k;
|
|
||||||
sign = x.s;
|
|
||||||
|
|
||||||
if (!yIsInt) {
|
|
||||||
if (sign < 0) return new Ctor(NaN);
|
|
||||||
|
|
||||||
// If y is a small integer use the 'exponentiation by squaring' algorithm.
|
// If y is a small integer use the 'exponentiation by squaring' algorithm.
|
||||||
} else if ((k = yn < 0 ? -yn : yn) <= MAX_SAFE_INTEGER) {
|
if (e >= y.d.length - 1 && (k = yn < 0 ? -yn : yn) <= MAX_SAFE_INTEGER) {
|
||||||
r = intPow(Ctor, x, k, pr);
|
r = intPow(Ctor, x, k, pr);
|
||||||
return y.s < 0 ? new Ctor(1).div(r) : finalise(r, pr, rm);
|
return y.s < 0 ? new Ctor(1).div(r) : finalise(r, pr, rm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result is negative if x is negative and the last digit of integer y is odd.
|
s = x.s;
|
||||||
sign = sign < 0 && y.d[Math.max(e, k)] & 1 ? -1 : 1;
|
|
||||||
|
|
||||||
if (x.eq(-1)) {
|
// if x is negative
|
||||||
x.s = sign;
|
if (s < 0) {
|
||||||
return x;
|
|
||||||
|
// if y is not an integer
|
||||||
|
if (e < y.d.length - 1) return new Ctor(NaN);
|
||||||
|
|
||||||
|
// Result is positive if x is negative and the last digit of integer y is even.
|
||||||
|
if ((y.d[e] & 1) == 0) s = 1;
|
||||||
|
|
||||||
|
// if x.eq(-1)
|
||||||
|
if (x.e == 0 && x.d[0] == 1 && x.d.length == 1) {
|
||||||
|
x.s = s;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estimate result exponent.
|
// Estimate result exponent.
|
||||||
@ -2293,15 +2298,14 @@
|
|||||||
// log10(x) = log10(x_significand) + x_exponent
|
// log10(x) = log10(x_significand) + x_exponent
|
||||||
// log10(x_significand) = ln(x_significand) / ln(10)
|
// log10(x_significand) = ln(x_significand) / ln(10)
|
||||||
k = mathpow(+x, yn);
|
k = mathpow(+x, yn);
|
||||||
|
|
||||||
e = k == 0 || !isFinite(k)
|
e = k == 0 || !isFinite(k)
|
||||||
? mathfloor(yn * (Math.log('0.' + digitsToString(x.d)) / Math.LN10 + x.e + 1))
|
? mathfloor(yn * (Math.log('0.' + digitsToString(x.d)) / Math.LN10 + x.e + 1))
|
||||||
: new Ctor(k + '').e;
|
: new Ctor(k + '').e;
|
||||||
|
|
||||||
// Estimate may be incorrect e.g. x: 0.999999999999999999, y: 2.29, e: 0, r.e: -1.
|
// Exponent estimate may be incorrect e.g. x: 0.999999999999999999, y: 2.29, e: 0, r.e: -1.
|
||||||
|
|
||||||
// Overflow/underflow?
|
// Overflow/underflow?
|
||||||
if (e > Ctor.maxE + 1 || e < Ctor.minE - 1) return new Ctor(e > 0 ? sign / 0 : 0);
|
if (e > Ctor.maxE + 1 || e < Ctor.minE - 1) return new Ctor(e > 0 ? s / 0 : 0);
|
||||||
|
|
||||||
external = false;
|
external = false;
|
||||||
Ctor.rounding = x.s = 1;
|
Ctor.rounding = x.s = 1;
|
||||||
@ -2315,24 +2319,28 @@
|
|||||||
// r = x^y = exp(y*ln(x))
|
// r = x^y = exp(y*ln(x))
|
||||||
r = naturalExponential(y.times(naturalLogarithm(x, pr + k)), pr);
|
r = naturalExponential(y.times(naturalLogarithm(x, pr + k)), pr);
|
||||||
|
|
||||||
// Truncate to the required precision plus five rounding digits.
|
// r may be Infinity, e.g. (0.9999999999999999).pow(-1e+40)
|
||||||
r = finalise(r, pr + 5, 1);
|
if (r.d) {
|
||||||
|
|
||||||
// If the rounding digits are [49]9999 or [50]0000 increase the precision by 10 and recalculate
|
// Truncate to the required precision plus five rounding digits.
|
||||||
// the result.
|
r = finalise(r, pr + 5, 1);
|
||||||
if (checkRoundingDigits(r.d, pr, rm)) {
|
|
||||||
e = pr + 10;
|
|
||||||
|
|
||||||
// Truncate to the increased precision plus five rounding digits.
|
// If the rounding digits are [49]9999 or [50]0000 increase the precision by 10 and recalculate
|
||||||
r = finalise(naturalExponential(y.times(naturalLogarithm(x, e + k)), e), e + 5, 1);
|
// the result.
|
||||||
|
if (checkRoundingDigits(r.d, pr, rm)) {
|
||||||
|
e = pr + 10;
|
||||||
|
|
||||||
// Check for 14 nines from the 2nd rounding digit (the first rounding digit may be 4 or 9).
|
// Truncate to the increased precision plus five rounding digits.
|
||||||
if (+digitsToString(r.d).slice(pr + 1, pr + 15) + 1 == 1e14) {
|
r = finalise(naturalExponential(y.times(naturalLogarithm(x, e + k)), e), e + 5, 1);
|
||||||
r = finalise(r, pr + 1, 0);
|
|
||||||
|
// Check for 14 nines from the 2nd rounding digit (the first rounding digit may be 4 or 9).
|
||||||
|
if (+digitsToString(r.d).slice(pr + 1, pr + 15) + 1 == 1e14) {
|
||||||
|
r = finalise(r, pr + 1, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.s = sign;
|
r.s = s;
|
||||||
external = true;
|
external = true;
|
||||||
Ctor.rounding = rm;
|
Ctor.rounding = rm;
|
||||||
|
|
||||||
|
@ -109,6 +109,11 @@ T('pow', function () {
|
|||||||
t('8.97', '-1', '0.111482720178', 12, 3);
|
t('8.97', '-1', '0.111482720178', 12, 3);
|
||||||
t('61766796871807246.3278075', '-1', '0.00000000000000001618993', 7, 0);
|
t('61766796871807246.3278075', '-1', '0.00000000000000001618993', 7, 0);
|
||||||
|
|
||||||
|
t('-1', '101', '-1', 100, 1);
|
||||||
|
t('-1', '9999999999999999999999999999999999999999999999999999999999999999999999999', '-1', 100, 1);
|
||||||
|
t('-1', '1e307', '1', 100, 1);
|
||||||
|
t('-1', '1e309', '1', 100, 1);
|
||||||
|
|
||||||
Decimal.toExpNeg = Decimal.toExpPos = 0;
|
Decimal.toExpNeg = Decimal.toExpPos = 0;
|
||||||
|
|
||||||
t('9.9999999999999', '2220.75', '5.623413251778e+2220', 13, 1);
|
t('9.9999999999999', '2220.75', '5.623413251778e+2220', 13, 1);
|
||||||
@ -126,4 +131,9 @@ T('pow', function () {
|
|||||||
t('908948247.896330216349750387912923575076135766138', '11.38907521122213262858256836', '1.0702278292293091784680297675223031e+102', 35, 3);
|
t('908948247.896330216349750387912923575076135766138', '11.38907521122213262858256836', '1.0702278292293091784680297675223031e+102', 35, 3);
|
||||||
t('4.485925762349120387154391E+47', '1677945.16766265206929939', '8.53959030215133943e+79957194', 18, 5);
|
t('4.485925762349120387154391E+47', '1677945.16766265206929939', '8.53959030215133943e+79957194', 18, 5);
|
||||||
t('2.8448989811706207675566E+89', '2.368592228588521845032068137267440272102614', '7.58940197453762187722508511706932e+211', 33, 5);
|
t('2.8448989811706207675566E+89', '2.368592228588521845032068137267440272102614', '7.58940197453762187722508511706932e+211', 33, 5);
|
||||||
|
|
||||||
|
t('0.9999999999999999', '-1e+30', '1.530863912e+43429448190325', 10, 1);
|
||||||
|
t('0.9999999999999999999999999999999999999999999999999', '-1e+32', '1.00000000000000001000000000000000005e+0', 36, 1);
|
||||||
|
t('0.9999999999999999', '-1e+50', 'Infinity', 40, 1);
|
||||||
|
t('0.9999999999999999999999999999999899999999999999994403269002375809806554775739676251993670310626872684', '-1.49181945463118148622657269735650603014891811120124843379694396257337810020127409048127397077199569e+271', 'Infinity', 100, 1);
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user