mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-18 14:59:29 +00:00
commit
bc2c81f9cd
@ -34,7 +34,7 @@ module.exports = function (math) {
|
||||
* @return {Number | BigNumber | Array | Matrix} The factorial of `n`
|
||||
*/
|
||||
math.factorial = function factorial (n) {
|
||||
var value, res;
|
||||
var value, res, preciseFacs;
|
||||
|
||||
if (arguments.length != 1) {
|
||||
throw new math.error.ArgumentsError('factorial', arguments.length, 1);
|
||||
@ -53,23 +53,33 @@ module.exports = function (math) {
|
||||
return new BigNumber(n);
|
||||
}
|
||||
|
||||
n = n.toNumber();
|
||||
if (n < fac.length) {
|
||||
return (n < 21)
|
||||
? new BigNumber(fac[n])
|
||||
: fac[n];
|
||||
n = n.toNumber(); // Should definitely be below Number.MAX_VALUE
|
||||
if (n < smallBigFacs.length) {
|
||||
return BigNumber.convert(smallBigFacs[n]).toSD(math.precision);
|
||||
}
|
||||
|
||||
// adjust n do align with the precision specific tables
|
||||
n -= smallBigFacs.length;
|
||||
if (preciseFacs = bigBigFacs[math.precision]) {
|
||||
if (preciseFacs[n]) {
|
||||
return preciseFacs[n];
|
||||
}
|
||||
res = preciseFacs[preciseFacs.length-1];
|
||||
} else {
|
||||
preciseFacs = [];
|
||||
res = BigNumber.convert(smallBigFacs[smallBigFacs.length-1])
|
||||
.toSD(math.precision);
|
||||
}
|
||||
|
||||
var one = new BigNumber(1);
|
||||
value = new BigNumber(fac.length);
|
||||
res = fac[fac.length - 1];
|
||||
for (var i = fac.length; i < n; ++i) {
|
||||
value = new BigNumber(preciseFacs.length + smallBigFacs.length);
|
||||
for (var i = preciseFacs.length; i < n; ++i) {
|
||||
res = res.times(value);
|
||||
value = value.plus(one);
|
||||
fac[i] = res;
|
||||
preciseFacs[i] = res;
|
||||
}
|
||||
|
||||
return fac[n] = res.times(value);
|
||||
return preciseFacs[n] = res.times(value);
|
||||
}
|
||||
|
||||
if (isBoolean(n) || n === null) {
|
||||
@ -92,8 +102,11 @@ module.exports = function (math) {
|
||||
return n.isInteger() && (!n.isNegative() || n.isZero());
|
||||
};
|
||||
|
||||
// 0-21! values
|
||||
var fac = [
|
||||
// 21! >= values for each precision
|
||||
var bigBigFacs = [];
|
||||
|
||||
// 0-20! values
|
||||
var smallBigFacs = [
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
@ -114,7 +127,6 @@ module.exports = function (math) {
|
||||
355687428096000,
|
||||
6402373705728000,
|
||||
121645100408832000,
|
||||
2432902008176640000,
|
||||
new BigNumber('51090942171709440000')
|
||||
2432902008176640000
|
||||
]
|
||||
};
|
||||
|
||||
@ -104,7 +104,7 @@ exports.and = function(x, y) {
|
||||
throw new Error('Parameters in function bitAnd must be integer numbers');
|
||||
}
|
||||
|
||||
var BigNumber = x['constructor'];
|
||||
var BigNumber = x.constructor;
|
||||
if (x.isNaN() || y.isNaN()) {
|
||||
return new BigNumber(NaN);
|
||||
}
|
||||
@ -193,7 +193,7 @@ exports.leftShift = function (x, y) {
|
||||
throw new Error('Parameters in function leftShift must be integer numbers');
|
||||
}
|
||||
|
||||
var BigNumber = x['constructor'];
|
||||
var BigNumber = x.constructor;
|
||||
if (x.isNaN() || y.isNaN() || (y.isNegative() && !y.isZero())) {
|
||||
return new BigNumber(NaN);
|
||||
}
|
||||
@ -221,14 +221,14 @@ exports.not = function (x) {
|
||||
throw new Error('Parameter in function bitNot must be integer numbers');
|
||||
}
|
||||
|
||||
var BigNumber = x['constructor'];
|
||||
var prevPrec = BigNumber['precision'];
|
||||
BigNumber['precision'] = 1E9;
|
||||
var BigNumber = x.constructor;
|
||||
var prevPrec = BigNumber.precision;
|
||||
BigNumber.config({precision: 1E9});
|
||||
|
||||
var x = x.plus(BigNumber['ONE']);
|
||||
x['s'] = -x['s'] || null;
|
||||
var x = x.plus(BigNumber.ONE);
|
||||
x.s = -x.s || null;
|
||||
|
||||
BigNumber['precision'] = prevPrec;
|
||||
BigNumber.config({precision: prevPrec});
|
||||
return x;
|
||||
};
|
||||
|
||||
@ -256,7 +256,7 @@ exports.or = function (x, y) {
|
||||
throw new Error('Parameters in function bitOr must be integer numbers');
|
||||
}
|
||||
|
||||
var BigNumber = x['constructor'];
|
||||
var BigNumber = x.constructor;
|
||||
if (x.isNaN() || y.isNaN()) {
|
||||
return new BigNumber(NaN);
|
||||
}
|
||||
@ -294,21 +294,22 @@ exports.or = function (x, y) {
|
||||
* @returns {BigNumber} sine of x
|
||||
*/
|
||||
exports.sin = function (x) {
|
||||
var BigNumber = x['constructor'];
|
||||
var precision = BigNumber['precision'];
|
||||
var BigNumber = x.constructor;
|
||||
var precision = BigNumber.precision;
|
||||
if (x.isNaN() || !x.isFinite()) {
|
||||
return new BigNumber(NaN);
|
||||
}
|
||||
|
||||
// sin(-x) == -sin(x)
|
||||
var isNeg;
|
||||
if (isNeg = x.isNegative()) {
|
||||
x['s'] = -x['s'];
|
||||
var isNeg = x.isNegative();
|
||||
if (isNeg) {
|
||||
x.s = -x.s;
|
||||
}
|
||||
|
||||
// Get offset within the period of sin (-pi, pi] w/ gaurd digits
|
||||
var pi = exports.pi(precision + ~~(3*Math.log(precision)) + 1);
|
||||
var tau = pi.times(2);
|
||||
var prec_plus_guard_digits = precision + (3*Math.log(precision) | 0) + 1;
|
||||
var pi = exports.pi(prec_plus_guard_digits + 2);
|
||||
var tau = exports.tau(prec_plus_guard_digits);
|
||||
|
||||
// Catch if tau multiple using pi's precision
|
||||
if (x.div(pi.toDP(x.dp(), 1)).toNumber() % 2 == 0) {
|
||||
@ -327,7 +328,7 @@ exports.sin = function (x) {
|
||||
var yPrev = NaN;
|
||||
var y2 = y.times(y);
|
||||
var num = y;
|
||||
var den = BigNumber['ONE'];
|
||||
var den = BigNumber.ONE;
|
||||
var add = true;
|
||||
for (var k = 1; !y.equals(yPrev); k += 2) {
|
||||
num = num.times(y2);
|
||||
@ -339,9 +340,9 @@ exports.sin = function (x) {
|
||||
}
|
||||
|
||||
if (isNeg) {
|
||||
y['s'] = -y['s'];
|
||||
y.s = -y.s;
|
||||
}
|
||||
y['constructor']['precision'] = precision;
|
||||
y.constructor.config({precision: precision});
|
||||
return y.toDP(precision - 1);
|
||||
};
|
||||
|
||||
@ -369,7 +370,7 @@ exports.rightShift = function (x, y) {
|
||||
throw new Error('Parameters in function rightArithShift must be integer numbers');
|
||||
}
|
||||
|
||||
var BigNumber = x['constructor'];
|
||||
var BigNumber = x.constructor;
|
||||
if (x.isNaN() || y.isNaN() || (y.isNegative() && !y.isZero())) {
|
||||
return new BigNumber(NaN);
|
||||
}
|
||||
@ -415,7 +416,7 @@ exports.xor = function (x, y) {
|
||||
throw new Error('Parameters in function bitXor must be integer numbers');
|
||||
}
|
||||
|
||||
var BigNumber = x['constructor'];
|
||||
var BigNumber = x.constructor;
|
||||
if (x.isNaN() || y.isNaN()) {
|
||||
return new BigNumber(NaN);
|
||||
}
|
||||
@ -639,11 +640,11 @@ exports.toFixed = function(value, precision) {
|
||||
|
||||
|
||||
function bitwise(x, y, func) {
|
||||
var BigNumber = x['constructor'];
|
||||
var BigNumber = x.constructor;
|
||||
|
||||
var xBits, yBits;
|
||||
var xSign = +(x['s'] < 0);
|
||||
var ySign = +(y['s'] < 0);
|
||||
var xSign = +(x.s < 0);
|
||||
var ySign = +(y.s < 0);
|
||||
if (xSign) {
|
||||
xBits = decToBinary(coefficientToString(exports.not(x)));
|
||||
for (var i = 0; i < xBits.length; ++i) {
|
||||
@ -676,11 +677,11 @@ function bitwise(x, y, func) {
|
||||
var longLen = maxBits.length;
|
||||
var expFuncVal = func(xSign, ySign) ^ 1;
|
||||
var outVal = new BigNumber(expFuncVal ^ 1);
|
||||
var twoPower = BigNumber['ONE'];
|
||||
var twoPower = BigNumber.ONE;
|
||||
var two = new BigNumber(2);
|
||||
|
||||
var prevPrec = BigNumber['precision'];
|
||||
BigNumber['precision'] = 1E9;
|
||||
var prevPrec = BigNumber.precision;
|
||||
BigNumber.config({precision: 1E9});
|
||||
|
||||
while (shortLen > 0) {
|
||||
if (func(minBits[--shortLen], maxBits[--longLen]) == expFuncVal) {
|
||||
@ -695,10 +696,10 @@ function bitwise(x, y, func) {
|
||||
twoPower = twoPower.times(two);
|
||||
}
|
||||
|
||||
BigNumber['precision'] = prevPrec;
|
||||
BigNumber.config({precision: prevPrec});
|
||||
|
||||
if (expFuncVal == 0) {
|
||||
outVal['s'] = -outVal['s'];
|
||||
outVal.s = -outVal.s;
|
||||
}
|
||||
return outVal;
|
||||
}
|
||||
@ -708,7 +709,7 @@ function bitwise(x, y, func) {
|
||||
|
||||
|
||||
function coefficientToString(x) {
|
||||
var a = x['c'];
|
||||
var a = x.c;
|
||||
var r = a[0] + '';
|
||||
|
||||
for (var i = 1; i < a.length; ++i) {
|
||||
@ -723,7 +724,7 @@ function coefficientToString(x) {
|
||||
var j;
|
||||
for (j = r.length - 1; r.charAt(j) == '0'; --j);
|
||||
|
||||
var xe = x['e'];
|
||||
var xe = x.e;
|
||||
var str = r.slice(0, j + 1 || 1);
|
||||
var strL = str.length;
|
||||
if (xe > 0) {
|
||||
|
||||
@ -42,9 +42,9 @@ describe('leftShift', function () {
|
||||
assert.deepEqual(leftShift(bignumber(2), bignumber(3)), bignumber(16));
|
||||
assert.deepEqual(leftShift(bignumber(500), bignumber(100)), bignumber('633825300114114700748351602688000'));
|
||||
assert.deepEqual(leftShift(bignumber(-1), bignumber(2)), bignumber(-4));
|
||||
assert.deepEqual(leftShift(bignumber(0), bignumber(-2)).toString(), 'NaN');
|
||||
assert.equal(leftShift(bignumber(0), bignumber(-2)).isNaN(), true);
|
||||
assert.deepEqual(leftShift(bignumber(Infinity), bignumber(2)), bignumber(Infinity));
|
||||
assert.deepEqual(leftShift(bignumber(Infinity), bignumber(Infinity)).toString(), 'NaN');
|
||||
assert.equal(leftShift(bignumber(Infinity), bignumber(Infinity)).isNaN(), true);
|
||||
});
|
||||
|
||||
it('should left shift mixed numbers and bignumbers', function () {
|
||||
@ -53,8 +53,8 @@ describe('leftShift', function () {
|
||||
assert.deepEqual(leftShift(2, bignumber(3)), bignumber(16));
|
||||
assert.deepEqual(leftShift(-1, bignumber(2)), bignumber(-4));
|
||||
assert.deepEqual(leftShift(bignumber(-1), 2), bignumber(-4));
|
||||
assert.deepEqual(leftShift(bignumber(0), -2).toString(), 'NaN');
|
||||
assert.deepEqual(leftShift(bignumber(Infinity), Infinity).toString(), 'NaN');
|
||||
assert.equal(leftShift(bignumber(0), -2).isNaN(), true);
|
||||
assert.equal(leftShift(bignumber(Infinity), Infinity).isNaN(), true);
|
||||
});
|
||||
|
||||
it('should left shift mixed booleans and bignumbers', function () {
|
||||
|
||||
@ -43,21 +43,21 @@ describe('rightArithShift', function () {
|
||||
assert.deepEqual(rightArithShift(bignumber(17), bignumber(3)), bignumber(2));
|
||||
assert.deepEqual(rightArithShift(bignumber('633825300114114700748351602688000'), bignumber(100)), bignumber(500));
|
||||
assert.deepEqual(rightArithShift(bignumber(-17), bignumber(3)), bignumber(-3));
|
||||
assert.deepEqual(rightArithShift(bignumber(-17), bignumber(-3)).toString(), 'NaN');
|
||||
assert.deepEqual(rightArithShift(bignumber(Infinity), bignumber(Infinity)).toString(), 'NaN');
|
||||
assert.equal(rightArithShift(bignumber(-17), bignumber(-3)).isNaN(), true);
|
||||
assert.equal(rightArithShift(bignumber(Infinity), bignumber(Infinity)).isNaN(), true);
|
||||
assert.deepEqual(rightArithShift(bignumber(-Infinity), bignumber(Infinity)), bignumber(-1));
|
||||
});
|
||||
|
||||
it('should right arithmetically shift mixed numbers and bignumbers', function () {
|
||||
assert.deepEqual(rightArithShift(bignumber(17), 3), bignumber(2));
|
||||
assert.deepEqual(rightArithShift(bignumber('-633825300114114700748351602688000'), 100), bignumber(-500));
|
||||
assert.deepEqual(rightArithShift(bignumber(-17), -3).toString(), 'NaN');
|
||||
assert.equal(rightArithShift(bignumber(-17), -3).isNaN(), true);
|
||||
assert.deepEqual(rightArithShift(17, bignumber(3)), bignumber(2));
|
||||
assert.deepEqual(rightArithShift(-17, bignumber(3)), bignumber(-3));
|
||||
assert.deepEqual(rightArithShift(-3, bignumber(-17)).toString(), 'NaN');
|
||||
assert.equal(rightArithShift(-3, bignumber(-17)).isNaN(), true);
|
||||
assert.deepEqual(rightArithShift(bignumber(-Infinity), Infinity), bignumber(-1));
|
||||
assert.deepEqual(rightArithShift(bignumber(Infinity), Infinity).toString(), 'NaN');
|
||||
assert.deepEqual(rightArithShift(Infinity, bignumber(Infinity)).toString(), 'NaN');
|
||||
assert.equal(rightArithShift(bignumber(Infinity), Infinity).isNaN(), true);
|
||||
assert.equal(rightArithShift(Infinity, bignumber(Infinity)).isNaN(), true);
|
||||
});
|
||||
|
||||
it('should right arithmetically shift mixed booleans and bignumbers', function () {
|
||||
|
||||
@ -16,17 +16,27 @@ describe('factorial', function() {
|
||||
});
|
||||
|
||||
it('should calculate the factorial of a bignumber', function() {
|
||||
assert.deepEqual(factorial(math.bignumber(0)), math.bignumber(1));
|
||||
assert.deepEqual(factorial(math.bignumber(1)), math.bignumber(1));
|
||||
assert.deepEqual(factorial(math.bignumber(2)), math.bignumber(2));
|
||||
assert.deepEqual(factorial(math.bignumber(3)), math.bignumber(6));
|
||||
assert.deepEqual(factorial(math.bignumber(4)), math.bignumber(24));
|
||||
assert.deepEqual(factorial(math.bignumber(5)), math.bignumber(120));
|
||||
assert.deepEqual(factorial(math.bignumber(20)), math.bignumber('2432902008176640000'));
|
||||
assert.deepEqual(factorial(math.bignumber(21)), math.bignumber('51090942171709440000'));
|
||||
assert.deepEqual(factorial(math.bignumber(25)), math.bignumber('1.5511210043330985984e+25'));
|
||||
assert.deepEqual(factorial(math.bignumber(24)), math.bignumber('6.2044840173323943936e+23'));
|
||||
assert.deepEqual(factorial(math.bignumber(22)), math.bignumber('1124000727777607680000'));
|
||||
var bigmath = math.create({precision: 5});
|
||||
var bigfactorial = bigmath.factorial;
|
||||
var bignumber = bigmath.bignumber;
|
||||
|
||||
assert.deepEqual(bigfactorial(bignumber(11)), bignumber(39917000));
|
||||
assert.deepEqual(bigfactorial(bignumber(22)), bignumber(1.124e+21));
|
||||
|
||||
bigmath.config({precision: 20});
|
||||
assert.deepEqual(bigfactorial(bignumber(5)), bignumber(120));
|
||||
assert.deepEqual(bigfactorial(bignumber(19)), bignumber(121645100408832000));
|
||||
assert.deepEqual(bigfactorial(bignumber(20)), bignumber(2432902008176640000));
|
||||
assert.deepEqual(bigfactorial(bignumber(21)), bignumber('51090942171709440000'));
|
||||
assert.deepEqual(bigfactorial(bignumber(25)), bignumber('1.5511210043330985984e+25'));
|
||||
assert.deepEqual(bigfactorial(bignumber(24)), bignumber('6.2044840173323943936e+23'));
|
||||
assert.deepEqual(bigfactorial(bignumber(22)), bignumber('1124000727777607680000'));
|
||||
|
||||
bigmath.config({precision: 5});
|
||||
assert.deepEqual(bigfactorial(bignumber(11)), bignumber(39917000));
|
||||
assert.deepEqual(bigfactorial(bignumber(22)), bignumber(1.124e+21));
|
||||
assert.deepEqual(bigfactorial(bignumber(24)), bignumber(6.2045e+23));
|
||||
assert.deepEqual(bigfactorial(bignumber(21)), bignumber(5.1091e+19));
|
||||
});
|
||||
|
||||
it('should calculate the factorial of a boolean', function() {
|
||||
|
||||
@ -36,28 +36,32 @@ describe('sin', function() {
|
||||
assert.deepEqual(bigmath.sin(bigmath.bignumber(0)), bigmath.bignumber(0));
|
||||
|
||||
// 103.64 % tau = 3.109... <- pretty close to the pi boundary
|
||||
assert.deepEqual(bigmath.sin(bigmath.bignumber(103.64)).toString(), '0.032551816956616158442731315994267213051204459121689332893471030' +
|
||||
'714804383298805501395839512341888732261080924779366105855493575' +
|
||||
'835362891900420559398509489530577719840860106717522689249606121' +
|
||||
'2602629134186583352145117086874446046421403346033616');
|
||||
assert.deepEqual(bigmath.sin(bigmath.bignumber(-103.64)).toString(), '-0.0325518169566161584427313159942672130512044591216893328934710' +
|
||||
'3071480438329880550139583951234188873226108092477936610585549' +
|
||||
'3575835362891900420559398509489530577719840860106717522689249' +
|
||||
'6061212602629134186583352145117086874446046421403346033616');
|
||||
var result_val = bigmath.sin(bigmath.bignumber(103.64));
|
||||
assert.equal(result_val.constructor.precision, 242);
|
||||
assert.deepEqual(result_val.toString(), '0.032551816956616158442731315994267213051204459121689332893471030' +
|
||||
'714804383298805501395839512341888732261080924779366105855493575' +
|
||||
'835362891900420559398509489530577719840860106717522689249606121' +
|
||||
'2602629134186583352145117086874446046421403346033616');
|
||||
result_val = bigmath.sin(bigmath.bignumber(-103.64));
|
||||
assert.equal(result_val.constructor.precision, 242);
|
||||
assert.deepEqual(result_val.toString(), '-0.0325518169566161584427313159942672130512044591216893328934710' +
|
||||
'3071480438329880550139583951234188873226108092477936610585549' +
|
||||
'3575835362891900420559398509489530577719840860106717522689249' +
|
||||
'6061212602629134186583352145117086874446046421403346033616');
|
||||
bigmath.config({precision: 15});
|
||||
|
||||
var bigPi = bigmath.pi;
|
||||
var result = bigmath.SQRT2.div(2).toString();
|
||||
assert.deepEqual(bigmath.sin(bigPi.div(4)).toString(), result);
|
||||
result_val = bigmath.SQRT2.div(2).toString();
|
||||
assert.deepEqual(bigmath.sin(bigPi.div(4)).toString(), result_val);
|
||||
assert.deepEqual(bigmath.sin(bigPi.div(2)).toString(), '1');
|
||||
assert.deepEqual(bigmath.sin(bigPi.times(3).div(4)).toString(), result);
|
||||
assert.deepEqual(bigmath.sin(bigPi).toString(), '0');
|
||||
assert.deepEqual(bigmath.sin(bigPi.times(5).div(4)).toString(), '-'+result);
|
||||
assert.deepEqual(bigmath.sin(bigPi.times(3).div(4)).toString(), result_val);
|
||||
assert.equal(bigmath.sin(bigPi).isZero(), true);
|
||||
assert.deepEqual(bigmath.sin(bigPi.times(5).div(4)).toString(), '-'+result_val);
|
||||
assert.deepEqual(bigmath.sin(bigPi.times(3).div(2)).toString(), '-1');
|
||||
assert.deepEqual(bigmath.sin(bigPi.times(7).div(4)).toString(), '-'+result);
|
||||
assert.deepEqual(bigmath.sin(bigPi.times(2)).toString(), '0');
|
||||
assert.deepEqual(bigmath.sin(bigmath.tau).toString(), '0');
|
||||
assert.deepEqual(bigmath.sin(bigmath.tau.times(2)).toString(), '0');
|
||||
assert.deepEqual(bigmath.sin(bigPi.times(7).div(4)).toString(), '-'+result_val);
|
||||
assert.equal(bigmath.sin(bigPi.times(2)).isZero(), true);
|
||||
assert.equal(bigmath.sin(bigmath.tau).isZero(), true);
|
||||
assert.equal(bigmath.sin(bigmath.tau.times(2)).isZero(), true);
|
||||
});
|
||||
|
||||
it('should return the sine of a complex number', function() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user