From 4a99e0305534d2c4e497ea170628b3bc70401bb3 Mon Sep 17 00:00:00 2001 From: josdejong Date: Sat, 23 Nov 2013 10:55:39 +0100 Subject: [PATCH] All arithmetic functions not supporting BigNumbers downgrade BigNumbers to Numbers --- HISTORY.md | 5 +++-- lib/function/arithmetic/gcd.js | 26 +++++++++++++++++++++++-- lib/function/arithmetic/lcm.js | 26 +++++++++++++++++++++++-- lib/function/arithmetic/log.js | 8 +++++++- lib/function/arithmetic/log10.js | 8 +++++++- lib/function/arithmetic/xgcd.js | 27 ++++++++++++++++++++++++-- test/function/arithmetic/gcd.test.js | 10 ++++++++++ test/function/arithmetic/lcm.test.js | 10 ++++++++++ test/function/arithmetic/log.test.js | 6 ++++++ test/function/arithmetic/log10.test.js | 6 ++++++ test/function/arithmetic/xgcd.test.js | 10 ++++++++++ 11 files changed, 132 insertions(+), 10 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 0a3f694d0..dcfc5799d 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -4,9 +4,10 @@ https://github.com/josdejong/mathjs ## not yet released, version 0.16.0 -- Implemented BigNumber support for arbitrary precision calculations, - added settings `number.defaultType` and `number.precision` to configure +- Implemented BigNumber support for arbitrary precision calculations. + Added settings `number.defaultType` and `number.precision` to configure big numbers. +- Documentation is extended. - Removed utility functions `isScalar`, `toScalar`, `isVector`, `toVector` from `Matrix` and `Range`. Use `math.squeeze` and `math.size` instead. - Implemented functions `get` and `set` on `Matrix`, for easier and faster diff --git a/lib/function/arithmetic/gcd.js b/lib/function/arithmetic/gcd.js index 1f5ea2b4c..dc356a14c 100644 --- a/lib/function/arithmetic/gcd.js +++ b/lib/function/arithmetic/gcd.js @@ -1,9 +1,11 @@ module.exports = function (math) { var util = require('../../util/index'), + BigNumber = require('bignumber.js'), collection = require('../../type/collection'), isNumber = util.number.isNumber, + toNumber = util.number.toNumber, isBoolean = util.boolean.isBoolean, isInteger = util.number.isInteger, isCollection = collection.isCollection; @@ -40,13 +42,33 @@ module.exports = function (math) { return (a < 0) ? -a : a; } - // TODO: implement BigNumber support for gcd - // evaluate gcd element wise if (isCollection(a) || isCollection(b)) { return collection.deepMap2(a, b, gcd); } + // TODO: implement BigNumber support for gcd + + // downgrade bignumbers to numbers + if (a instanceof BigNumber) { + a = toNumber(a); + if (isNumber(a)) { + return gcd(a, b); + } + else { + throw Error('Parameters in function gcd must be integer numbers.'); + } + } + if (b instanceof BigNumber) { + b = toNumber(b); + if (isNumber(b)) { + return gcd(a, b); + } + else { + throw Error('Parameters in function gcd must be integer numbers.'); + } + } + if (isBoolean(a)) { return gcd(+a, b); } diff --git a/lib/function/arithmetic/lcm.js b/lib/function/arithmetic/lcm.js index f33dff8a2..eeb18587f 100644 --- a/lib/function/arithmetic/lcm.js +++ b/lib/function/arithmetic/lcm.js @@ -1,9 +1,11 @@ module.exports = function (math) { var util = require('../../util/index'), + BigNumber = require('bignumber.js'), collection = require('../../type/collection'), isNumber = util.number.isNumber, + toNumber = util.number.toNumber, isBoolean = util.boolean.isBoolean, isInteger = util.number.isInteger, isCollection = collection.isCollection; @@ -49,8 +51,6 @@ module.exports = function (math) { return Math.abs(prod / a); } - // TODO: implement BigNumber support for lcm - // evaluate lcm element wise if (isCollection(a) || isCollection(b)) { return collection.deepMap2(a, b, lcm); @@ -63,6 +63,28 @@ module.exports = function (math) { return lcm(a, +b); } + // TODO: implement BigNumber support for lcm + + // downgrade bignumbers to numbers + if (a instanceof BigNumber) { + a = toNumber(a); + if (isNumber(a)) { + return lcm(a, b); + } + else { + throw Error('Parameters in function lcm must be integer numbers.'); + } + } + if (b instanceof BigNumber) { + b = toNumber(b); + if (isNumber(b)) { + return lcm(a, b); + } + else { + throw Error('Parameters in function lcm must be integer numbers.'); + } + } + throw new util.error.UnsupportedTypeError('lcm', a, b); } diff --git a/lib/function/arithmetic/log.js b/lib/function/arithmetic/log.js index d921e184c..69c0cf3f8 100644 --- a/lib/function/arithmetic/log.js +++ b/lib/function/arithmetic/log.js @@ -1,10 +1,12 @@ module.exports = function (math) { var util = require('../../util/index'), + BigNumber = require('bignumber.js'), Complex = require('../../type/Complex'), collection = require('../../type/collection'), isNumber = util.number.isNumber, + toNumber = util.number.toNumber, isBoolean = util.boolean.isBoolean, isComplex = Complex.isComplex, isCollection = collection.isCollection; @@ -42,7 +44,11 @@ module.exports = function (math) { ); } - // TODO: implement BigNumber support for log + if (x instanceof BigNumber) { + // TODO: implement BigNumber support for log + // downgrade to Number + return log(toNumber(x)); + } if (isCollection(x)) { return collection.deepMap(x, log); diff --git a/lib/function/arithmetic/log10.js b/lib/function/arithmetic/log10.js index 6cf170d23..0e7185f51 100644 --- a/lib/function/arithmetic/log10.js +++ b/lib/function/arithmetic/log10.js @@ -1,9 +1,11 @@ module.exports = function (math) { var util = require('../../util/index'), + BigNumber = require('bignumber.js'), Complex = require('../../type/Complex'), collection = require('../../type/collection'), + toNumber = util.number.toNumber, isNumber = util.number.isNumber, isBoolean = util.boolean.isBoolean, isComplex = Complex.isComplex, @@ -34,7 +36,11 @@ module.exports = function (math) { } } - // TODO: implement BigNumber support for log10 + if (x instanceof BigNumber) { + // TODO: implement BigNumber support for log10 + // downgrade to Number + return log10(toNumber(x)); + } if (isComplex(x)) { return new Complex ( diff --git a/lib/function/arithmetic/xgcd.js b/lib/function/arithmetic/xgcd.js index c7fdd732c..d46a71dde 100644 --- a/lib/function/arithmetic/xgcd.js +++ b/lib/function/arithmetic/xgcd.js @@ -1,6 +1,9 @@ module.exports = function (math) { var util = require('../../util/index'), + BigNumber = require('bignumber.js'), + + toNumber = util.number.toNumber, isNumber = util.number.isNumber, isBoolean = util.boolean.isBoolean, isInteger = util.number.isInteger; @@ -28,6 +31,28 @@ module.exports = function (math) { return _xgcd(a, b); } + // TODO: implement BigNumber support for xgcd + + // downgrade bignumbers to numbers + if (a instanceof BigNumber) { + a = toNumber(a); + if (isNumber(a)) { + return xgcd(a, b); + } + else { + throw Error('Parameters in function xgcd must be integer numbers.'); + } + } + if (b instanceof BigNumber) { + b = toNumber(b); + if (isNumber(b)) { + return xgcd(a, b); + } + else { + throw Error('Parameters in function xgcd must be integer numbers.'); + } + } + if (isBoolean(a)) { return xgcd(+a, b); } @@ -38,8 +63,6 @@ module.exports = function (math) { throw new util.error.UnsupportedTypeError('xgcd', a, b); } - // TODO: implement BigNumber support for xgcd - // zero or one argument throw new SyntaxError('Function xgcd expects two arguments'); }; diff --git a/test/function/arithmetic/gcd.test.js b/test/function/arithmetic/gcd.test.js index 5a0af1cb1..f3b9ea03a 100644 --- a/test/function/arithmetic/gcd.test.js +++ b/test/function/arithmetic/gcd.test.js @@ -44,6 +44,16 @@ describe('gcd', function() { assert.deepEqual(2, gcd(-2, -6)); }); + it('should calculate gcd for BigNumbers (downgrades to Number)', function() { + assert.equal(gcd(math.bignumber(12), math.bignumber(8)), 4); + assert.equal(gcd(math.bignumber(8), math.bignumber(12)), 4); + }); + + it('should calculate gcd for mixed BigNumbers to Numbers (downgrades to Number)', function() { + assert.equal(gcd(math.bignumber(12), 8), 4); + assert.equal(gcd(8, math.bignumber(12)), 4); + }); + it('should find the greatest common divisor of booleans', function() { assert.equal(gcd(true, true), 1); assert.equal(gcd(true, false), 1); diff --git a/test/function/arithmetic/lcm.test.js b/test/function/arithmetic/lcm.test.js index 19445d93e..224990da8 100644 --- a/test/function/arithmetic/lcm.test.js +++ b/test/function/arithmetic/lcm.test.js @@ -34,6 +34,16 @@ describe('lcm', function() { assert.equal(lcm(0, 0), 0); }); + it('should calculate lcm for BigNumbers (downgrades to Number)', function() { + assert.equal(lcm(math.bignumber(4), math.bignumber(6)), 12); + assert.equal(lcm(math.bignumber(4), math.bignumber(6)), 12); + }); + + it('should calculate lcm for mixed BigNumbers to Numbers (downgrades to Number)', function() { + assert.equal(lcm(math.bignumber(4), 6), 12); + assert.equal(lcm(4, math.bignumber(6)), 12); + }); + it('should find the lowest common multiple of booleans', function() { assert.equal(lcm(true, true), 1); assert.equal(lcm(true, false), 0); diff --git a/test/function/arithmetic/log.test.js b/test/function/arithmetic/log.test.js index f915e74ba..7fc8f5628 100644 --- a/test/function/arithmetic/log.test.js +++ b/test/function/arithmetic/log.test.js @@ -37,6 +37,12 @@ describe('log', function() { assert.throws(function () {log(1, 2, 3)}, SyntaxError, 'Wrong number of arguments in function log (3 provided, 1-2 expected)'); }); + it('should return the log of a bignumber', function() { + approx.deepEqual(log(math.bignumber(2)), 0.693147180559945); + approx.deepEqual(log(math.bignumber(3)), 1.098612288668110); + + }); + it('should return the log of a complex number', function() { approx.deepEqual(log(math.i), complex('1.570796326794897i')); approx.deepEqual(log(complex(0, -1)), complex('-1.570796326794897i')); diff --git a/test/function/arithmetic/log10.test.js b/test/function/arithmetic/log10.test.js index da0821256..251cd21ae 100644 --- a/test/function/arithmetic/log10.test.js +++ b/test/function/arithmetic/log10.test.js @@ -31,6 +31,12 @@ describe('log10', function() { approx.deepEqual(log10(1000), 3); }); + it('should return the log of a bignumber', function() { + approx.deepEqual(log10(math.bignumber(2)), 0.301029995663981); + approx.deepEqual(log10(math.bignumber(3)), 0.477121254719662); + + }); + it('should throw an error if used with a wrong number of arguments', function() { assert.throws(function () {log10()}, SyntaxError, 'Wrong number of arguments in function log10 (0 provided, 1 expected)'); assert.throws(function () {log10(1, 2)}, SyntaxError, 'Wrong number of arguments in function log10 (2 provided, 1 expected)'); diff --git a/test/function/arithmetic/xgcd.test.js b/test/function/arithmetic/xgcd.test.js index 60ac23e73..d5fa6add5 100644 --- a/test/function/arithmetic/xgcd.test.js +++ b/test/function/arithmetic/xgcd.test.js @@ -36,6 +36,16 @@ describe('xgcd', function() { assert.deepEqual([0, 0, 0], xgcd(0, 0)); }); + it('should calculate xgcd for BigNumbers (downgrades to Number)', function() { + assert.deepEqual(xgcd(math.bignumber(65), math.bignumber(40)), [5, -3, 5]); + assert.deepEqual(xgcd(math.bignumber(65), math.bignumber(40)), [5, -3, 5]); + }); + + it('should calculate xgcd for mixed BigNumbers to Numbers (downgrades to Number)', function() { + assert.deepEqual(xgcd(math.bignumber(65), 40), [5, -3, 5]); + assert.deepEqual(xgcd(65, math.bignumber(40)), [5, -3, 5]); + }); + it.skip ('should calculate xgcd for edge cases with negative values', function () { assert.deepEqual([1, -2, 1], xgcd(2, 5)); assert.deepEqual([1, -2, -1], xgcd(2, -5));