mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-18 14:59:29 +00:00
Merge pull request #259 from BigFav/bigSin
Initial BigNumber sin support. Tests added as well.
This commit is contained in:
commit
622d1bd083
@ -12,7 +12,9 @@ module.exports = function (math) {
|
||||
isBoolean = util['boolean'].isBoolean,
|
||||
isComplex = Complex.isComplex,
|
||||
isUnit = Unit.isUnit,
|
||||
isCollection = collection.isCollection;
|
||||
isCollection = collection.isCollection,
|
||||
|
||||
bigSin = util.bignumber.sin;
|
||||
|
||||
/**
|
||||
* Calculate the sine of a value.
|
||||
@ -37,8 +39,8 @@ module.exports = function (math) {
|
||||
*
|
||||
* cos, tan
|
||||
*
|
||||
* @param {Number | Boolean | Complex | Unit | Array | Matrix | null} x Function input
|
||||
* @return {Number | Complex | Array | Matrix} Sine of x
|
||||
* @param {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix | null} x Function input
|
||||
* @return {Number | BigNumber | Complex | Array | Matrix} Sine of x
|
||||
*/
|
||||
math.sin = function sin(x) {
|
||||
if (arguments.length != 1) {
|
||||
@ -72,9 +74,8 @@ module.exports = function (math) {
|
||||
}
|
||||
|
||||
if (x instanceof BigNumber) {
|
||||
// TODO: implement BigNumber support
|
||||
// downgrade to Number
|
||||
return sin(x.toNumber());
|
||||
// TODO: implement better BigNumber support
|
||||
return bigSin(x);
|
||||
}
|
||||
|
||||
throw new math.error.UnsupportedTypeError('sin', math['typeof'](x));
|
||||
|
||||
@ -39,33 +39,6 @@ exports.phi = function (precision) {
|
||||
return new Big(1).plus(new Big(5).sqrt()).div(2);
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the arc tangent of x
|
||||
*
|
||||
* arctan(x) = x - x^3/3 + x^5/5 - x^7/7 + x^9/9 - ...
|
||||
* = x - x^2*x^1/3 + x^2*x^3/5 - x^2*x^5/7 + x^2*x^7/9 - ...
|
||||
*
|
||||
* @param {BigNumber} x
|
||||
* @returns {BigNumber} arc tangent of x
|
||||
*/
|
||||
exports.arctan = function (x) {
|
||||
var y = x;
|
||||
var yPrev = NaN;
|
||||
var x2 = x.times(x);
|
||||
var num = x;
|
||||
var sign = -1;
|
||||
|
||||
for (var k = 3; !y.equals(yPrev); k += 2) {
|
||||
num = num.times(x2);
|
||||
|
||||
yPrev = y;
|
||||
y = (sign > 0) ? y.plus(num.div(k)) : y.minus(num.div(k));
|
||||
sign = -sign;
|
||||
}
|
||||
|
||||
return y;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate BigNumber pi.
|
||||
*
|
||||
@ -171,6 +144,33 @@ exports.and = function(x, y) {
|
||||
return bitwise(x, y, function (a, b) { return a & b });
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the arc tangent of x
|
||||
*
|
||||
* arctan(x) = x - x^3/3 + x^5/5 - x^7/7 + x^9/9 - ...
|
||||
* = x - x^2*x^1/3 + x^2*x^3/5 - x^2*x^5/7 + x^2*x^7/9 - ...
|
||||
*
|
||||
* @param {BigNumber} x
|
||||
* @returns {BigNumber} arc tangent of x
|
||||
*/
|
||||
exports.arctan = function (x) {
|
||||
var y = x;
|
||||
var yPrev = NaN;
|
||||
var x2 = x.times(x);
|
||||
var num = x;
|
||||
var sign = -1;
|
||||
|
||||
for (var k = 3; !y.equals(yPrev); k += 2) {
|
||||
num = num.times(x2);
|
||||
|
||||
yPrev = y;
|
||||
y = (sign > 0) ? y.plus(num.div(k)) : y.minus(num.div(k));
|
||||
sign = -sign;
|
||||
}
|
||||
|
||||
return y;
|
||||
};
|
||||
|
||||
/*
|
||||
* Special Cases:
|
||||
* n << -n = N
|
||||
@ -281,6 +281,60 @@ exports.or = function (x, y) {
|
||||
return bitwise(x, y, function (a, b) { return a | b });
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the sine of x using Taylor Series.
|
||||
*
|
||||
* sin(x) = x - x^3/3! + x^5/5! - x^7/7! + x^9/9! - ...
|
||||
* = x - x^2*x^1/3! + x^2*x^3/5! - x^2*x^5/7! + x^2*x^7/9! - ...
|
||||
*
|
||||
* TODO: Replace with Chebyshev approximation.
|
||||
*
|
||||
* @param {BigNumber} x
|
||||
* @returns {BigNumber} sine of x
|
||||
*/
|
||||
exports.sin = function (x) {
|
||||
var BigNumber = x['constructor'];
|
||||
var precision = BigNumber['precision'];
|
||||
if (x.isNaN() || !x.isFinite()) {
|
||||
return new BigNumber(NaN);
|
||||
}
|
||||
|
||||
// Get number's offset within the period of sin (tau)
|
||||
var pi = exports.pi(2 * precision - 5);
|
||||
var tau = pi.times(2);
|
||||
|
||||
// Catch if tau multiple using pi's precision
|
||||
if (x.div(pi.toDP(x.dp(), 1)).toNumber() % 2 == 0) {
|
||||
return new BigNumber(0);
|
||||
}
|
||||
|
||||
var y = x.mod(tau);
|
||||
// Catch if tau multiple with tau's precision
|
||||
if (y.toDP(x.dp(), 1).isZero()) {
|
||||
return new BigNumber(0);
|
||||
}
|
||||
if (y.gt(pi)) {
|
||||
y = y.minus(tau);
|
||||
}
|
||||
y['constructor']['precision'] = precision;
|
||||
|
||||
var yPrev = NaN;
|
||||
var y2 = y.times(y);
|
||||
var num = y;
|
||||
var den = BigNumber['ONE'];
|
||||
var sign = -1;
|
||||
for (var k = 1; !y.equals(yPrev); k += 2) {
|
||||
num = num.times(y2);
|
||||
den = den.times(k+1).times(k+2);
|
||||
|
||||
yPrev = y;
|
||||
y = (sign > 0) ? y.plus(num.div(den)) : y.minus(num.div(den));
|
||||
sign = -sign;
|
||||
}
|
||||
|
||||
return y.toDP(precision - 1);
|
||||
};
|
||||
|
||||
/*
|
||||
* Special Cases:
|
||||
* n >> -n = N
|
||||
|
||||
@ -20,20 +20,36 @@ describe('sin', function() {
|
||||
|
||||
it('should return the sine of a number', function() {
|
||||
approx.equal(sin(0), 0);
|
||||
approx.equal(sin(pi*1/4), 0.707106781186548);
|
||||
approx.equal(sin(pi*1/8), 0.382683432365090);
|
||||
approx.equal(sin(pi*2/4), 1);
|
||||
approx.equal(sin(pi/8), 0.382683432365090);
|
||||
approx.equal(sin(pi/4), Math.SQRT2/2);
|
||||
approx.equal(sin(pi/2), 1);
|
||||
approx.equal(sin(pi*3/4), 0.707106781186548);
|
||||
approx.equal(sin(pi*4/4), 0);
|
||||
approx.equal(sin(pi), 0);
|
||||
approx.equal(sin(pi*5/4), -0.707106781186548);
|
||||
approx.equal(sin(pi*6/4), -1);
|
||||
approx.equal(sin(pi*3/2), -1);
|
||||
approx.equal(sin(pi*7/4), -0.707106781186548);
|
||||
approx.equal(sin(pi*8/4), 0);
|
||||
approx.equal(sin(pi/4), math.sqrt(2)/2);
|
||||
approx.equal(sin(pi*2), 0);
|
||||
});
|
||||
|
||||
it('should return the sine of a bignumber (downgrades to number)', function() {
|
||||
approx.equal(sin(math.bignumber(1)), 0.841470984807897);
|
||||
it('should return the sine of a bignumber', function() {
|
||||
var bigmath = math.create({number: 'bignumber', precision: 60});
|
||||
assert.deepEqual(sin(math.bignumber(0)), math.bignumber(0));
|
||||
assert.deepEqual(sin(math.bignumber(1)), math.bignumber('0.84147098480789650665250232163029899962256306079837106567275171'));
|
||||
|
||||
bigmath.config({precision: 15});
|
||||
|
||||
var bigPi = bigmath.pi;
|
||||
var result = bigmath.SQRT2.div(2).toString();
|
||||
assert.deepEqual(bigmath.sin(bigPi.div(4)).toString(), result);
|
||||
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(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');
|
||||
});
|
||||
|
||||
it('should return the sine of a complex number', function() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user