From a37bac1d4be27c280294ebc8b6d578cff8287930 Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Mon, 8 Dec 2014 10:14:58 -0800 Subject: [PATCH 01/19] Removed parseInt as it is doesn't work for strings with 'e' in them; using unary plus to convert strings to non-bignumber ints. Also uncommented out the BigNumber sections in preparation for their inclusion. --- lib/function/bitwise/bitAnd.js | 16 +++++----------- lib/function/bitwise/bitNot.js | 8 ++++---- lib/function/bitwise/bitOr.js | 16 +++++----------- lib/function/bitwise/bitXor.js | 16 +++++----------- lib/function/bitwise/leftShift.js | 13 +++++-------- lib/function/bitwise/rightArithShift.js | 13 +++++-------- lib/function/bitwise/rightLogShift.js | 4 ++-- 7 files changed, 31 insertions(+), 55 deletions(-) diff --git a/lib/function/bitwise/bitAnd.js b/lib/function/bitwise/bitAnd.js index 750be4c56..d7e7d0055 100644 --- a/lib/function/bitwise/bitAnd.js +++ b/lib/function/bitwise/bitAnd.js @@ -3,7 +3,7 @@ module.exports = function (math, config) { var util = require('../../util/index'), - //BigNumber = math.type.BigNumber, + BigNumber = math.type.BigNumber, Matrix = require('../../type/Matrix'), Unit = require('../../type/Unit'), collection = require('../../type/collection'), @@ -44,14 +44,11 @@ module.exports = function (math, config) { return x & y; } - /*if (x instanceof BigNumber) { + if (x instanceof BigNumber) { // try to convert to big number if (isNumber(y)) { y = BigNumber.convert(y); } - else if (isBoolean(y) || y === null) { - y = new BigNumber(y ? 1 : 0); - } if (y instanceof BigNumber) { return x.and(y); @@ -65,9 +62,6 @@ module.exports = function (math, config) { if (isNumber(x)) { x = BigNumber.convert(x); } - else if (isBoolean(x) || x === null) { - x = new BigNumber(x ? 1 : 0); - } if (x instanceof BigNumber) { return x.and(y) @@ -75,7 +69,7 @@ module.exports = function (math, config) { // downgrade to Number return bitAnd(x, y.toNumber()); - }*/ + } if (isCollection(x) || isCollection(y)) { return collection.deepMap2(x, y, bitAnd); @@ -84,12 +78,12 @@ module.exports = function (math, config) { if (isString(x)) { return bitAnd((config.number == 'bignumber') ? new BigNumber(x) - : parseInt(x), y); + : +x, y); } if (isString(y)) { return bitAnd(x, (config.number == 'bignumber') ? new BigNumber(y) - : parseInt(y)); + : +y); } if (isBoolean(x) || x === null) { diff --git a/lib/function/bitwise/bitNot.js b/lib/function/bitwise/bitNot.js index 904fb4a23..02773e7e0 100644 --- a/lib/function/bitwise/bitNot.js +++ b/lib/function/bitwise/bitNot.js @@ -3,7 +3,7 @@ module.exports = function (math, config) { var util = require('../../util/index'), - //BigNumber = math.type.BigNumber, + BigNumber = math.type.BigNumber, Matrix = require('../../type/Matrix'), Unit = require('../../type/Unit'), collection = require('../../type/collection'), @@ -44,9 +44,9 @@ module.exports = function (math, config) { return ~x; } - /*if (x instanceof BigNumber) { + if (x instanceof BigNumber) { return x.not(); - }*/ + } if (isCollection(x)) { return collection.deepMap(x, bitNot); @@ -55,7 +55,7 @@ module.exports = function (math, config) { if (isString(x)) { return bitNot((config.number == 'bignumber') ? new BigNumber(x) - : parseInt(x)); + : +x); } if (isBoolean(x) || x === null) { diff --git a/lib/function/bitwise/bitOr.js b/lib/function/bitwise/bitOr.js index 896c8ae30..52f2351b0 100644 --- a/lib/function/bitwise/bitOr.js +++ b/lib/function/bitwise/bitOr.js @@ -3,7 +3,7 @@ module.exports = function (math, config) { var util = require('../../util/index'), - //BigNumber = math.type.BigNumber, + BigNumber = math.type.BigNumber, Matrix = require('../../type/Matrix'), Unit = require('../../type/Unit'), collection = require('../../type/collection'), @@ -45,14 +45,11 @@ module.exports = function (math, config) { return x | y; } - /*if (x instanceof BigNumber) { + if (x instanceof BigNumber) { // try to convert to big number if (isNumber(y)) { y = BigNumber.convert(y); } - else if (isBoolean(y) || y === null) { - y = new BigNumber(y ? 1 : 0); - } if (y instanceof BigNumber) { return x.or(y); @@ -66,9 +63,6 @@ module.exports = function (math, config) { if (isNumber(x)) { x = BigNumber.convert(x); } - else if (isBoolean(x) || x === null) { - x = new BigNumber(x ? 1 : 0); - } if (x instanceof BigNumber) { return x.or(y) @@ -76,7 +70,7 @@ module.exports = function (math, config) { // downgrade to Number return bitOr(x, y.toNumber()); - }*/ + } if (isCollection(x) || isCollection(y)) { return collection.deepMap2(x, y, bitOr); @@ -85,12 +79,12 @@ module.exports = function (math, config) { if (isString(x)) { return bitOr((config.number == 'bignumber') ? new BigNumber(x) - : parseInt(x), y); + : +x, y); } if (isString(y)) { return bitOr(x, (config.number == 'bignumber') ? new BigNumber(y) - : parseInt(y)); + : +y); } if (isBoolean(x) || x === null) { diff --git a/lib/function/bitwise/bitXor.js b/lib/function/bitwise/bitXor.js index e961cc4f3..c0101d6d6 100644 --- a/lib/function/bitwise/bitXor.js +++ b/lib/function/bitwise/bitXor.js @@ -3,7 +3,7 @@ module.exports = function (math, config) { var util = require('../../util/index'), - //BigNumber = math.type.BigNumber, + BigNumber = math.type.BigNumber, Matrix = require('../../type/Matrix'), Unit = require('../../type/Unit'), collection = require('../../type/collection'), @@ -45,14 +45,11 @@ module.exports = function (math, config) { return x ^ y; } - /*if (x instanceof BigNumber) { + if (x instanceof BigNumber) { // try to convert to big number if (isNumber(y)) { y = BigNumber.convert(y); } - else if (isBoolean(y) || y === null) { - y = new BigNumber(y ? 1 : 0); - } if (y instanceof BigNumber) { return x.xor(y); @@ -66,9 +63,6 @@ module.exports = function (math, config) { if (isNumber(x)) { x = BigNumber.convert(x); } - else if (isBoolean(x) || x === null) { - x = new BigNumber(x ? 1 : 0); - } if (x instanceof BigNumber) { return x.xor(y) @@ -76,7 +70,7 @@ module.exports = function (math, config) { // downgrade to Number return bitXor(x, y.toNumber()); - }*/ + } if (isCollection(x) || isCollection(y)) { return collection.deepMap2(x, y, bitXor); @@ -85,12 +79,12 @@ module.exports = function (math, config) { if (isString(x)) { return bitXor((config.number == 'bignumber') ? new BigNumber(x) - : parseInt(x), y); + : +x, y); } if (isString(y)) { return bitXor(x, (config.number == 'bignumber') ? new BigNumber(y) - : parseInt(y)); + : +y); } if (isBoolean(x) || x === null) { diff --git a/lib/function/bitwise/leftShift.js b/lib/function/bitwise/leftShift.js index 9c04c647a..583e27613 100644 --- a/lib/function/bitwise/leftShift.js +++ b/lib/function/bitwise/leftShift.js @@ -3,7 +3,7 @@ module.exports = function (math, config) { var util = require('../../util/index'), - //BigNumber = math.type.BigNumber, + BigNumber = math.type.BigNumber, Matrix = require('../../type/Matrix'), Unit = require('../../type/Unit'), collection = require('../../type/collection'), @@ -45,14 +45,11 @@ module.exports = function (math, config) { return x << y; } - /*if (x instanceof BigNumber) { + if (x instanceof BigNumber) { // try to convert to big number if (isNumber(y)) { y = BigNumber.convert(y); } - else if (y === null) { - y = new BigNumber(0); - } if (y instanceof BigNumber) { return x.leftShift(y); @@ -73,7 +70,7 @@ module.exports = function (math, config) { // downgrade to Number return leftShift(x, y.toNumber()); - }*/ + } if (isCollection(x) && isNumber(y)) { return collection.deepMap2(x, y, leftShift); @@ -82,12 +79,12 @@ module.exports = function (math, config) { if (isString(x)) { return leftShift((config.number == 'bignumber') ? new BigNumber(x) - : parseInt(x), y); + : +x, y); } if (isString(y)) { return leftShift(x, (config.number == 'bignumber') ? new BigNumber(y) - : parseInt(y)); + : +y); } if (isBoolean(x) || x === null) { diff --git a/lib/function/bitwise/rightArithShift.js b/lib/function/bitwise/rightArithShift.js index 7c598d2f0..bb5c8a337 100644 --- a/lib/function/bitwise/rightArithShift.js +++ b/lib/function/bitwise/rightArithShift.js @@ -3,7 +3,7 @@ module.exports = function (math, config) { var util = require('../../util/index'), - //BigNumber = math.type.BigNumber, + BigNumber = math.type.BigNumber, Matrix = require('../../type/Matrix'), Unit = require('../../type/Unit'), collection = require('../../type/collection'), @@ -45,14 +45,11 @@ module.exports = function (math, config) { return x >> y; } - /*if (x instanceof BigNumber) { + if (x instanceof BigNumber) { // try to convert to big number if (isNumber(y)) { y = BigNumber.convert(y); } - else if (y === null) { - y = new BigNumber(0); - } if (y instanceof BigNumber) { return x.rightShift(y); @@ -73,7 +70,7 @@ module.exports = function (math, config) { // downgrade to Number return rightArithShift(x, y.toNumber()); - }*/ + } if (isCollection(x) && isNumber(y)) { return collection.deepMap2(x, y, rightArithShift); @@ -82,12 +79,12 @@ module.exports = function (math, config) { if (isString(x)) { return rightArithShift((config.number == 'bignumber') ? new BigNumber(x) - : parseInt(x), y); + : +x, y); } if (isString(y)) { return rightArithShift(x, (config.number == 'bignumber') ? new BigNumber(y) - : parseInt(y)); + : +y); } if (isBoolean(x) || x === null) { diff --git a/lib/function/bitwise/rightLogShift.js b/lib/function/bitwise/rightLogShift.js index d21a47871..b87e5da2d 100644 --- a/lib/function/bitwise/rightLogShift.js +++ b/lib/function/bitwise/rightLogShift.js @@ -51,12 +51,12 @@ module.exports = function (math, config) { if (isString(x)) { return rightLogShift((config.number == 'bignumber') ? new BigNumber(x) - : parseInt(x), y); + : +x, y); } if (isString(y)) { return rightLogShift(x, (config.number == 'bignumber') ? new BigNumber(y) - : parseInt(y)); + : +y); } if (isBoolean(x) || x === null) { From 38fd1c63156238c97d24c6e7ce4cf1237ed081d0 Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Mon, 8 Dec 2014 10:31:06 -0800 Subject: [PATCH 02/19] Add test cases to reflect previous error while using parseInt instead of unary plus; added test cases that included strings in scientific notation. --- test/function/bitwise/bitAnd.test.js | 1 + test/function/bitwise/bitNot.test.js | 1 + test/function/bitwise/bitOr.test.js | 1 + test/function/bitwise/bitXor.test.js | 1 + test/function/bitwise/leftShift.test.js | 1 + test/function/bitwise/rightArithShift.test.js | 1 + test/function/bitwise/rightLogShift.test.js | 1 + 7 files changed, 7 insertions(+) diff --git a/test/function/bitwise/bitAnd.test.js b/test/function/bitwise/bitAnd.test.js index 27fcbc068..4631ec314 100644 --- a/test/function/bitwise/bitAnd.test.js +++ b/test/function/bitwise/bitAnd.test.js @@ -69,6 +69,7 @@ describe('bitAnd', function () { assert.equal(bitAnd('86', 120), 80); assert.equal(bitAnd('-120', '-86'), -120); assert.equal(bitAnd(-120, '-86'), -120); + assert.equal(bitAnd(-120, '-86e2'), -8696); }); it('should bitwise and strings and matrices element wise', function () { diff --git a/test/function/bitwise/bitNot.test.js b/test/function/bitwise/bitNot.test.js index 49fca2e96..3ac83ea5d 100644 --- a/test/function/bitwise/bitNot.test.js +++ b/test/function/bitwise/bitNot.test.js @@ -24,6 +24,7 @@ describe('bitNot', function () { it('should return bitwise not of a string', function () { assert.equal(bitNot('2'), -3); assert.equal(bitNot('-2'), 1); + assert.equal(bitNot('-86e2'), 8599); }); /*it('should return bignumber bitwise not on a string', function() { diff --git a/test/function/bitwise/bitOr.test.js b/test/function/bitwise/bitOr.test.js index 395ec81f3..db808de57 100644 --- a/test/function/bitwise/bitOr.test.js +++ b/test/function/bitwise/bitOr.test.js @@ -47,6 +47,7 @@ describe('bitOr', function () { assert.equal(bitOr('86', 120), 126); assert.equal(bitOr('-120', '-86'), -86); assert.equal(bitOr(-120, '-86'), -86); + assert.equal(bitOr(-120, '-86e2'), -24); }); it('should bitwise or strings and matrices element wise', function () { diff --git a/test/function/bitwise/bitXor.test.js b/test/function/bitwise/bitXor.test.js index 2667ebc2a..9e9901909 100644 --- a/test/function/bitwise/bitXor.test.js +++ b/test/function/bitwise/bitXor.test.js @@ -49,6 +49,7 @@ describe('bitXor', function () { assert.equal(bitXor('86', 120), 46); assert.equal(bitXor('-120', '-86'), 34); assert.equal(bitXor(-120, '-86'), 34); + assert.equal(bitXor(-120, '-86e2'), 8672); }); it('should xor strings and matrices element wise', function () { diff --git a/test/function/bitwise/leftShift.test.js b/test/function/bitwise/leftShift.test.js index 6ae21d4e0..cfe8ef024 100644 --- a/test/function/bitwise/leftShift.test.js +++ b/test/function/bitwise/leftShift.test.js @@ -70,6 +70,7 @@ describe('leftShift', function () { assert.equal(leftShift('2', 0), 2); assert.equal(leftShift(2, '3'), 16); assert.equal(leftShift('-2', 2), -8); + assert.equal(leftShift(-2, '1e2'), -32); }); it('should element-wise left shift a matrix', function () { diff --git a/test/function/bitwise/rightArithShift.test.js b/test/function/bitwise/rightArithShift.test.js index ea920a3a7..219013cf3 100644 --- a/test/function/bitwise/rightArithShift.test.js +++ b/test/function/bitwise/rightArithShift.test.js @@ -45,6 +45,7 @@ describe('rightArithShift', function () { assert.equal(rightArithShift('2', 0), 2); assert.equal(rightArithShift(22, '3'), 2); assert.equal(rightArithShift('-256', 2), -64); + assert.equal(rightArithShift('-256', '1e2'), -16); }); diff --git a/test/function/bitwise/rightLogShift.test.js b/test/function/bitwise/rightLogShift.test.js index ef4b4ac5e..29a4ada70 100644 --- a/test/function/bitwise/rightLogShift.test.js +++ b/test/function/bitwise/rightLogShift.test.js @@ -45,6 +45,7 @@ describe('rightLogShift', function () { assert.equal(rightLogShift('2', 0), 2); assert.equal(rightLogShift(22, '3'), 2); assert.equal(rightLogShift('-256', 2), 1073741760); + assert.equal(rightLogShift('-256', '1e2'), 268435440); }); From 632eba954a06f9acd6ee913de2549ed578c633eb Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Tue, 9 Dec 2014 12:53:41 -0800 Subject: [PATCH 03/19] Uncommented bignumber portions, and added bignumber test cases. --- lib/function/bitwise/bitAnd.js | 46 ++++++++--------- lib/function/bitwise/bitNot.js | 2 +- lib/function/bitwise/bitOr.js | 46 ++++++++--------- lib/function/bitwise/bitXor.js | 46 ++++++++--------- lib/function/bitwise/leftShift.js | 51 +++++++++---------- lib/function/bitwise/rightArithShift.js | 51 +++++++++---------- lib/function/bitwise/rightLogShift.js | 6 +-- test/function/bitwise/bitAnd.test.js | 20 +++++--- test/function/bitwise/bitNot.test.js | 22 +++----- test/function/bitwise/bitOr.test.js | 30 ++++++++++- test/function/bitwise/bitXor.test.js | 30 ++++++++++- test/function/bitwise/leftShift.test.js | 21 +++++--- test/function/bitwise/rightArithShift.test.js | 29 ++++++++++- test/function/bitwise/rightLogShift.test.js | 3 -- 14 files changed, 235 insertions(+), 168 deletions(-) diff --git a/lib/function/bitwise/bitAnd.js b/lib/function/bitwise/bitAnd.js index d7e7d0055..0bb878842 100644 --- a/lib/function/bitwise/bitAnd.js +++ b/lib/function/bitwise/bitAnd.js @@ -44,6 +44,28 @@ module.exports = function (math, config) { return x & y; } + if (isCollection(x) || isCollection(y)) { + return collection.deepMap2(x, y, bitAnd); + } + + if (isString(x)) { + return bitAnd((config.number === 'bignumber') + ? new BigNumber(x) + : +x, y); + } + if (isString(y)) { + return bitAnd(x, (config.number === 'bignumber') + ? new BigNumber(y) + : +y); + } + + if (isBoolean(x) || x === null) { + return bitAnd(+x, y); + } + if (isBoolean(y) || y === null) { + return bitAnd(x, +y); + } + if (x instanceof BigNumber) { // try to convert to big number if (isNumber(y)) { @@ -64,35 +86,13 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - return x.and(y) + return x.and(y); } // downgrade to Number return bitAnd(x, y.toNumber()); } - if (isCollection(x) || isCollection(y)) { - return collection.deepMap2(x, y, bitAnd); - } - - if (isString(x)) { - return bitAnd((config.number == 'bignumber') - ? new BigNumber(x) - : +x, y); - } - if (isString(y)) { - return bitAnd(x, (config.number == 'bignumber') - ? new BigNumber(y) - : +y); - } - - if (isBoolean(x) || x === null) { - return bitAnd(+x, y); - } - if (isBoolean(y) || y === null) { - return bitAnd(x, +y); - } - throw new math.error.UnsupportedTypeError('bitAnd', math['typeof'](x), math['typeof'](y)); }; }; diff --git a/lib/function/bitwise/bitNot.js b/lib/function/bitwise/bitNot.js index 02773e7e0..492fc6d1b 100644 --- a/lib/function/bitwise/bitNot.js +++ b/lib/function/bitwise/bitNot.js @@ -53,7 +53,7 @@ module.exports = function (math, config) { } if (isString(x)) { - return bitNot((config.number == 'bignumber') + return bitNot((config.number === 'bignumber') ? new BigNumber(x) : +x); } diff --git a/lib/function/bitwise/bitOr.js b/lib/function/bitwise/bitOr.js index 52f2351b0..955fd1006 100644 --- a/lib/function/bitwise/bitOr.js +++ b/lib/function/bitwise/bitOr.js @@ -45,6 +45,28 @@ module.exports = function (math, config) { return x | y; } + if (isCollection(x) || isCollection(y)) { + return collection.deepMap2(x, y, bitOr); + } + + if (isString(x)) { + return bitOr((config.number === 'bignumber') + ? new BigNumber(x) + : +x, y); + } + if (isString(y)) { + return bitOr(x, (config.number === 'bignumber') + ? new BigNumber(y) + : +y); + } + + if (isBoolean(x) || x === null) { + return bitOr(+x, y); + } + if (isBoolean(y) || y === null) { + return bitOr(x, +y); + } + if (x instanceof BigNumber) { // try to convert to big number if (isNumber(y)) { @@ -65,35 +87,13 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - return x.or(y) + return x.or(y); } // downgrade to Number return bitOr(x, y.toNumber()); } - if (isCollection(x) || isCollection(y)) { - return collection.deepMap2(x, y, bitOr); - } - - if (isString(x)) { - return bitOr((config.number == 'bignumber') - ? new BigNumber(x) - : +x, y); - } - if (isString(y)) { - return bitOr(x, (config.number == 'bignumber') - ? new BigNumber(y) - : +y); - } - - if (isBoolean(x) || x === null) { - return bitOr(+x, y); - } - if (isBoolean(y) || y === null) { - return bitOr(x, +y); - } - throw new math.error.UnsupportedTypeError('bitOr', math['typeof'](x), math['typeof'](y)); }; }; diff --git a/lib/function/bitwise/bitXor.js b/lib/function/bitwise/bitXor.js index c0101d6d6..2427cbe42 100644 --- a/lib/function/bitwise/bitXor.js +++ b/lib/function/bitwise/bitXor.js @@ -45,6 +45,28 @@ module.exports = function (math, config) { return x ^ y; } + if (isCollection(x) || isCollection(y)) { + return collection.deepMap2(x, y, bitXor); + } + + if (isString(x)) { + return bitXor((config.number === 'bignumber') + ? new BigNumber(x) + : +x, y); + } + if (isString(y)) { + return bitXor(x, (config.number === 'bignumber') + ? new BigNumber(y) + : +y); + } + + if (isBoolean(x) || x === null) { + return bitXor(+x, y); + } + if (isBoolean(y) || y === null) { + return bitXor(x, +y); + } + if (x instanceof BigNumber) { // try to convert to big number if (isNumber(y)) { @@ -65,35 +87,13 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - return x.xor(y) + return x.xor(y); } // downgrade to Number return bitXor(x, y.toNumber()); } - if (isCollection(x) || isCollection(y)) { - return collection.deepMap2(x, y, bitXor); - } - - if (isString(x)) { - return bitXor((config.number == 'bignumber') - ? new BigNumber(x) - : +x, y); - } - if (isString(y)) { - return bitXor(x, (config.number == 'bignumber') - ? new BigNumber(y) - : +y); - } - - if (isBoolean(x) || x === null) { - return bitXor(+x, y); - } - if (isBoolean(y) || y === null) { - return bitXor(x, +y); - } - throw new math.error.UnsupportedTypeError('bitXor', math['typeof'](x), math['typeof'](y)); }; }; diff --git a/lib/function/bitwise/leftShift.js b/lib/function/bitwise/leftShift.js index 583e27613..b55662c73 100644 --- a/lib/function/bitwise/leftShift.js +++ b/lib/function/bitwise/leftShift.js @@ -45,13 +45,30 @@ module.exports = function (math, config) { return x << y; } - if (x instanceof BigNumber) { - // try to convert to big number - if (isNumber(y)) { - y = BigNumber.convert(y); - } + if (isCollection(x) && isNumber(y)) { + return collection.deepMap2(x, y, leftShift); + } - if (y instanceof BigNumber) { + if (isString(x)) { + return leftShift((config.number === 'bignumber') + ? new BigNumber(x) + : +x, y); + } + if (isString(y)) { + return leftShift(x, (config.number === 'bignumber') + ? new BigNumber(y) + : +y); + } + + if (isBoolean(x) || x === null) { + return leftShift(+x, y); + } + if (isBoolean(y) || y === null) { + return leftShift(x, +y); + } + + if (x instanceof BigNumber) { + if (isNumber(y) || y instanceof BigNumber) { return x.leftShift(y); } @@ -72,28 +89,6 @@ module.exports = function (math, config) { return leftShift(x, y.toNumber()); } - if (isCollection(x) && isNumber(y)) { - return collection.deepMap2(x, y, leftShift); - } - - if (isString(x)) { - return leftShift((config.number == 'bignumber') - ? new BigNumber(x) - : +x, y); - } - if (isString(y)) { - return leftShift(x, (config.number == 'bignumber') - ? new BigNumber(y) - : +y); - } - - if (isBoolean(x) || x === null) { - return leftShift(+x, y); - } - if (isBoolean(y) || y === null) { - return leftShift(x, +y); - } - throw new math.error.UnsupportedTypeError('leftShift', math['typeof'](x), math['typeof'](y)); }; }; diff --git a/lib/function/bitwise/rightArithShift.js b/lib/function/bitwise/rightArithShift.js index bb5c8a337..7332a1a04 100644 --- a/lib/function/bitwise/rightArithShift.js +++ b/lib/function/bitwise/rightArithShift.js @@ -45,13 +45,30 @@ module.exports = function (math, config) { return x >> y; } - if (x instanceof BigNumber) { - // try to convert to big number - if (isNumber(y)) { - y = BigNumber.convert(y); - } + if (isCollection(x) && isNumber(y)) { + return collection.deepMap2(x, y, rightArithShift); + } - if (y instanceof BigNumber) { + if (isString(x)) { + return rightArithShift((config.number === 'bignumber') + ? new BigNumber(x) + : +x, y); + } + if (isString(y)) { + return rightArithShift(x, (config.number === 'bignumber') + ? new BigNumber(y) + : +y); + } + + if (isBoolean(x) || x === null) { + return rightArithShift(+x, y); + } + if (isBoolean(y) || y === null) { + return rightArithShift(x, +y); + } + + if (x instanceof BigNumber) { + if (isNumber(y) || y instanceof BigNumber) { return x.rightShift(y); } @@ -72,28 +89,6 @@ module.exports = function (math, config) { return rightArithShift(x, y.toNumber()); } - if (isCollection(x) && isNumber(y)) { - return collection.deepMap2(x, y, rightArithShift); - } - - if (isString(x)) { - return rightArithShift((config.number == 'bignumber') - ? new BigNumber(x) - : +x, y); - } - if (isString(y)) { - return rightArithShift(x, (config.number == 'bignumber') - ? new BigNumber(y) - : +y); - } - - if (isBoolean(x) || x === null) { - return rightArithShift(+x, y); - } - if (isBoolean(y) || y === null) { - return rightArithShift(x, +y); - } - throw new math.error.UnsupportedTypeError('rightArithShift', math['typeof'](x), math['typeof'](y)); }; }; diff --git a/lib/function/bitwise/rightLogShift.js b/lib/function/bitwise/rightLogShift.js index b87e5da2d..c7256e1cb 100644 --- a/lib/function/bitwise/rightLogShift.js +++ b/lib/function/bitwise/rightLogShift.js @@ -33,7 +33,7 @@ module.exports = function (math, config) { * * @param {Number | Boolean | String | Array | Matrix | null} x Value to be shifted * @param {Number | Boolean | String | null} y Amount of shifts - * @return {Integer | BigNumber | Array | Matrix} `x` zero-filled shifted right `y` times + * @return {Integer | Array | Matrix} `x` zero-filled shifted right `y` times */ math.rightLogShift = function rightLogShift(x, y) { if (arguments.length != 2) { @@ -49,12 +49,12 @@ module.exports = function (math, config) { } if (isString(x)) { - return rightLogShift((config.number == 'bignumber') + return rightLogShift((config.number === 'bignumber') ? new BigNumber(x) : +x, y); } if (isString(y)) { - return rightLogShift(x, (config.number == 'bignumber') + return rightLogShift(x, (config.number === 'bignumber') ? new BigNumber(y) : +y); } diff --git a/test/function/bitwise/bitAnd.test.js b/test/function/bitwise/bitAnd.test.js index 4631ec314..9490baaa1 100644 --- a/test/function/bitwise/bitAnd.test.js +++ b/test/function/bitwise/bitAnd.test.js @@ -1,9 +1,8 @@ // test bitAnd var assert = require('assert'), - approx = require('../../../tools/approx'), error = require('../../../lib/error/index'), math = require('../../../index'), - //bignumber = math.bignumber, + bignumber = math.bignumber, bitAnd = math.bitAnd; describe('bitAnd', function () { @@ -36,12 +35,12 @@ describe('bitAnd', function () { assert.equal(bitAnd(false, 1), 0); }); -/*it('should bitwise and bignumbers', function () { + it('should bitwise and bignumbers', function () { assert.deepEqual(bitAnd(bignumber(1), bignumber(2)), bignumber(0)); - assert.deepEqual(bitAnd(bignumber('-1.0e+31'), bignumber('-1.0e+32')), bignumber('-1.0127339798528531708e+32')); - assert.deepEqual(bitAnd(bignumber('1.0e+31'), bignumber('1.0e+32')), bignumber('8.726602014714682918e+30')); - assert.deepEqual(bitAnd(bignumber('-1.0e+31'), bignumber('1.0e+32')), bignumber('9.1273397985285317082e+31')); - assert.deepEqual(bitAnd(bignumber('1.0e+31'), bignumber('-1.0e+32')), bignumber('1.273397985285317082e+30')); + assert.deepEqual(bitAnd(bignumber('-1.0e+31'), bignumber('-1.0e+32')), bignumber('-101273397985285317082036849082368')); + assert.deepEqual(bitAnd(bignumber('1.0e+31'), bignumber('1.0e+32')), bignumber('8726602014714682917961003433984')); + assert.deepEqual(bitAnd(bignumber('-1.0e+31'), bignumber('1.0e+32')), bignumber('91273397985285317082038996566016')); + assert.deepEqual(bitAnd(bignumber('1.0e+31'), bignumber('-1.0e+32')), bignumber('1273397985285317082036849082368')); }); it('should bitwise and mixed numbers and bignumbers', function () { @@ -56,7 +55,12 @@ describe('bitAnd', function () { assert.deepEqual(bitAnd(bignumber(1), false), bignumber(0)); assert.deepEqual(bitAnd(false, bignumber(3)), bignumber(0)); assert.deepEqual(bitAnd(true, bignumber(3)), bignumber(1)); - });*/ + }); + + it('should bitwise and mixed strings and bignumbers', function () { + assert.deepEqual(bitAnd(bignumber('-1.0e+31'), '-1.0e+32'), bignumber('-101273397985285317082036849082368')); + assert.deepEqual(bitAnd('1.0e+32', bignumber('1.0e+31')), bignumber('8726602014714682917961003433984')); + }); it('should throw an error if used with a unit', function() { assert.throws(function () {bitAnd(math.unit('5cm'), 2)}, error.UnsupportedTypeError); diff --git a/test/function/bitwise/bitNot.test.js b/test/function/bitwise/bitNot.test.js index 3ac83ea5d..c79034e27 100644 --- a/test/function/bitwise/bitNot.test.js +++ b/test/function/bitwise/bitNot.test.js @@ -2,7 +2,7 @@ var assert = require('assert'), math = require('../../../index'), error = require('../../../lib/error/index'), - // bignumber = math.bignumber, + bignumber = math.bignumber, bitNot = math.bitNot; describe('bitNot', function () { @@ -11,12 +11,6 @@ describe('bitNot', function () { assert.equal(bitNot(false), -1); }); - /*it('should return bignumber bitwise not of a boolean', function () { - var bigmath = math.create({number: 'bignumber'}); - assert.deepEqual(bigmath.bitNot(true), bigmath.bignumber(-2)); - assert.deepEqual(bigmath.bitNot(false), bigmath.bignumber(-1)); - });*/ - it('should return bitwise not of null', function () { assert.equal(bitNot(null), -1); }); @@ -27,11 +21,11 @@ describe('bitNot', function () { assert.equal(bitNot('-86e2'), 8599); }); - /*it('should return bignumber bitwise not on a string', function() { - var bigmath = math.create({number: 'bignumber'}); - assert.deepEqual(bigmath.bitNot('2'), bigmath.bignumber(-3)); - assert.deepEqual(bigmath.bitNot('-2'), bigmath.bignumber(1)); - });*/ + it('should return bignumber bitwise not on a string', function() { + assert.deepEqual(bitNot(bignumber('2')), bignumber(-3)); + assert.deepEqual(bitNot(bignumber('-2')), bignumber(1)); + assert.deepEqual(bitNot(bignumber('1.2345e30')), bignumber('-1234500000000000000000000000001')); + }); it('should perform bitwise not of a number', function () { assert.deepEqual(bitNot(2), -3); @@ -39,10 +33,10 @@ describe('bitNot', function () { assert.deepEqual(bitNot(0), -1); }); - /*it('should perform bitwise not of a big number', function() { + it('should perform bitwise not of a big number', function() { assert.deepEqual(bitNot(bignumber(2)), bignumber(-3)); assert.deepEqual(bitNot(bignumber(-2)), bignumber(1)); - });*/ + }); it('should throw an error if used with a unit', function() { assert.throws(function () {bitNot(math.unit('5cm'))}, error.UnsupportedTypeError); diff --git a/test/function/bitwise/bitOr.test.js b/test/function/bitwise/bitOr.test.js index db808de57..657e5828f 100644 --- a/test/function/bitwise/bitOr.test.js +++ b/test/function/bitwise/bitOr.test.js @@ -1,9 +1,8 @@ // test bitOr var assert = require('assert'), - approx = require('../../../tools/approx'), error = require('../../../lib/error/index'), math = require('../../../index'), - //bignumber = math.bignumber, + bignumber = math.bignumber, bitOr = math.bitOr; describe('bitOr', function () { @@ -36,6 +35,33 @@ describe('bitOr', function () { assert.equal(bitOr(false, 0), 0); }); + it('should bitwise or bignumbers', function () { + assert.deepEqual(bitOr(bignumber(1), bignumber(2)), bignumber(3)); + assert.deepEqual(bitOr(bignumber('-1.0e+31'), bignumber('-1.0e+32')), bignumber('-8726602014714682917963150917632')); + assert.deepEqual(bitOr(bignumber('1.0e+31'), bignumber('1.0e+32')), bignumber('101273397985285317082038996566016')); + assert.deepEqual(bitOr(bignumber('-1.0e+31'), bignumber('1.0e+32')), bignumber('-1273397985285317082038996566016')); + assert.deepEqual(bitOr(bignumber('1.0e+31'), bignumber('-1.0e+32')), bignumber('-91273397985285317082036849082368')); + }); + + it('should bitwise or mixed numbers and bignumbers', function () { + assert.deepEqual(bitOr(bignumber(1), 2), bignumber(3)); + assert.deepEqual(bitOr(1, bignumber(2)), bignumber(3)); + assert.deepEqual(bitOr(bignumber(7), 9), bignumber(15)); + assert.deepEqual(bitOr(7, bignumber(9)), bignumber(15)); + }); + + it('should bitwise or mixed booleans and bignumbers', function () { + assert.deepEqual(bitOr(bignumber(1), false), bignumber(1)); + assert.deepEqual(bitOr(bignumber(2), true), bignumber(3)); + assert.deepEqual(bitOr(false, bignumber(1)), bignumber(1)); + assert.deepEqual(bitOr(true, bignumber(2)), bignumber(3)); + }); + + it('should bitwise or mixed strings and bignumbers', function () { + assert.deepEqual(bitOr('-1.0e+31', bignumber('-1.0e+32')), bignumber('-8726602014714682917963150917632')); + assert.deepEqual(bitOr(bignumber('1.0e+31'), '1.0e+32'), bignumber('101273397985285317082038996566016')); + }); + it('should throw an error if used with a unit', function() { assert.throws(function () {bitOr(math.unit('5cm'), 2)}, error.UnsupportedTypeError); assert.throws(function () {bitOr(2, math.unit('5cm'))}, error.UnsupportedTypeError); diff --git a/test/function/bitwise/bitXor.test.js b/test/function/bitwise/bitXor.test.js index 9e9901909..900cb30f1 100644 --- a/test/function/bitwise/bitXor.test.js +++ b/test/function/bitwise/bitXor.test.js @@ -1,9 +1,8 @@ // test bitXor var assert = require('assert'), - approx = require('../../../tools/approx'), error = require('../../../lib/error/index'), math = require('../../../index'), - //bignumber = math.bignumber, + bignumber = math.bignumber, bitXor = math.bitXor; describe('bitXor', function () { @@ -38,6 +37,33 @@ describe('bitXor', function () { assert.equal(bitXor(false, 1), 1); }); + it('should bitwise xor bignumbers', function () { + assert.deepEqual(bitXor(bignumber(1), bignumber(2)), bignumber(3)); + assert.deepEqual(bitXor(bignumber('-1.0e+31'), bignumber('-1.0e+32')), bignumber('92546795970570634164073698164736')); + assert.deepEqual(bitXor(bignumber('1.0e+31'), bignumber('1.0e+32')), bignumber('92546795970570634164077993132032')); + assert.deepEqual(bitXor(bignumber('-1.0e+31'), bignumber('1.0e+32')), bignumber('-92546795970570634164077993132032')); + assert.deepEqual(bitXor(bignumber('1.0e+31'), bignumber('-1.0e+32')), bignumber('-92546795970570634164073698164736')); + }); + + it('should bitwise xor mixed numbers and bignumbers', function () { + assert.deepEqual(bitXor(bignumber(1), 2), bignumber(3)); + assert.deepEqual(bitXor(1, bignumber(2)), bignumber(3)); + assert.deepEqual(bitXor(bignumber(7), 9), bignumber(14)); + assert.deepEqual(bitXor(7, bignumber(9)), bignumber(14)); + }); + + it('should bitwise xor mixed booleans and bignumbers', function () { + assert.deepEqual(bitXor(bignumber(1), true), bignumber(0)); + assert.deepEqual(bitXor(bignumber(1), false), bignumber(1)); + assert.deepEqual(bitXor(true, bignumber(3)), bignumber(2)); + assert.deepEqual(bitXor(false, bignumber(3)), bignumber(3)); + }); + + it('should bitwise and mixed strings and bignumbers', function () { + assert.deepEqual(bitXor(bignumber('-1.0e+31'), '-1.0e+32'), bignumber('92546795970570634164073698164736')); + assert.deepEqual(bitXor('1.0e+31', bignumber('1.0e+32')), bignumber('92546795970570634164077993132032')); + }); + it('should throw an error if used with a unit', function() { assert.throws(function () {bitXor(math.unit('5cm'), 2)}, error.UnsupportedTypeError); assert.throws(function () {bitXor(2, math.unit('5cm'))}, error.UnsupportedTypeError); diff --git a/test/function/bitwise/leftShift.test.js b/test/function/bitwise/leftShift.test.js index cfe8ef024..0f487b50f 100644 --- a/test/function/bitwise/leftShift.test.js +++ b/test/function/bitwise/leftShift.test.js @@ -1,9 +1,8 @@ // test leftShift var assert = require('assert'), - approx = require('../../../tools/approx'), error = require('../../../lib/error/index'), math = require('../../../index'), - //bignumber = math.bignumber, + bignumber = math.bignumber, leftShift = math.leftShift; describe('leftShift', function () { @@ -38,18 +37,17 @@ describe('leftShift', function () { assert.equal(leftShift(null, 1), 0); }); - /*it('should left shift bignumbers', function () { + it('should left shift bignumbers', 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('-1')); + assert.deepEqual(leftShift(bignumber(-1), bignumber(2)), bignumber(-4)); }); it('should left shift mixed numbers and bignumbers', function () { assert.deepEqual(leftShift(bignumber(2), 3), bignumber(16)); assert.deepEqual(leftShift(2, bignumber(3)), bignumber(16)); - - approx.equal(leftShift(-1, bignumber(2)), bignumber(-4)); - approx.equal(leftShift(bignumber(-1), 2), bignumber(-4)); + assert.deepEqual(leftShift(-1, bignumber(2)), bignumber(-4)); + assert.deepEqual(leftShift(bignumber(-1), 2), bignumber(-4)); }); it('should left shift mixed booleans and bignumbers', function () { @@ -57,7 +55,14 @@ describe('leftShift', function () { assert.deepEqual(leftShift(false, bignumber(3)), bignumber(0)); assert.deepEqual(leftShift(bignumber(3), false), bignumber(3)); assert.deepEqual(leftShift(bignumber(3), true), bignumber(6)); - });*/ + }); + + it('should left shift mixed bignumbers and string', function () { + assert.deepEqual(leftShift(bignumber(2), '3'), bignumber(16)); + assert.deepEqual(leftShift('2', bignumber(3)), bignumber(16)); + assert.deepEqual(leftShift(bignumber(-1), '2'), bignumber(-4)); + assert.deepEqual(leftShift('-2', bignumber(3)), bignumber(-16)); + }); it('should throw an error if used with a unit', function() { assert.throws(function () {leftShift(math.unit('5cm'), 2)}, error.UnsupportedTypeError); diff --git a/test/function/bitwise/rightArithShift.test.js b/test/function/bitwise/rightArithShift.test.js index 219013cf3..86c9817b6 100644 --- a/test/function/bitwise/rightArithShift.test.js +++ b/test/function/bitwise/rightArithShift.test.js @@ -1,9 +1,8 @@ // test rightArithShift var assert = require('assert'), - //approx = require('../../../tools/approx'), error = require('../../../lib/error/index'), math = require('../../../index'), - //bignumber = math.bignumber, + bignumber = math.bignumber, rightArithShift = math.rightArithShift; describe('rightArithShift', function () { @@ -48,6 +47,32 @@ describe('rightArithShift', function () { assert.equal(rightArithShift('-256', '1e2'), -16); }); + it('should right arithmetically shift bignumbers', 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)); + }); + + 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(17, bignumber(3)), bignumber(2)); + assert.deepEqual(rightArithShift(-17, bignumber(3)), bignumber(-3)); + }); + + it('should right arithmetically shift mixed booleans and bignumbers', function () { + assert.deepEqual(rightArithShift(true, bignumber(0)), bignumber(1)); + assert.deepEqual(rightArithShift(false, bignumber('1000000')), bignumber(0)); + assert.deepEqual(rightArithShift(bignumber(3), false), bignumber(3)); + assert.deepEqual(rightArithShift(bignumber(3), true), bignumber(1)); + }); + + it('should right arithmetically shift mixed bignumbers and string', function () { + assert.deepEqual(rightArithShift(bignumber(17), '3'), bignumber(2)); + assert.deepEqual(rightArithShift('17', bignumber(3)), bignumber(2)); + assert.deepEqual(rightArithShift(bignumber('-17'), '3'), bignumber(-3)); + assert.deepEqual(rightArithShift('-17', bignumber(3)), bignumber(-3)); + }); it('should throw an error if used with a unit', function() { assert.throws(function () {rightArithShift(math.unit('5cm'), 2)}, error.UnsupportedTypeError); diff --git a/test/function/bitwise/rightLogShift.test.js b/test/function/bitwise/rightLogShift.test.js index 29a4ada70..ee9120b22 100644 --- a/test/function/bitwise/rightLogShift.test.js +++ b/test/function/bitwise/rightLogShift.test.js @@ -1,9 +1,7 @@ // test rightLogShift var assert = require('assert'), - //approx = require('../../../tools/approx'), error = require('../../../lib/error/index'), math = require('../../../index'), - //bignumber = math.bignumber, rightLogShift = math.rightLogShift; describe('rightLogShift', function () { @@ -48,7 +46,6 @@ describe('rightLogShift', function () { assert.equal(rightLogShift('-256', '1e2'), 268435440); }); - it('should throw an error if used with a unit', function() { assert.throws(function () {rightLogShift(math.unit('5cm'), 2)}, error.UnsupportedTypeError); assert.throws(function () {rightLogShift(2, math.unit('5cm'))}, error.UnsupportedTypeError); From 50702826df7ff55bfb337e0ed12f738a57b46ec4 Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Tue, 9 Dec 2014 22:11:24 -0800 Subject: [PATCH 04/19] Slightly lower the code size for the 2-input gates, to much the flow of the shifts. --- lib/function/bitwise/bitAnd.js | 7 +------ lib/function/bitwise/bitOr.js | 7 +------ lib/function/bitwise/bitXor.js | 7 +------ 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/lib/function/bitwise/bitAnd.js b/lib/function/bitwise/bitAnd.js index 0bb878842..a79571c77 100644 --- a/lib/function/bitwise/bitAnd.js +++ b/lib/function/bitwise/bitAnd.js @@ -67,12 +67,7 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - // try to convert to big number - if (isNumber(y)) { - y = BigNumber.convert(y); - } - - if (y instanceof BigNumber) { + if (isNumber(y) || y instanceof BigNumber) { return x.and(y); } diff --git a/lib/function/bitwise/bitOr.js b/lib/function/bitwise/bitOr.js index 955fd1006..7641049a5 100644 --- a/lib/function/bitwise/bitOr.js +++ b/lib/function/bitwise/bitOr.js @@ -68,12 +68,7 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - // try to convert to big number - if (isNumber(y)) { - y = BigNumber.convert(y); - } - - if (y instanceof BigNumber) { + if (isNumber(y) || y instanceof BigNumber) { return x.or(y); } diff --git a/lib/function/bitwise/bitXor.js b/lib/function/bitwise/bitXor.js index 2427cbe42..96a4210ad 100644 --- a/lib/function/bitwise/bitXor.js +++ b/lib/function/bitwise/bitXor.js @@ -68,12 +68,7 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - // try to convert to big number - if (isNumber(y)) { - y = BigNumber.convert(y); - } - - if (y instanceof BigNumber) { + if (isNumber(y) || y instanceof BigNumber) { return x.xor(y); } From 77001b40c01537355b18b397f85c0caffc876816 Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Tue, 9 Dec 2014 22:27:19 -0800 Subject: [PATCH 05/19] Adjusted return types in the comments above the method; Integer isn't a JavaScript type. --- lib/function/bitwise/bitAnd.js | 2 +- lib/function/bitwise/bitNot.js | 2 +- lib/function/bitwise/bitOr.js | 2 +- lib/function/bitwise/bitXor.js | 2 +- lib/function/bitwise/leftShift.js | 2 +- lib/function/bitwise/rightArithShift.js | 2 +- lib/function/bitwise/rightLogShift.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/function/bitwise/bitAnd.js b/lib/function/bitwise/bitAnd.js index a79571c77..42247e87d 100644 --- a/lib/function/bitwise/bitAnd.js +++ b/lib/function/bitwise/bitAnd.js @@ -33,7 +33,7 @@ module.exports = function (math, config) { * * @param {Number | BigNumber | Boolean | String | Array | Matrix | null} x First value to and * @param {Number | BigNumber | Boolean | String | Array | Matrix | null} y Second value to and - * @return {Integer | BigNumber | Array | Matrix} AND of `x` and `y` + * @return {Number | BigNumber | Array | Matrix} AND of `x` and `y` */ math.bitAnd = function bitAnd(x, y) { if (arguments.length != 2) { diff --git a/lib/function/bitwise/bitNot.js b/lib/function/bitwise/bitNot.js index 492fc6d1b..4c8ce3774 100644 --- a/lib/function/bitwise/bitNot.js +++ b/lib/function/bitwise/bitNot.js @@ -33,7 +33,7 @@ module.exports = function (math, config) { * bitAnd, bitOr, bitXor, leftShift, rightArithShift, rightLogShift * * @param {Number | BigNumber | Boolean | String | Array | Matrix | null} x Value to not - * @return {Integer | BigNumber | Array | Matrix} NOT of `x` + * @return {Number | BigNumber | Array | Matrix} NOT of `x` */ math.bitNot = function bitNot(x) { if (arguments.length != 1) { diff --git a/lib/function/bitwise/bitOr.js b/lib/function/bitwise/bitOr.js index 7641049a5..88fcd94f8 100644 --- a/lib/function/bitwise/bitOr.js +++ b/lib/function/bitwise/bitOr.js @@ -34,7 +34,7 @@ module.exports = function (math, config) { * * @param {Number | BigNumber | Boolean | String | Array | Matrix | null} x First value to or * @param {Number | BigNumber | Boolean | String | Array | Matrix | null} y Second value to or - * @return {Integer | BigNumber | Array | Matrix} OR of `x` and `y` + * @return {Number | BigNumber | Array | Matrix} OR of `x` and `y` */ math.bitOr = function bitOr(x, y) { if (arguments.length != 2) { diff --git a/lib/function/bitwise/bitXor.js b/lib/function/bitwise/bitXor.js index 96a4210ad..93b119fb6 100644 --- a/lib/function/bitwise/bitXor.js +++ b/lib/function/bitwise/bitXor.js @@ -34,7 +34,7 @@ module.exports = function (math, config) { * * @param {Number | BigNumber | Boolean | String | Array | Matrix | null} x First value to xor * @param {Number | BigNumber | Boolean | String | Array | Matrix | null} y Second value to xor - * @return {Integer | BigNumber | Array | Matrix} XOR of `x` and `y` + * @return {Number | BigNumber | Array | Matrix} XOR of `x` and `y` */ math.bitXor = function bitXor(x, y) { if (arguments.length != 2) { diff --git a/lib/function/bitwise/leftShift.js b/lib/function/bitwise/leftShift.js index b55662c73..959e5ef47 100644 --- a/lib/function/bitwise/leftShift.js +++ b/lib/function/bitwise/leftShift.js @@ -34,7 +34,7 @@ module.exports = function (math, config) { * * @param {Number | BigNumber | Boolean | String | Array | Matrix | null} x Value to be shifted * @param {Number | BigNumber | Boolean | String | null} y Amount of shifts - * @return {Integer | BigNumber | Array | Matrix} `x` shifted left `y` times + * @return {Number | BigNumber | Array | Matrix} `x` shifted left `y` times */ math.leftShift = function leftShift(x, y) { if (arguments.length != 2) { diff --git a/lib/function/bitwise/rightArithShift.js b/lib/function/bitwise/rightArithShift.js index 7332a1a04..b9c9ea951 100644 --- a/lib/function/bitwise/rightArithShift.js +++ b/lib/function/bitwise/rightArithShift.js @@ -34,7 +34,7 @@ module.exports = function (math, config) { * * @param {Number | BigNumber | Boolean | String | Array | Matrix | null} x Value to be shifted * @param {Number | BigNumber | Boolean | String | null} y Amount of shifts - * @return {Integer | BigNumber | Array | Matrix} `x` sign-filled shifted right `y` times + * @return {Number | BigNumber | Array | Matrix} `x` sign-filled shifted right `y` times */ math.rightArithShift = function rightArithShift(x, y) { if (arguments.length != 2) { diff --git a/lib/function/bitwise/rightLogShift.js b/lib/function/bitwise/rightLogShift.js index c7256e1cb..02974a2d7 100644 --- a/lib/function/bitwise/rightLogShift.js +++ b/lib/function/bitwise/rightLogShift.js @@ -33,7 +33,7 @@ module.exports = function (math, config) { * * @param {Number | Boolean | String | Array | Matrix | null} x Value to be shifted * @param {Number | Boolean | String | null} y Amount of shifts - * @return {Integer | Array | Matrix} `x` zero-filled shifted right `y` times + * @return {Number | Array | Matrix} `x` zero-filled shifted right `y` times */ math.rightLogShift = function rightLogShift(x, y) { if (arguments.length != 2) { From c3a7410a9a63e3bbcda431dfe18662f73a34af59 Mon Sep 17 00:00:00 2001 From: Pavel Panchekha Date: Fri, 12 Dec 2014 12:14:28 -0800 Subject: [PATCH 06/19] Add tests for calling sin and cos on very small inputs. --- test/function/trigonometry/cos.test.js | 3 ++- test/function/trigonometry/sin.test.js | 1 + test/function/trigonometry/sinh.test.js | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/test/function/trigonometry/cos.test.js b/test/function/trigonometry/cos.test.js index 433baa544..675d682f8 100644 --- a/test/function/trigonometry/cos.test.js +++ b/test/function/trigonometry/cos.test.js @@ -30,6 +30,7 @@ describe('cos', function() { approx.equal(cos(pi*7/4), 0.707106781186548); approx.equal(cos(pi*8/4), 1); approx.equal(cos(pi/4), math.sqrt(2)/2); + assert.deepEqual(cos(complex('1e-50+1e-50i')), complex(1, -1e-100)); }); it('should return the cosine of a bignumber (downgrades to number)', function() { @@ -76,4 +77,4 @@ describe('cos', function() { assert.throws(function () {cos(1, 2)}, error.ArgumentsError); }); -}); \ No newline at end of file +}); diff --git a/test/function/trigonometry/sin.test.js b/test/function/trigonometry/sin.test.js index 43f6a78dd..c13aebbbe 100644 --- a/test/function/trigonometry/sin.test.js +++ b/test/function/trigonometry/sin.test.js @@ -46,6 +46,7 @@ describe('sin', function() { approx.deepEqual(sin(complex('i')), complex(0, 1.175201193643801)); approx.deepEqual(sin(complex('1')), complex(0.841470984807897, 0)); approx.deepEqual(sin(complex('1+i')), complex(1.298457581415977, 0.634963914784736)); + assert.deepEqual(sin(complex('1e-50i')), complex(0, 1e-50)); }); it('should return the sine of an angle', function() { diff --git a/test/function/trigonometry/sinh.test.js b/test/function/trigonometry/sinh.test.js index d062ba860..848e6dbe8 100644 --- a/test/function/trigonometry/sinh.test.js +++ b/test/function/trigonometry/sinh.test.js @@ -24,6 +24,12 @@ describe('sinh', function() { approx.equal(sinh(1), 1.1752011936438014); }); + it('should return the sinh of very small numbers', function() { + // If sinh returns 0, that is bad, so we are using assert.equal, not approx.equal + assert.equal(sinh(-1e-10), -1e-10); + assert.equal(sinh(1e-50), 1e-50); + }) + it('should return the sinh of a bignumber (downgrades to number)', function() { approx.equal(sinh(math.bignumber(1)), 1.1752011936438014); }); From 402d667b8f80163ac1b7c8ba57b42355827c8913 Mon Sep 17 00:00:00 2001 From: Pavel Panchekha Date: Fri, 12 Dec 2014 12:14:51 -0800 Subject: [PATCH 07/19] Fix sinh (and complex sin/cos) for small inputs --- lib/function/trigonometry/cos.js | 4 ++-- lib/function/trigonometry/sin.js | 4 ++-- lib/function/trigonometry/sinh.js | 6 +++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/function/trigonometry/cos.js b/lib/function/trigonometry/cos.js index f03c4824c..9601c00ef 100644 --- a/lib/function/trigonometry/cos.js +++ b/lib/function/trigonometry/cos.js @@ -52,8 +52,8 @@ module.exports = function (math) { if (isComplex(x)) { // cos(z) = (exp(iz) + exp(-iz)) / 2 return new Complex( - 0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp(x.im)), - 0.5 * Math.sin(x.re) * (Math.exp(-x.im) - Math.exp(x.im)) + Math.cos(x.re) * math.cosh(-x.im), + Math.sin(x.re) * math.sinh(-x.im) ); } diff --git a/lib/function/trigonometry/sin.js b/lib/function/trigonometry/sin.js index 7b68f6afc..f35f7a47b 100644 --- a/lib/function/trigonometry/sin.js +++ b/lib/function/trigonometry/sin.js @@ -51,8 +51,8 @@ module.exports = function (math) { if (isComplex(x)) { return new Complex( - 0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp( x.im)), - 0.5 * Math.cos(x.re) * (Math.exp( x.im) - Math.exp(-x.im)) + Math.sin(x.re) * math.cosh(-x.im), + Math.cos(x.re) * math.sinh(x.im) ); } diff --git a/lib/function/trigonometry/sinh.js b/lib/function/trigonometry/sinh.js index 85afa0d66..17c8edc24 100644 --- a/lib/function/trigonometry/sinh.js +++ b/lib/function/trigonometry/sinh.js @@ -41,7 +41,11 @@ module.exports = function (math) { } if (isNumber(x)) { - return (Math.exp(x) - Math.exp(-x)) / 2; + if (Math.abs(x) < 1) { + return x + (x * x * x) / 6 + (x * x * x * x * x) / 120; + } else { + return (Math.exp(x) - Math.exp(-x)) / 2; + } } if (isComplex(x)) { From 617320709e52cc27a477b7a1167217768952200b Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Fri, 12 Dec 2014 22:45:55 -0800 Subject: [PATCH 08/19] C/Java/Python style and. Will switch later if needed. --- lib/function/relational/and.js | 109 +++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 lib/function/relational/and.js diff --git a/lib/function/relational/and.js b/lib/function/relational/and.js new file mode 100644 index 000000000..608e62c90 --- /dev/null +++ b/lib/function/relational/and.js @@ -0,0 +1,109 @@ +'use strict'; + +module.exports = function (math) { + var util = require('../../util/index'), + + BigNumber = math.type.BigNumber, + Complex = require('../../type/Complex'), + Unit = require('../../type/Unit'), + collection = require('../../type/collection'), + + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Test whether two values are both defined with a nonzero/nonempty value. + * + * Syntax: + * + * math.and(x, y) + * + * Examples: + * + * math.and(2, 4); // returns true + * + * a = [2, 5, 1]; + * b = [2, 7, 1]; + * c = 0; + * + * math.and(a, b); // returns true + * math.and(a, c); // returns false + * + * See also: + * + * not, or + * + * @param {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix | null | undefined} x First value to check + * @param {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix | null | undefined} y Second value to check + * @return {Boolean | Array | Matrix} + * Returns true when both inputs are defined with a nonzero/nonempty value. + */ + math.and = function and(x, y) { + if (arguments.length != 2) { + throw new math.error.ArgumentsError('and', arguments.length, 2); + } + + if (isComplex(x)) { + if (x.re == 0 && x.im == 0) { + return false; + } + + return and(true, y); + } + if (isComplex(y)) { + if (y.re == 0 && y.im == 0) { + return false; + } + + return and(x, true); + } + + if (x instanceof BigNumber) { + if (x.isZero()) { + return false; + } + + return and(true, y); + } + if (y instanceof BigNumber) { + if (y.isZero()) { + return false; + } + + return and(x, true); + } + + if (isUnit(x)) { + if (x.value === null || x.value == 0) { + return false; + } + + return and(true, y); + } + if (isUnit(y)) { + if (y.value === null || y.value == 0) { + return false; + } + + return and(x, true); + } + + if (isCollection(x)) { + if (x.length == 0) { + return false; + } + + return and(true, y); + } + if (isCollection(y)) { + if (y.length == 0) { + return false; + } + + return and(x, true); + } + + return x && y; + }; +}; From e51bb94d56e5d46ea48496de4e0ff5b592a06183 Mon Sep 17 00:00:00 2001 From: Pavel Panchekha Date: Sun, 14 Dec 2014 00:42:45 -0800 Subject: [PATCH 09/19] Fix the test case so it passes on all hardware. The fix is to test that the imaginary part is nonzero, not that it is exactly 1e-100. In some software / hardware combos, it seems to return 1.0000000000000001e-100. --- test/function/trigonometry/cos.test.js | 2 +- test/function/trigonometry/sinh.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/function/trigonometry/cos.test.js b/test/function/trigonometry/cos.test.js index 675d682f8..f4b8c14ff 100644 --- a/test/function/trigonometry/cos.test.js +++ b/test/function/trigonometry/cos.test.js @@ -30,7 +30,7 @@ describe('cos', function() { approx.equal(cos(pi*7/4), 0.707106781186548); approx.equal(cos(pi*8/4), 1); approx.equal(cos(pi/4), math.sqrt(2)/2); - assert.deepEqual(cos(complex('1e-50+1e-50i')), complex(1, -1e-100)); + assert.ok(cos(complex('1e-50+1e-50i')).im != 0); }); it('should return the cosine of a bignumber (downgrades to number)', function() { diff --git a/test/function/trigonometry/sinh.test.js b/test/function/trigonometry/sinh.test.js index 848e6dbe8..7c10043c4 100644 --- a/test/function/trigonometry/sinh.test.js +++ b/test/function/trigonometry/sinh.test.js @@ -24,7 +24,7 @@ describe('sinh', function() { approx.equal(sinh(1), 1.1752011936438014); }); - it('should return the sinh of very small numbers', function() { + it('should return the sinh of very small numbers (avoid returning zero)', function() { // If sinh returns 0, that is bad, so we are using assert.equal, not approx.equal assert.equal(sinh(-1e-10), -1e-10); assert.equal(sinh(1e-50), 1e-50); From 3f42d8d08c9cf40ec0c0f62ea9f4d5dda2d9f4ad Mon Sep 17 00:00:00 2001 From: jos Date: Sun, 14 Dec 2014 13:24:24 +0100 Subject: [PATCH 10/19] Fixe a typo (see #246) --- docs/reference/units.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/units.md b/docs/reference/units.md index b3603eb65..ca2e11e2b 100644 --- a/docs/reference/units.md +++ b/docs/reference/units.md @@ -11,7 +11,7 @@ Base | Unit Length | meter (m), inch (in), foot (ft), yard (yd), mile (mi), link (li), rod (rd), chain (ch), angstrom, mil Surface | m2, sqin, sqft, sqyd, sqmi, sqrd, sqch, sqmil Volume | m3, litre (l, L, lt, liter), cc, cuin, cuft, cuyd, teaspoon, tablespoon -Liquid | volume minim (min), fluiddram (fldr), fluidounce (fldz), gill (gi), cup (cp), pint (pt), quart (qt), gallon (gal), beerbarrel (bbl), oilbarrel (obl), hogshead, drop (gtt) +Liquid | volume minim (min), fluiddram (fldr), fluidounce (floz), gill (gi), cup (cp), pint (pt), quart (qt), gallon (gal), beerbarrel (bbl), oilbarrel (obl), hogshead, drop (gtt) Angles | rad, deg, grad, cycle Time | second (s), seconds, minute, minutes, hour (h), hours, day, days Mass | gram(g), tonne, ton, grain (gr), dram(dr), ounce (oz), poundmass (lbm, lb, lbs), hundredweight (cwt), stick From 05cb69f6da9c0a2f9a3a0021e269a2ab0021a259 Mon Sep 17 00:00:00 2001 From: jos Date: Sun, 14 Dec 2014 13:35:17 +0100 Subject: [PATCH 11/19] Converting a unit without value will now result in a unit *with* value --- HISTORY.md | 6 ++++++ lib/type/Unit.js | 5 +++-- test/type/Unit.test.js | 19 +++++++++++++++++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index f0b4f11f6..844dedcef 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,12 @@ # History +## not yet released, version 1.1.2 + +- Converting a unit without value will now result in a unit *with* value, + i.e. `inch in cm` will return `2.54 cm` instead of `cm`. + + ## 2014-11-22, version 1.1.1 - Fixed Unit divided by Number returning zero. diff --git a/lib/type/Unit.js b/lib/type/Unit.js index 3452682a4..f44e7463e 100644 --- a/lib/type/Unit.js +++ b/lib/type/Unit.js @@ -347,6 +347,7 @@ Unit.prototype.equals = function(other) { */ Unit.prototype.to = function (valuelessUnit) { var other; + var value = this.value == null ? this._normalize(1) : this.value; if (isString(valuelessUnit)) { other = new Unit(null, valuelessUnit); @@ -354,7 +355,7 @@ Unit.prototype.to = function (valuelessUnit) { throw new Error('Units do not match'); } - other.value = this.value; + other.value = value; other.fixPrefix = true; return other; } @@ -367,7 +368,7 @@ Unit.prototype.to = function (valuelessUnit) { } other = valuelessUnit.clone(); - other.value = this.value; + other.value = value; other.fixPrefix = true; return other; } diff --git a/test/type/Unit.test.js b/test/type/Unit.test.js index 3ab90b6a7..c87186f07 100644 --- a/test/type/Unit.test.js +++ b/test/type/Unit.test.js @@ -178,6 +178,21 @@ describe('unit', function() { assert.equal(u2.fixPrefix, true); }); + it ('should convert a valueless unit', function () { + var u1 = new Unit(null, 'm'); + assert.equal(u1.value, null); + assert.equal(u1.unit.name, 'm'); + assert.equal(u1.prefix.name, ''); + assert.equal(u1.fixPrefix, false); + + var u2 = u1.to(new Unit(null, 'cm')); + assert.notStrictEqual(u1, u2); // u2 must be a clone + assert.equal(u2.value, 1); // u2 must have a value + assert.equal(u2.unit.name, 'm'); + assert.equal(u2.prefix.name, 'c'); + assert.equal(u2.fixPrefix, true); + }); + it ('should throw an error when converting to an incompatible unit', function () { var u1 = new Unit(5000, 'cm'); assert.throws(function () {u1.to('kg')}, /Units do not match/); @@ -243,8 +258,8 @@ describe('unit', function() { }); it('should format a unit with fixed prefix and without value', function() { - assert.equal(new Unit(null, 'cm').to('km').format(), 'km'); - assert.equal(new Unit(null, 'cm').to('inch').format(), 'inch'); + assert.equal(new Unit(null, 'km').to('cm').format(), '1e+5 cm'); + assert.equal(new Unit(null, 'inch').to('cm').format(), '2.54 cm'); }); it('should ignore properties in Object.prototype when finding the best prefix', function() { From 20b4ad2dd5e6cbc9e52fed98a13fa1a11779c7bb Mon Sep 17 00:00:00 2001 From: jos Date: Sun, 14 Dec 2014 14:03:16 +0100 Subject: [PATCH 12/19] Updated history --- HISTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/HISTORY.md b/HISTORY.md index 844dedcef..244b740ff 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -5,6 +5,7 @@ - Converting a unit without value will now result in a unit *with* value, i.e. `inch in cm` will return `2.54 cm` instead of `cm`. +- Improved accuracy of `sinh` and complex `cos` and `sin`. Thanks @pavpanchekha. ## 2014-11-22, version 1.1.1 From f36fbb39680eafa7e007e4d0f8a6b720bd7a42fb Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Mon, 15 Dec 2014 01:02:41 -0800 Subject: [PATCH 13/19] Added bitwise functions into the bignumber section of mathjs. Made more test cases as well. Shifts are not fully precise, but other bitwise opts are. --- lib/function/bitwise/bitAnd.js | 15 +- lib/function/bitwise/bitNot.js | 6 +- lib/function/bitwise/bitOr.js | 15 +- lib/function/bitwise/bitXor.js | 15 +- lib/function/bitwise/leftShift.js | 13 +- lib/function/bitwise/rightArithShift.js | 12 +- lib/util/bignumber.js | 489 ++++++++++++++++++ test/function/bitwise/bitAnd.test.js | 1 + test/function/bitwise/bitNot.test.js | 9 +- test/function/bitwise/leftShift.test.js | 10 + test/function/bitwise/rightArithShift.test.js | 8 + 11 files changed, 557 insertions(+), 36 deletions(-) diff --git a/lib/function/bitwise/bitAnd.js b/lib/function/bitwise/bitAnd.js index 42247e87d..ed0fe1be8 100644 --- a/lib/function/bitwise/bitAnd.js +++ b/lib/function/bitwise/bitAnd.js @@ -11,7 +11,9 @@ module.exports = function (math, config) { isBoolean = util['boolean'].isBoolean, isNumber = util.number.isNumber, isString = util.string.isString, - isCollection = collection.isCollection; + isCollection = collection.isCollection, + + bigBitAnd = util.bignumber.and; /** * Bitwise AND two values, `x & y`. @@ -67,8 +69,13 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - if (isNumber(y) || y instanceof BigNumber) { - return x.and(y); + // try to convert to big number + if (isNumber(y)) { + y = BigNumber.convert(y); + } + + if (y instanceof BigNumber) { + return bigBitAnd(x, y); } // downgrade to Number @@ -81,7 +88,7 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - return x.and(y); + return bigBitAnd(x, y); } // downgrade to Number diff --git a/lib/function/bitwise/bitNot.js b/lib/function/bitwise/bitNot.js index 4c8ce3774..03e1617d4 100644 --- a/lib/function/bitwise/bitNot.js +++ b/lib/function/bitwise/bitNot.js @@ -11,7 +11,9 @@ module.exports = function (math, config) { isBoolean = util['boolean'].isBoolean, isNumber = util.number.isNumber, isString = util.string.isString, - isCollection = collection.isCollection; + isCollection = collection.isCollection, + + bigBitNot = util.bignumber.not; /** * Bitwise NOT value, `~x`. @@ -45,7 +47,7 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - return x.not(); + return bigBitNot(x); } if (isCollection(x)) { diff --git a/lib/function/bitwise/bitOr.js b/lib/function/bitwise/bitOr.js index 88fcd94f8..564cdb1d2 100644 --- a/lib/function/bitwise/bitOr.js +++ b/lib/function/bitwise/bitOr.js @@ -11,7 +11,9 @@ module.exports = function (math, config) { isBoolean = util['boolean'].isBoolean, isNumber = util.number.isNumber, isString = util.string.isString, - isCollection = collection.isCollection; + isCollection = collection.isCollection, + + bigBitOr = util.bignumber.or; /** * Bitwise OR two values, `x | y`. @@ -68,8 +70,13 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - if (isNumber(y) || y instanceof BigNumber) { - return x.or(y); + // try to convert to big number + if (isNumber(y)) { + y = BigNumber.convert(y); + } + + if (y instanceof BigNumber) { + return bigBitOr(x, y); } // downgrade to Number @@ -82,7 +89,7 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - return x.or(y); + return bigBitOr(x, y); } // downgrade to Number diff --git a/lib/function/bitwise/bitXor.js b/lib/function/bitwise/bitXor.js index 93b119fb6..27339a96a 100644 --- a/lib/function/bitwise/bitXor.js +++ b/lib/function/bitwise/bitXor.js @@ -12,7 +12,9 @@ module.exports = function (math, config) { isNumber = util.number.isNumber, isString = util.string.isString, isUnit = Unit.isUnit, - isCollection = collection.isCollection; + isCollection = collection.isCollection, + + bigBitXor = util.bignumber.xor; /** * Bitwise XOR two values, `x ^ y`. @@ -68,8 +70,13 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - if (isNumber(y) || y instanceof BigNumber) { - return x.xor(y); + // try to convert to big number + if (isNumber(y)) { + y = BigNumber.convert(y); + } + + if (y instanceof BigNumber) { + return bigBitXor(x, y); } // downgrade to Number @@ -82,7 +89,7 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - return x.xor(y); + return bigBitXor(x, y); } // downgrade to Number diff --git a/lib/function/bitwise/leftShift.js b/lib/function/bitwise/leftShift.js index 959e5ef47..de591f37b 100644 --- a/lib/function/bitwise/leftShift.js +++ b/lib/function/bitwise/leftShift.js @@ -11,7 +11,9 @@ module.exports = function (math, config) { isBoolean = util['boolean'].isBoolean, isNumber = util.number.isNumber, isString = util.string.isString, - isCollection = collection.isCollection; + isCollection = collection.isCollection, + + bigLeftShift = util.bignumber.leftShift; /** * Bitwise left logical shift one value by another values, `x << y`. @@ -69,20 +71,15 @@ module.exports = function (math, config) { if (x instanceof BigNumber) { if (isNumber(y) || y instanceof BigNumber) { - return x.leftShift(y); + return bigLeftShift(x, y); } // downgrade to Number return leftShift(x.toNumber(), y); } if (y instanceof BigNumber) { - // try to convert to big number if (isNumber(x)) { - x = BigNumber.convert(x); - } - - if (x instanceof BigNumber) { - return x.leftShift(y); + return bigLeftShift(x, y); } // downgrade to Number diff --git a/lib/function/bitwise/rightArithShift.js b/lib/function/bitwise/rightArithShift.js index b9c9ea951..8750cfc1b 100644 --- a/lib/function/bitwise/rightArithShift.js +++ b/lib/function/bitwise/rightArithShift.js @@ -11,7 +11,9 @@ module.exports = function (math, config) { isBoolean = util['boolean'].isBoolean, isNumber = util.number.isNumber, isString = util.string.isString, - isCollection = collection.isCollection; + isCollection = collection.isCollection, + + bigRightShift = util.bignumber.rightShift; /** * Bitwise right arithmetic shift one value by another values, `x >> y`. @@ -69,7 +71,7 @@ module.exports = function (math, config) { if (x instanceof BigNumber) { if (isNumber(y) || y instanceof BigNumber) { - return x.rightShift(y); + return bigRightShift(x, y); } // downgrade to Number @@ -78,11 +80,7 @@ module.exports = function (math, config) { if (y instanceof BigNumber) { // try to convert to big number if (isNumber(x)) { - x = BigNumber.convert(x); - } - - if (x instanceof BigNumber) { - return x.rightShift(y); + return bigRightShift(x, y); } // downgrade to Number diff --git a/lib/util/bignumber.js b/lib/util/bignumber.js index 483670256..5ed7b98e5 100644 --- a/lib/util/bignumber.js +++ b/lib/util/bignumber.js @@ -13,6 +13,10 @@ exports.isBigNumber = function (value) { return (value instanceof BigNumber); }; + +/* BigNumber constants. */ + + /** * Calculate BigNumber e * @param {Number} precision @@ -98,6 +102,367 @@ exports.tau = function (precision) { return new Big(2).times(pi); }; + +/* BigNumber functions. */ + + +/* + * Special Cases: + * N & n = N + * n & 0 = 0 + * n & -1 = n + * n & n = n + * I & I = I + * -I & -I = -I + * I & -I = 0 + * I & n = n + * I & -n = I + * -I & n = 0 + * -I & -n = -I + * + * @param {BigNumber} value + * @param {BigNumber} value + * @return {BigNumber} Result of `x` & `y`, is fully precise + * + */ +exports.and = function(x, y) { + var BigNumber = x['constructor']; + if (x.isNaN() || y.isNaN()) { + return new BigNumber(NaN); + } + + x = x.trunc(); + y = y.trunc(); + if (x.isZero() || y.eq(-1) || x.eq(y)) { + return x; + } + if (y.isZero() || x.eq(-1)) { + return y; + } + + if (!x.isFinite() || !y.isFinite()) { + if (!x.isFinite() && !y.isFinite()) { + if (x.isNegative() == y.isNegtive()) { + return x; + } + return new BigNumber(0); + } + if (!x.isFinite()) { + if (y.isNegative()) { + return x; + } + if (x.isNegative()) { + return new BigNumber(0); + } + return y; + } + if (!y.isFinite()) { + if (x.isNegative()) { + return y; + } + if (y.isNegative()) { + return new BigNumber(0); + } + return x; + } + } + return bitwise(x, y, function (a, b) { return a & b }); +}; + +/* + * Special Cases: + * n << -n = N + * n << N = N + * N << n = N + * n << 0 = n + * 0 << n = 0 + * I << I = N + * I << n = I + * n << I = I + * + * @param {Number | BigNumber} value + * @param {Number | BigNumber} value + * @return {BigNumber} Result of `x` << `y` + * + */ +exports.leftShift = function (x, y) { + var BigNumber, truncY; + if (isNumber(x)) { + BigNumber = y['constructor']; + + if (y.isZero() && y.isNegative()) { + y['s'] = -y['s']; + } + + truncY = y.trunc(); + if (truncY.isNegative() && !truncY.isZero()) { + return new BigNumber(NaN); + } + + x = new BigNumber(x > 0 + ? Math.floor(x) + : Math.ceil(x)); + } else { + BigNumber = x['constructor']; + x = x.trunc(); + } + + if (isNumber(y)) { + y = y > 0 + ? Math.floor(y) + : Math.ceil(y); + + if (y < 0) { + return new BigNumber(NaN); + } + if (y == 0 || x == 0) { + return x; + } + if (y == Infinity && !x.isFinite()) { + return new BigNumber(NaN); + } + if (y < 55) { + return x.times(Math.pow(2, y) + ''); + } + return x.times(new BigNumber(2).pow(y)); + } + + if (!truncY) { + if (y.isNegative() && y.isZero()) { + y['s'] = -y['s']; + } + + truncY = y.trunc(); + if (truncY.isNegative() && !truncY.isZero()) { + return new BigNumber(NaN); + } + } + + if (x.isZero() || truncY.isZero()) { + return x; + } + if (!x.isFinite() && !truncY.isFinite()) { + return new BigNumber(NaN); + } + if (truncY.lt(55)) { + return x.times(Math.pow(2, truncY.toNumber()) + ''); + } + return x.times(new BigNumber(2).pow(truncY)); +}; + +/* + * @param {BigNumber} value + * @return {BigNumber} Result of ~`x`, fully precise + * + */ +exports.not = function (x) { + var BigNumber = x['constructor']; + var prevPrec = BigNumber['precision']; + BigNumber['precision'] = 1E9; + + var x = x.trunc().plus(BigNumber['ONE']); + x['s'] = -x['s'] || null; + + BigNumber['precision'] = prevPrec; + return x; +}; + +/* + * Special Cases: + * N | n = N + * n | 0 = n + * n | -1 = -1 + * n | n = n + * I | I = I + * -I | -I = -I + * I | -n = -1 + * I | -I = -1 + * I | n = I + * -I | n = -I + * -I | -n = -n + * + * @param {BigNumber} value + * @param {BigNumber} value + * @return {BigNumber} Result of `x` | `y`, fully precise + * + */ +exports.or = function (x, y) { + var BigNumber = x['constructor']; + if (x.isNaN() || y.isNaN()) { + return new BigNumber(NaN); + } + + x = x.trunc(); + y = y.trunc(); + if (x.isZero() || y.eq(-1) || x.eq(y)) { + return y; + } + if (y.isZero() || x.eq(-1)) { + return x; + } + + if (!x.isFinite() || !y.isFinite()) { + if ((!x.isFinite() && !x.isNegative() && y.isNegative()) || + (x.isNegative() && !y.isNegative() && !y.isFinite())) { + return new BigNumber(-1); + } + if (x.isNegative() && y.isNegative()) { + return x.isFinite() + ? x + : y; + } + return x.isFinite() + ? y + : x; + } + return bitwise(x, y, function (a, b) { return a | b }); +}; + +/* + * Special Cases: + * n >> -n = N + * n >> N = N + * N >> n = N + * I >> I = N + * n >> 0 = n + * I >> n = I + * -I >> n = -I + * -I >> I = -I + * n >> I = I + * -n >> I = -1 + * 0 >> n = 0 + * + * @param {Number | BigNumber} value + * @param {Number | BigNumber} value + * @return {BigNumber} Result of `x` >> `y` + * + */ +exports.rightShift = function (x, y) { + var BigNumber, truncY; + if (isNumber(x)) { + BigNumber = y['constructor']; + + if (y.isZero() && y.isNegative()) { + y['s'] = -y['s']; + } + + truncY = y.trunc(); + if (truncY.isNegative()) { + return new BigNumber(NaN); + } + + x = new BigNumber(x > 0 + ? Math.floor(x) + : Math.ceil(x)); + } else { + BigNumber = x['constructor']; + x = x.trunc(); + } + + if (isNumber(y)) { + y = y > 0 + ? Math.floor(y) + : Math.ceil(y); + + if (y < 0) { + return new BigNumber(NaN); + } + if (y == 0 || x == 0) { + return x; + } + if (x < 0 && y == Infinity) { + return new BigNumber(-1); + } + if (y == Infinity && !x.isFinite()) { + return new BigNumber(NaN); + } + if (y < 55) { + return x.div(Math.pow(2, y) + '').floor(); + } + return x.div(new BigNumber(2).pow(y)).floor(); + } + + if (!truncY) { + if (y.isNegative() && y.isZero()) { + y['s'] = -y['s']; + } + + truncY = y.trunc(); + if (truncY.isNegative()) { + return new BigNumber(NaN); + } + } + + if (x.isZero() || truncY.isZero()) { + return x; + } + if (x.isNegative() && !truncY.isFinite()) { + return new BigNumber(-1); + } + if (!x.isFinite() && !truncY.isFinite()) { + return new BigNumber(NaN); + } + if (truncY.lt(55)) { + return x.div(Math.pow(2, truncY.toNumber()) + '').floor(); + } + return x.div(new BigNumber(2).pow(truncY)).floor(); +}; + +/* + * Special Cases: + * N ^ n = N + * n ^ 0 = n + * n ^ n = 0 + * n ^ -1 = ~n + * I ^ n = I + * I ^ -n = -I + * I ^ -I = -1 + * -I ^ n = -I + * -I ^ -n = I + * + * @param {BigNumber} value + * @param {BigNumber} value + * @return {BigNumber} Result of `x` ^ `y`, fully precise + * + */ +exports.xor = function (x, y) { + var BigNumber = x['constructor']; + if (x.isNaN() || y.isNaN()) { + return new BigNumber(NaN); + } + + x = x.trunc(); + y = y.trunc(); + if (x.isZero()) { + return y; + } + if (y.isZero()) { + return x; + } + + if (x.eq(y)) { + return new BigNumber(0); + } + + if (x.eq(-1)) { + return exports.not(y); + } + if (y.eq(-1)) { + return exports.not(x); + } + + if (!x.isFinite() || !y.isFinite()) { + if (!x.isFinite() && !y.isFinite()) { + return new BigNumber(-1); + } + return new BigNumber(x.isNegative() == y.isNegative() + ? Infinity + : -Infinity); + } + return bitwise(x, y, function (a, b) { return a ^ b }); +}; + + /** * Convert a number to a formatted string representation. * @@ -281,3 +646,127 @@ exports.toFixed = function(value, precision) { // Note: the (precision || 0) is needed as the toFixed of BigNumber has an // undefined default precision instead of 0. }; + + +/* Private functions. */ + + +function bitwise(x, y, func) { + var BigNumber = x['constructor']; + + var xBits, yBits; + 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) { + xBits[i] ^= 1; + } + } else { + xBits = decToBinary(coefficientToString(x)); + } + if (ySign) { + yBits = decToBinary(coefficientToString(exports.not(y))); + for (var i = 0; i < yBits.length; ++i) { + yBits[i] ^= 1; + } + } else { + yBits = decToBinary(coefficientToString(y)); + } + + var minBits, maxBits, minSign; + if (xBits.length <= yBits.length) { + minBits = xBits; + maxBits = yBits; + minSign = xSign; + } else { + minBits = yBits; + maxBits = xBits; + minSign = ySign; + } + + var shortLen = minBits.length; + var longLen = maxBits.length; + var expFuncVal = func(xSign, ySign) ^ 1; + var outVal = new BigNumber(expFuncVal ^ 1); + var twoPower = BigNumber['ONE']; + var two = new BigNumber(2); + + var prevPrec = BigNumber['precision']; + BigNumber['precision'] = 1E9; + + while (shortLen > 0) { + if (func(minBits[--shortLen], maxBits[--longLen]) == expFuncVal) { + outVal = outVal.plus(twoPower); + } + twoPower = twoPower.times(two); + } + while (longLen > 0) { + if (func(minSign, maxBits[--longLen]) == expFuncVal) { + outVal = outVal.plus(twoPower); + } + twoPower = twoPower.times(two); + } + + BigNumber['precision'] = prevPrec; + + if (expFuncVal == 0) { + outVal['s'] = -outVal['s']; + } + return outVal; +} + + +/* Private functions extracted from decimal.js, and edited to specialize. */ + + +function coefficientToString(x) { + var a = x['c']; + var r = a[0] + ''; + + for (var i = 1; i < a.length; ++i) { + var s = a[i] + ''; + for (var z = 7 - s.length; z--; ) { + s = '0' + s; + } + + r += s; + } + + var j; + for (j = r.length - 1; r.charAt(j) == '0'; --j); + + var xe = x['e']; + var str = r.slice(0, j + 1 || 1); + var strL = str.length; + if (xe > 0) { + if (++xe > strL) { + // Append zeros. + for (xe -= strL; xe--; str += '0'); + } else if (xe < strL) { + str = str.slice(0, xe) + '.' + str.slice(xe); + } + } + return str; +} + +function decToBinary(str) { + var arr = [0]; + for (var i = 0; i < str.length; ) { + for (var arrL = arr.length; arrL--; arr[arrL] *= 10); + + arr[0] += str.charAt(i++) << 0; // convert to int + for (var j = 0; j < arr.length; ++j) { + if (arr[j] > 1) { + if (arr[j + 1] == null) { + arr[j + 1] = 0; + } + + arr[j + 1] += arr[j] >> 1; + arr[j] &= 1; + } + } + } + + return arr.reverse(); +} diff --git a/test/function/bitwise/bitAnd.test.js b/test/function/bitwise/bitAnd.test.js index 9490baaa1..a15ed0a05 100644 --- a/test/function/bitwise/bitAnd.test.js +++ b/test/function/bitwise/bitAnd.test.js @@ -41,6 +41,7 @@ describe('bitAnd', function () { assert.deepEqual(bitAnd(bignumber('1.0e+31'), bignumber('1.0e+32')), bignumber('8726602014714682917961003433984')); assert.deepEqual(bitAnd(bignumber('-1.0e+31'), bignumber('1.0e+32')), bignumber('91273397985285317082038996566016')); assert.deepEqual(bitAnd(bignumber('1.0e+31'), bignumber('-1.0e+32')), bignumber('1273397985285317082036849082368')); + assert.deepEqual(bitAnd(bignumber('2.1877409333271352879E+75'), bignumber('-3.220131224058161211554E+42')), bignumber('2187740933327135287899999999999996863578490213829130431270426161710498840576')); }); it('should bitwise and mixed numbers and bignumbers', function () { diff --git a/test/function/bitwise/bitNot.test.js b/test/function/bitwise/bitNot.test.js index c79034e27..d354e932d 100644 --- a/test/function/bitwise/bitNot.test.js +++ b/test/function/bitwise/bitNot.test.js @@ -21,21 +21,16 @@ describe('bitNot', function () { assert.equal(bitNot('-86e2'), 8599); }); - it('should return bignumber bitwise not on a string', function() { - assert.deepEqual(bitNot(bignumber('2')), bignumber(-3)); - assert.deepEqual(bitNot(bignumber('-2')), bignumber(1)); - assert.deepEqual(bitNot(bignumber('1.2345e30')), bignumber('-1234500000000000000000000000001')); - }); - it('should perform bitwise not of a number', function () { assert.deepEqual(bitNot(2), -3); assert.deepEqual(bitNot(-2), 1); assert.deepEqual(bitNot(0), -1); }); - it('should perform bitwise not of a big number', function() { + it('should perform bitwise not of a bignumber', function() { assert.deepEqual(bitNot(bignumber(2)), bignumber(-3)); assert.deepEqual(bitNot(bignumber(-2)), bignumber(1)); + assert.deepEqual(bitNot(bignumber('1.2345e30')), bignumber('-1234500000000000000000000000001')); }); it('should throw an error if used with a unit', function() { diff --git a/test/function/bitwise/leftShift.test.js b/test/function/bitwise/leftShift.test.js index 0f487b50f..eaed4fb10 100644 --- a/test/function/bitwise/leftShift.test.js +++ b/test/function/bitwise/leftShift.test.js @@ -1,5 +1,6 @@ // test leftShift var assert = require('assert'), + approx = require('../../../tools/approx'), error = require('../../../lib/error/index'), math = require('../../../index'), bignumber = math.bignumber, @@ -41,13 +42,22 @@ 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(-1.9), bignumber(2.9)), bignumber(-4)); + assert.deepEqual(leftShift(bignumber(0), bignumber(-2)).toString(), 'NaN'); + assert.deepEqual(leftShift(bignumber(Infinity), bignumber(2)), bignumber(Infinity)); + assert.deepEqual(leftShift(bignumber(Infinity), bignumber(Infinity)).toString(), 'NaN'); }); it('should left shift mixed numbers and bignumbers', function () { assert.deepEqual(leftShift(bignumber(2), 3), bignumber(16)); + assert.deepEqual(leftShift(bignumber(500), 100), bignumber('633825300114114700748351602688000')); assert.deepEqual(leftShift(2, bignumber(3)), bignumber(16)); assert.deepEqual(leftShift(-1, bignumber(2)), bignumber(-4)); + assert.deepEqual(leftShift(-1.9, bignumber(2.9)), bignumber(-4)); assert.deepEqual(leftShift(bignumber(-1), 2), bignumber(-4)); + assert.deepEqual(leftShift(bignumber(-1.9), 2.9), bignumber(-4)); + assert.deepEqual(leftShift(bignumber(0), -2).toString(), 'NaN'); + assert.deepEqual(leftShift(bignumber(Infinity), Infinity).toString(), 'NaN'); }); it('should left shift mixed booleans and bignumbers', function () { diff --git a/test/function/bitwise/rightArithShift.test.js b/test/function/bitwise/rightArithShift.test.js index 86c9817b6..241085582 100644 --- a/test/function/bitwise/rightArithShift.test.js +++ b/test/function/bitwise/rightArithShift.test.js @@ -51,13 +51,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.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.deepEqual(rightArithShift(17, bignumber(3)), bignumber(2)); assert.deepEqual(rightArithShift(-17, bignumber(3)), bignumber(-3)); + assert.deepEqual(rightArithShift(-3, bignumber(-17)).toString(), 'NaN'); + assert.deepEqual(rightArithShift(bignumber(-Infinity), Infinity), bignumber(-1)); + assert.deepEqual(rightArithShift(bignumber(Infinity), Infinity).toString(), 'NaN'); + assert.deepEqual(rightArithShift(Infinity, bignumber(Infinity)).toString(), 'NaN'); }); it('should right arithmetically shift mixed booleans and bignumbers', function () { From 6c1197f6462c4a8f827ee82ba1bc35deb6781c1c Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Mon, 15 Dec 2014 03:43:10 -0800 Subject: [PATCH 14/19] Added '~' to the parser. --- lib/expression/parse.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/expression/parse.js b/lib/expression/parse.js index 8ac715213..5382be573 100644 --- a/lib/expression/parse.js +++ b/lib/expression/parse.js @@ -116,6 +116,7 @@ var DELIMITERS = { '%': true, '^': true, '.^': true, + '~': true, '!': true, '\'': true, '=': true, @@ -810,10 +811,15 @@ function parseMultiplyDivide () { */ function parseUnary () { var name, fn, params; + var unaryTokens = { + '-': 'unaryMinus', + '+': 'unaryPlus', + '~': 'bitNot' + }; - if (token == '-' || token == '+') { + fn = unaryTokens[token]; + if (fn) { name = token; - fn = name == '+' ? 'unaryPlus' : 'unaryMinus'; getTokenSkipNewline(); params = [parseUnary()]; From e73df489384fa1eddc30950cbee9b6c8376670ea Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Mon, 15 Dec 2014 04:00:52 -0800 Subject: [PATCH 15/19] Removed fail test case for now functioning token '~'. Added test cases for it as well. --- test/expression/parse.test.js | 37 +++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/test/expression/parse.test.js b/test/expression/parse.test.js index b1235aa0b..94bba6935 100644 --- a/test/expression/parse.test.js +++ b/test/expression/parse.test.js @@ -123,7 +123,6 @@ describe('parse', function() { it('should give informative syntax errors', function() { assert.throws(function () {parse('2 +')}, /Unexpected end of expression \(char 4\)/); - assert.throws(function () {parse('2 ~ 3')}, /Syntax error in part "~ 3" \(char 3\)/); assert.throws(function () {parse('2 + 3 + *')}, /Value expected \(char 9\)/); }); @@ -858,13 +857,47 @@ describe('parse', function() { assert.equal(parseAndEval('5++3'), 8); }); + it('should parse unary ~', function() { + assert.equal(parseAndEval('~2'), -3); + assert.equal(parseAndEval('~~2'), 2); + assert.equal(parseAndEval('~~~2'), -3); + assert.equal(parseAndEval('~true'), -2); + + assert.equal(parseAndEval('4*~2'), -12); + assert.equal(parseAndEval('4 * ~2'), -12); + assert.equal(parseAndEval('4-~2'), 7); + assert.equal(parseAndEval('4 - ~2'), 7); + assert.equal(parseAndEval('4+~2'), 1); + assert.equal(parseAndEval('4 + ~2'), 1); + + assert.equal(parseAndEval('10+~3'), 6); + }); + it('should parse unary plus and minus +, -', function() { assert.equal(parseAndEval('-+2'), -2); assert.equal(parseAndEval('-+-2'), 2); assert.equal(parseAndEval('+-+-2'), 2); assert.equal(parseAndEval('+-2'), -2); assert.equal(parseAndEval('+-+2'), -2); - assert.equal(parseAndEval('+-+-2'), 2); + assert.equal(parseAndEval('-+-+2'), 2); + }); + + it('should parse unary plus and bitwise not +, ~', function() { + assert.equal(parseAndEval('~+2'), -3); + assert.equal(parseAndEval('~+~2'), 2); + assert.equal(parseAndEval('+~+~2'), 2); + assert.equal(parseAndEval('+~2'), -3); + assert.equal(parseAndEval('+~+2'), -3); + assert.equal(parseAndEval('~+~+2'), 2); + }); + + it('should parse unary minus and bitwise not -, ~', function() { + assert.equal(parseAndEval('~-2'), 1); + assert.equal(parseAndEval('~-~2'), -4); + assert.equal(parseAndEval('-~-~2'), 4); + assert.equal(parseAndEval('-~2'), 3); + assert.equal(parseAndEval('-~-2'), -1); + assert.equal(parseAndEval('~-~-2'), 0); }); it('should parse unequal !=', function() { From b8b7c92ae12c9c4f39bba43377a179f3554b9a2f Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Mon, 15 Dec 2014 16:00:28 -0800 Subject: [PATCH 16/19] Moved type specific computation outside of the bignumber library, and made more style touchups. --- lib/function/bitwise/bitAnd.js | 8 +- lib/function/bitwise/bitNot.js | 4 +- lib/function/bitwise/bitOr.js | 8 +- lib/function/bitwise/bitXor.js | 8 +- lib/function/bitwise/leftShift.js | 59 ++++++-- lib/function/bitwise/rightArithShift.js | 61 ++++++-- lib/function/bitwise/rightLogShift.js | 8 +- lib/util/bignumber.js | 189 ++++++------------------ 8 files changed, 160 insertions(+), 185 deletions(-) diff --git a/lib/function/bitwise/bitAnd.js b/lib/function/bitwise/bitAnd.js index ed0fe1be8..10988be57 100644 --- a/lib/function/bitwise/bitAnd.js +++ b/lib/function/bitwise/bitAnd.js @@ -52,13 +52,13 @@ module.exports = function (math, config) { if (isString(x)) { return bitAnd((config.number === 'bignumber') - ? new BigNumber(x) - : +x, y); + ? BigNumber.convert(x) + : +x, y); } if (isString(y)) { return bitAnd(x, (config.number === 'bignumber') - ? new BigNumber(y) - : +y); + ? BigNumber.convert(y) + : +y); } if (isBoolean(x) || x === null) { diff --git a/lib/function/bitwise/bitNot.js b/lib/function/bitwise/bitNot.js index 03e1617d4..f89b8ac00 100644 --- a/lib/function/bitwise/bitNot.js +++ b/lib/function/bitwise/bitNot.js @@ -56,8 +56,8 @@ module.exports = function (math, config) { if (isString(x)) { return bitNot((config.number === 'bignumber') - ? new BigNumber(x) - : +x); + ? BigNumber.convert(x) + : +x); } if (isBoolean(x) || x === null) { diff --git a/lib/function/bitwise/bitOr.js b/lib/function/bitwise/bitOr.js index 564cdb1d2..07693e2fd 100644 --- a/lib/function/bitwise/bitOr.js +++ b/lib/function/bitwise/bitOr.js @@ -53,13 +53,13 @@ module.exports = function (math, config) { if (isString(x)) { return bitOr((config.number === 'bignumber') - ? new BigNumber(x) - : +x, y); + ? BigNumber.convert(x) + : +x, y); } if (isString(y)) { return bitOr(x, (config.number === 'bignumber') - ? new BigNumber(y) - : +y); + ? BigNumber.convert(y) + : +y); } if (isBoolean(x) || x === null) { diff --git a/lib/function/bitwise/bitXor.js b/lib/function/bitwise/bitXor.js index 27339a96a..ea44b50e9 100644 --- a/lib/function/bitwise/bitXor.js +++ b/lib/function/bitwise/bitXor.js @@ -53,13 +53,13 @@ module.exports = function (math, config) { if (isString(x)) { return bitXor((config.number === 'bignumber') - ? new BigNumber(x) - : +x, y); + ? BigNumber.convert(x) + : +x, y); } if (isString(y)) { return bitXor(x, (config.number === 'bignumber') - ? new BigNumber(y) - : +y); + ? BigNumber.convert(y) + : +y); } if (isBoolean(x) || x === null) { diff --git a/lib/function/bitwise/leftShift.js b/lib/function/bitwise/leftShift.js index de591f37b..c35bc46bf 100644 --- a/lib/function/bitwise/leftShift.js +++ b/lib/function/bitwise/leftShift.js @@ -43,8 +43,45 @@ module.exports = function (math, config) { throw new math.error.ArgumentsError('leftShift', arguments.length, 2); } - if (isNumber(x) && isNumber(y)) { - return x << y; + if (isNumber(x)) { + if (isNumber(y)) { + return x << y; + } + + if (y instanceof BigNumber) { + // truncate x and y + return bigLeftShift(BigNumber.convert((x > 0) + ? Math.floor(x) + : Math.ceil(x)), y.trunc()); + } + } + if (isNumber(y)) { + if (x instanceof BigNumber) { + // delay converting y to BigNumber; take advantage of Number speed + y = (y > 0) + ? Math.floor(y) + : Math.ceil(y); + + if (x.isNaN() || isNaN(y) || y < 0) { + return new BigNumber(NaN); + } + + x = x.trunc(); + if (y == 0 || x.isZero()) { + return x; + } + if (y == Infinity && !x.isFinite()) { + return new BigNumber(NaN); + } + + // Math.pow(2, y) is fully precise for y < 55, and fast + if (y < 55) { + return x.times(Math.pow(2, y) + ''); + } + + y = BigNumber.convert(y); + return bigLeftShift(x, y); + } } if (isCollection(x) && isNumber(y)) { @@ -53,13 +90,13 @@ module.exports = function (math, config) { if (isString(x)) { return leftShift((config.number === 'bignumber') - ? new BigNumber(x) - : +x, y); + ? BigNumber.convert(x) + : +x, y); } if (isString(y)) { return leftShift(x, (config.number === 'bignumber') - ? new BigNumber(y) - : +y); + ? BigNumber.convert(y) + : +y); } if (isBoolean(x) || x === null) { @@ -70,19 +107,15 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - if (isNumber(y) || y instanceof BigNumber) { - return bigLeftShift(x, y); + if (y instanceof BigNumber) { + return bigLeftShift(x.trunc(), y.trunc()); } // downgrade to Number return leftShift(x.toNumber(), y); } if (y instanceof BigNumber) { - if (isNumber(x)) { - return bigLeftShift(x, y); - } - - // downgrade to Number + // x is probably incompatible with BigNumber return leftShift(x, y.toNumber()); } diff --git a/lib/function/bitwise/rightArithShift.js b/lib/function/bitwise/rightArithShift.js index 8750cfc1b..b76e659b8 100644 --- a/lib/function/bitwise/rightArithShift.js +++ b/lib/function/bitwise/rightArithShift.js @@ -43,8 +43,46 @@ module.exports = function (math, config) { throw new math.error.ArgumentsError('rightArithShift', arguments.length, 2); } - if (isNumber(x) && isNumber(y)) { - return x >> y; + if (isNumber(x)) { + if (isNumber(y)) { + return x >> y; + } + + if (y instanceof BigNumber) { + // truncate x and y + return bigRightShift(BigNumber.convert((x > 0) + ? Math.floor(x) + : Math.ceil(x)), y.trunc()); + } + } + if (isNumber(y)) { + if (x instanceof BigNumber) { + // delay converting y to BigNumber; take advantage of Number speed + y = (y > 0) + ? Math.floor(y) + : Math.ceil(y); + + if (x.isNaN() || isNaN(y) || y < 0) { + return new BigNumber(NaN); + } + if (y == Infinity) { + if (x.isNegative()) { + return new BigNumber(-1); + } + if (!x.isFinite()) { + return new BigNumber(NaN); + } + return new BigNumber(0); + } + + // Math.pow(2, y) is fully precise for y < 55, and fast + if (y < 55) { + return x.div(Math.pow(2, y) + '').floor(); + } + + y = BigNumber.convert(y); + return bigRightShift(x, y); + } } if (isCollection(x) && isNumber(y)) { @@ -53,13 +91,13 @@ module.exports = function (math, config) { if (isString(x)) { return rightArithShift((config.number === 'bignumber') - ? new BigNumber(x) - : +x, y); + ? BigNumber.convert(x) + : +x, y); } if (isString(y)) { return rightArithShift(x, (config.number === 'bignumber') - ? new BigNumber(y) - : +y); + ? BigNumber.convert(y) + : +y); } if (isBoolean(x) || x === null) { @@ -70,20 +108,15 @@ module.exports = function (math, config) { } if (x instanceof BigNumber) { - if (isNumber(y) || y instanceof BigNumber) { - return bigRightShift(x, y); + if (y instanceof BigNumber) { + return bigRightShift(x.trunc(), y.trunc()); } // downgrade to Number return rightArithShift(x.toNumber(), y); } if (y instanceof BigNumber) { - // try to convert to big number - if (isNumber(x)) { - return bigRightShift(x, y); - } - - // downgrade to Number + // x is probably incompatible with BigNumber return rightArithShift(x, y.toNumber()); } diff --git a/lib/function/bitwise/rightLogShift.js b/lib/function/bitwise/rightLogShift.js index 02974a2d7..48eac405b 100644 --- a/lib/function/bitwise/rightLogShift.js +++ b/lib/function/bitwise/rightLogShift.js @@ -50,13 +50,13 @@ module.exports = function (math, config) { if (isString(x)) { return rightLogShift((config.number === 'bignumber') - ? new BigNumber(x) - : +x, y); + ? BigNumber.convert(x) + : +x, y); } if (isString(y)) { return rightLogShift(x, (config.number === 'bignumber') - ? new BigNumber(y) - : +y); + ? BigNumber.convert(y) + : +y); } if (isBoolean(x) || x === null) { diff --git a/lib/util/bignumber.js b/lib/util/bignumber.js index 5ed7b98e5..9da968278 100644 --- a/lib/util/bignumber.js +++ b/lib/util/bignumber.js @@ -180,74 +180,29 @@ exports.and = function(x, y) { * I << n = I * n << I = I * - * @param {Number | BigNumber} value - * @param {Number | BigNumber} value + * @param {BigNumber} value + * @param {BigNumber} value * @return {BigNumber} Result of `x` << `y` * */ exports.leftShift = function (x, y) { - var BigNumber, truncY; - if (isNumber(x)) { - BigNumber = y['constructor']; + var BigNumber = x['constructor']; - if (y.isZero() && y.isNegative()) { - y['s'] = -y['s']; - } - - truncY = y.trunc(); - if (truncY.isNegative() && !truncY.isZero()) { - return new BigNumber(NaN); - } - - x = new BigNumber(x > 0 - ? Math.floor(x) - : Math.ceil(x)); - } else { - BigNumber = x['constructor']; - x = x.trunc(); - } - - if (isNumber(y)) { - y = y > 0 - ? Math.floor(y) - : Math.ceil(y); - - if (y < 0) { - return new BigNumber(NaN); - } - if (y == 0 || x == 0) { - return x; - } - if (y == Infinity && !x.isFinite()) { - return new BigNumber(NaN); - } - if (y < 55) { - return x.times(Math.pow(2, y) + ''); - } - return x.times(new BigNumber(2).pow(y)); - } - - if (!truncY) { - if (y.isNegative() && y.isZero()) { - y['s'] = -y['s']; - } - - truncY = y.trunc(); - if (truncY.isNegative() && !truncY.isZero()) { - return new BigNumber(NaN); - } - } - - if (x.isZero() || truncY.isZero()) { - return x; - } - if (!x.isFinite() && !truncY.isFinite()) { + if (x.isNaN() || y.isNaN() || (y.isNegative() && !y.isZero())) { return new BigNumber(NaN); } - if (truncY.lt(55)) { - return x.times(Math.pow(2, truncY.toNumber()) + ''); + if (x.isZero() || y.isZero()) { + return x; } - return x.times(new BigNumber(2).pow(truncY)); + if (!x.isFinite() && !y.isFinite()) { + return new BigNumber(NaN); + } + + // Math.pow(2, y) is fully precise for y < 55, and fast + if (y.lt(55)) { + return x.times(Math.pow(2, y.toNumber()) + ''); + } + return x.times(new BigNumber(2).pow(y)); }; /* @@ -294,26 +249,24 @@ exports.or = function (x, y) { x = x.trunc(); y = y.trunc(); - if (x.isZero() || y.eq(-1) || x.eq(y)) { + + var negOne = new BigNumber(-1); + if (x.isZero() || y.eq(negOne) || x.eq(y)) { return y; } - if (y.isZero() || x.eq(-1)) { + if (y.isZero() || x.eq(negOne)) { return x; } if (!x.isFinite() || !y.isFinite()) { if ((!x.isFinite() && !x.isNegative() && y.isNegative()) || (x.isNegative() && !y.isNegative() && !y.isFinite())) { - return new BigNumber(-1); + return negOne; } if (x.isNegative() && y.isNegative()) { - return x.isFinite() - ? x - : y; + return x.isFinite() ? x : y; } - return x.isFinite() - ? y - : x; + return x.isFinite() ? y : x; } return bitwise(x, y, function (a, b) { return a | b }); }; @@ -332,80 +285,35 @@ exports.or = function (x, y) { * -n >> I = -1 * 0 >> n = 0 * - * @param {Number | BigNumber} value - * @param {Number | BigNumber} value + * @param {BigNumber} value + * @param {BigNumber} value * @return {BigNumber} Result of `x` >> `y` * */ exports.rightShift = function (x, y) { - var BigNumber, truncY; - if (isNumber(x)) { - BigNumber = y['constructor']; + var BigNumber = x['constructor']; - if (y.isZero() && y.isNegative()) { - y['s'] = -y['s']; - } - - truncY = y.trunc(); - if (truncY.isNegative()) { - return new BigNumber(NaN); - } - - x = new BigNumber(x > 0 - ? Math.floor(x) - : Math.ceil(x)); - } else { - BigNumber = x['constructor']; - x = x.trunc(); - } - - if (isNumber(y)) { - y = y > 0 - ? Math.floor(y) - : Math.ceil(y); - - if (y < 0) { - return new BigNumber(NaN); - } - if (y == 0 || x == 0) { - return x; - } - if (x < 0 && y == Infinity) { - return new BigNumber(-1); - } - if (y == Infinity && !x.isFinite()) { - return new BigNumber(NaN); - } - if (y < 55) { - return x.div(Math.pow(2, y) + '').floor(); - } - return x.div(new BigNumber(2).pow(y)).floor(); - } - - if (!truncY) { - if (y.isNegative() && y.isZero()) { - y['s'] = -y['s']; - } - - truncY = y.trunc(); - if (truncY.isNegative()) { - return new BigNumber(NaN); - } - } - - if (x.isZero() || truncY.isZero()) { - return x; - } - if (x.isNegative() && !truncY.isFinite()) { - return new BigNumber(-1); - } - if (!x.isFinite() && !truncY.isFinite()) { + if (x.isNaN() || y.isNaN() || (y.isNegative() && !y.isZero())) { return new BigNumber(NaN); } - if (truncY.lt(55)) { - return x.div(Math.pow(2, truncY.toNumber()) + '').floor(); + if (x.isZero() || y.isZero()) { + return x; } - return x.div(new BigNumber(2).pow(truncY)).floor(); + if (!y.isFinite()) { + if (x.isNegative()) { + return new BigNumber(-1); + } + if (!x.isFinite()) { + return new BigNumber(NaN); + } + return new BigNumber(0); + } + + // Math.pow(2, y) is fully precise for y < 55, and fast + if (y.lt(55)) { + return x.div(Math.pow(2, y.toNumber()) + '').floor(); + } + return x.div(new BigNumber(2).pow(y)).floor(); }; /* @@ -444,20 +352,21 @@ exports.xor = function (x, y) { return new BigNumber(0); } - if (x.eq(-1)) { + var negOne = new BigNumber(-1); + if (x.eq(negOne)) { return exports.not(y); } - if (y.eq(-1)) { + if (y.eq(negOne)) { return exports.not(x); } if (!x.isFinite() || !y.isFinite()) { if (!x.isFinite() && !y.isFinite()) { - return new BigNumber(-1); + return negOne; } return new BigNumber(x.isNegative() == y.isNegative() - ? Infinity - : -Infinity); + ? Infinity + : -Infinity); } return bitwise(x, y, function (a, b) { return a ^ b }); }; From 6c21826b4b67db41e079ce981593cce1c09c8008 Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Tue, 16 Dec 2014 02:56:15 -0800 Subject: [PATCH 17/19] Prohibit usage of integers. --- lib/function/bitwise/bitAnd.js | 7 +++- lib/function/bitwise/bitNot.js | 5 +++ lib/function/bitwise/bitOr.js | 5 +++ lib/function/bitwise/bitXor.js | 5 +++ lib/function/bitwise/leftShift.js | 24 +++++++------ lib/function/bitwise/rightArithShift.js | 23 +++++++----- lib/function/bitwise/rightLogShift.js | 5 +++ lib/util/bignumber.js | 36 +++++++++++++------ test/function/bitwise/bitAnd.test.js | 30 ++++++++++++++++ test/function/bitwise/bitNot.test.js | 12 +++++++ test/function/bitwise/bitOr.test.js | 30 ++++++++++++++++ test/function/bitwise/bitXor.test.js | 30 ++++++++++++++++ test/function/bitwise/leftShift.test.js | 33 +++++++++++++++-- test/function/bitwise/rightArithShift.test.js | 30 ++++++++++++++++ test/function/bitwise/rightLogShift.test.js | 21 +++++++++++ 15 files changed, 262 insertions(+), 34 deletions(-) diff --git a/lib/function/bitwise/bitAnd.js b/lib/function/bitwise/bitAnd.js index 10988be57..d929d7da8 100644 --- a/lib/function/bitwise/bitAnd.js +++ b/lib/function/bitwise/bitAnd.js @@ -9,6 +9,7 @@ module.exports = function (math, config) { collection = require('../../type/collection'), isBoolean = util['boolean'].isBoolean, + isInteger = util.number.isInteger, isNumber = util.number.isNumber, isString = util.string.isString, isCollection = collection.isCollection, @@ -43,6 +44,10 @@ module.exports = function (math, config) { } if (isNumber(x) && isNumber(y)) { + if (!isInteger(x) || !isInteger(y)) { + throw new Error('Parameters in function bitAnd must be integer numbers'); + } + return x & y; } @@ -73,7 +78,7 @@ module.exports = function (math, config) { if (isNumber(y)) { y = BigNumber.convert(y); } - + if (y instanceof BigNumber) { return bigBitAnd(x, y); } diff --git a/lib/function/bitwise/bitNot.js b/lib/function/bitwise/bitNot.js index f89b8ac00..ca9e31489 100644 --- a/lib/function/bitwise/bitNot.js +++ b/lib/function/bitwise/bitNot.js @@ -9,6 +9,7 @@ module.exports = function (math, config) { collection = require('../../type/collection'), isBoolean = util['boolean'].isBoolean, + isInteger = util.number.isInteger, isNumber = util.number.isNumber, isString = util.string.isString, isCollection = collection.isCollection, @@ -43,6 +44,10 @@ module.exports = function (math, config) { } if (isNumber(x)) { + if (!isInteger(x)) { + throw new Error('Parameter in function bitNot must be integer numbers'); + } + return ~x; } diff --git a/lib/function/bitwise/bitOr.js b/lib/function/bitwise/bitOr.js index 07693e2fd..bceb40cee 100644 --- a/lib/function/bitwise/bitOr.js +++ b/lib/function/bitwise/bitOr.js @@ -9,6 +9,7 @@ module.exports = function (math, config) { collection = require('../../type/collection'), isBoolean = util['boolean'].isBoolean, + isInteger = util.number.isInteger, isNumber = util.number.isNumber, isString = util.string.isString, isCollection = collection.isCollection, @@ -44,6 +45,10 @@ module.exports = function (math, config) { } if (isNumber(x) && isNumber(y)) { + if (!isInteger(x) || !isInteger(y)) { + throw new Error('Parameters in function bitOr must be integer numbers'); + } + return x | y; } diff --git a/lib/function/bitwise/bitXor.js b/lib/function/bitwise/bitXor.js index ea44b50e9..23968fa60 100644 --- a/lib/function/bitwise/bitXor.js +++ b/lib/function/bitwise/bitXor.js @@ -9,6 +9,7 @@ module.exports = function (math, config) { collection = require('../../type/collection'), isBoolean = util['boolean'].isBoolean, + isInteger = util.number.isInteger, isNumber = util.number.isNumber, isString = util.string.isString, isUnit = Unit.isUnit, @@ -44,6 +45,10 @@ module.exports = function (math, config) { } if (isNumber(x) && isNumber(y)) { + if (!isInteger(x) || !isInteger(y)) { + throw new Error('Parameters in function bitXor must be integer numbers'); + } + return x ^ y; } diff --git a/lib/function/bitwise/leftShift.js b/lib/function/bitwise/leftShift.js index c35bc46bf..662b31862 100644 --- a/lib/function/bitwise/leftShift.js +++ b/lib/function/bitwise/leftShift.js @@ -9,6 +9,7 @@ module.exports = function (math, config) { collection = require('../../type/collection'), isBoolean = util['boolean'].isBoolean, + isInteger = util.number.isInteger, isNumber = util.number.isNumber, isString = util.string.isString, isCollection = collection.isCollection, @@ -45,28 +46,31 @@ module.exports = function (math, config) { if (isNumber(x)) { if (isNumber(y)) { + if (!isInteger(x) || !isInteger(y)) { + throw new Error('Parameters in function leftShift must be integer numbers'); + } + return x << y; } if (y instanceof BigNumber) { - // truncate x and y - return bigLeftShift(BigNumber.convert((x > 0) - ? Math.floor(x) - : Math.ceil(x)), y.trunc()); + return bigLeftShift(BigNumber.convert(x), y); } } if (isNumber(y)) { + if (isFinite(y) && !isInteger(y)) { + throw new Error('Parameters in function leftShift must be integer numbers'); + } + if (x instanceof BigNumber) { - // delay converting y to BigNumber; take advantage of Number speed - y = (y > 0) - ? Math.floor(y) - : Math.ceil(y); + if (x.isFinite() && !x.isInteger()) { + throw new Error('Parameters in function leftShift must be integer numbers'); + } if (x.isNaN() || isNaN(y) || y < 0) { return new BigNumber(NaN); } - x = x.trunc(); if (y == 0 || x.isZero()) { return x; } @@ -108,7 +112,7 @@ module.exports = function (math, config) { if (x instanceof BigNumber) { if (y instanceof BigNumber) { - return bigLeftShift(x.trunc(), y.trunc()); + return bigLeftShift(x, y); } // downgrade to Number diff --git a/lib/function/bitwise/rightArithShift.js b/lib/function/bitwise/rightArithShift.js index b76e659b8..b795cb9da 100644 --- a/lib/function/bitwise/rightArithShift.js +++ b/lib/function/bitwise/rightArithShift.js @@ -9,6 +9,7 @@ module.exports = function (math, config) { collection = require('../../type/collection'), isBoolean = util['boolean'].isBoolean, + isInteger = util.number.isInteger, isNumber = util.number.isNumber, isString = util.string.isString, isCollection = collection.isCollection, @@ -45,22 +46,26 @@ module.exports = function (math, config) { if (isNumber(x)) { if (isNumber(y)) { + if (!isInteger(x) || !isInteger(y)) { + throw new Error('Parameters in function rightArithShift must be integer numbers'); + } + return x >> y; } if (y instanceof BigNumber) { - // truncate x and y - return bigRightShift(BigNumber.convert((x > 0) - ? Math.floor(x) - : Math.ceil(x)), y.trunc()); + return bigRightShift(BigNumber.convert(x), y); } } if (isNumber(y)) { + if (isFinite(y) && !isInteger(y)) { + throw new Error('Parameters in function rightArithShift must be integer numbers'); + } + if (x instanceof BigNumber) { - // delay converting y to BigNumber; take advantage of Number speed - y = (y > 0) - ? Math.floor(y) - : Math.ceil(y); + if (x.isFinite() && !x.isInteger()) { + throw new Error('Parameters in function rightArithShift must be integer numbers'); + } if (x.isNaN() || isNaN(y) || y < 0) { return new BigNumber(NaN); @@ -109,7 +114,7 @@ module.exports = function (math, config) { if (x instanceof BigNumber) { if (y instanceof BigNumber) { - return bigRightShift(x.trunc(), y.trunc()); + return bigRightShift(x, y); } // downgrade to Number diff --git a/lib/function/bitwise/rightLogShift.js b/lib/function/bitwise/rightLogShift.js index 48eac405b..54ad5c380 100644 --- a/lib/function/bitwise/rightLogShift.js +++ b/lib/function/bitwise/rightLogShift.js @@ -8,6 +8,7 @@ module.exports = function (math, config) { collection = require('../../type/collection'), isBoolean = util['boolean'].isBoolean, + isInteger = util.number.isInteger, isNumber = util.number.isNumber, isString = util.string.isString, isCollection = collection.isCollection; @@ -41,6 +42,10 @@ module.exports = function (math, config) { } if (isNumber(x) && isNumber(y)) { + if (!isInteger(x) || !isInteger(y)) { + throw new Error('Parameters in function rightLogShift must be integer numbers'); + } + return x >>> y; } diff --git a/lib/util/bignumber.js b/lib/util/bignumber.js index 9da968278..ec3b52590 100644 --- a/lib/util/bignumber.js +++ b/lib/util/bignumber.js @@ -126,13 +126,15 @@ exports.tau = function (precision) { * */ exports.and = function(x, y) { + if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { + throw new Error('Parameters in function bitAnd must be integer numbers'); + } + var BigNumber = x['constructor']; if (x.isNaN() || y.isNaN()) { return new BigNumber(NaN); } - x = x.trunc(); - y = y.trunc(); if (x.isZero() || y.eq(-1) || x.eq(y)) { return x; } @@ -186,8 +188,11 @@ exports.and = function(x, y) { * */ exports.leftShift = function (x, y) { - var BigNumber = x['constructor']; + if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { + throw new Error('Parameters in function leftShift must be integer numbers'); + } + var BigNumber = x['constructor']; if (x.isNaN() || y.isNaN() || (y.isNegative() && !y.isZero())) { return new BigNumber(NaN); } @@ -211,11 +216,15 @@ exports.leftShift = function (x, y) { * */ exports.not = function (x) { + if (x.isFinite() && !x.isInteger()) { + throw new Error('Parameter in function bitNot must be integer numbers'); + } + var BigNumber = x['constructor']; var prevPrec = BigNumber['precision']; BigNumber['precision'] = 1E9; - var x = x.trunc().plus(BigNumber['ONE']); + var x = x.plus(BigNumber['ONE']); x['s'] = -x['s'] || null; BigNumber['precision'] = prevPrec; @@ -242,14 +251,15 @@ exports.not = function (x) { * */ exports.or = function (x, y) { + if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { + throw new Error('Parameters in function bitOr must be integer numbers'); + } + var BigNumber = x['constructor']; if (x.isNaN() || y.isNaN()) { return new BigNumber(NaN); } - x = x.trunc(); - y = y.trunc(); - var negOne = new BigNumber(-1); if (x.isZero() || y.eq(negOne) || x.eq(y)) { return y; @@ -291,8 +301,11 @@ exports.or = function (x, y) { * */ exports.rightShift = function (x, y) { - var BigNumber = x['constructor']; + if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { + throw new Error('Parameters in function rightArithShift must be integer numbers'); + } + var BigNumber = x['constructor']; if (x.isNaN() || y.isNaN() || (y.isNegative() && !y.isZero())) { return new BigNumber(NaN); } @@ -334,13 +347,14 @@ exports.rightShift = function (x, y) { * */ exports.xor = function (x, y) { + if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { + throw new Error('Parameters in function bitXor must be integer numbers'); + } + var BigNumber = x['constructor']; if (x.isNaN() || y.isNaN()) { return new BigNumber(NaN); } - - x = x.trunc(); - y = y.trunc(); if (x.isZero()) { return y; } diff --git a/test/function/bitwise/bitAnd.test.js b/test/function/bitwise/bitAnd.test.js index a15ed0a05..101a37a04 100644 --- a/test/function/bitwise/bitAnd.test.js +++ b/test/function/bitwise/bitAnd.test.js @@ -77,6 +77,36 @@ describe('bitAnd', function () { assert.equal(bitAnd(-120, '-86e2'), -8696); }); + it('should throw an error if the parameters are not integers', function () { + assert.throws(function () { + bitAnd(1.1, 1); + }, /Parameters in function bitAnd must be integer numbers/); + assert.throws(function () { + bitAnd(1, 1.1); + }, /Parameters in function bitAnd must be integer numbers/); + assert.throws(function () { + bitAnd(1.1, 1.1); + }, /Parameters in function bitAnd must be integer numbers/); + assert.throws(function () { + bitAnd('1.1', 1); + }, /Parameters in function bitAnd must be integer numbers/); + assert.throws(function () { + bitAnd(1, '1.1'); + }, /Parameters in function bitAnd must be integer numbers/); + assert.throws(function () { + bitAnd(bignumber(1.1), 1); + }, /Parameters in function bitAnd must be integer numbers/); + assert.throws(function () { + bitAnd(1, bignumber(1.1)); + }, /Parameters in function bitAnd must be integer numbers/); + assert.throws(function () { + bitAnd(bignumber(1.1), bignumber(1)); + }, /Parameters in function bitAnd must be integer numbers/); + assert.throws(function () { + bitAnd(bignumber(1), bignumber(1.1)); + }, /Parameters in function bitAnd must be integer numbers/); + }); + it('should bitwise and strings and matrices element wise', function () { assert.deepEqual(bitAnd('42', ['1', 12, '31']), [0, 8, 10]); assert.deepEqual(bitAnd(['1', 12, '31'], '42'), [0, 8, 10]); diff --git a/test/function/bitwise/bitNot.test.js b/test/function/bitwise/bitNot.test.js index d354e932d..722c505f5 100644 --- a/test/function/bitwise/bitNot.test.js +++ b/test/function/bitwise/bitNot.test.js @@ -33,6 +33,18 @@ describe('bitNot', function () { assert.deepEqual(bitNot(bignumber('1.2345e30')), bignumber('-1234500000000000000000000000001')); }); + it('should throw an error if the parameters are not integers', function () { + assert.throws(function () { + bitNot(1.1); + }, /Parameter in function bitNot must be integer numbers/); + assert.throws(function () { + bitNot('1.1'); + }, /Parameter in function bitNot must be integer numbers/); + assert.throws(function () { + bitNot(bignumber(1.1)); + }, /Parameter in function bitNot must be integer numbers/); + }); + it('should throw an error if used with a unit', function() { assert.throws(function () {bitNot(math.unit('5cm'))}, error.UnsupportedTypeError); }); diff --git a/test/function/bitwise/bitOr.test.js b/test/function/bitwise/bitOr.test.js index 657e5828f..b80e8d8a5 100644 --- a/test/function/bitwise/bitOr.test.js +++ b/test/function/bitwise/bitOr.test.js @@ -76,6 +76,36 @@ describe('bitOr', function () { assert.equal(bitOr(-120, '-86e2'), -24); }); + it('should throw an error if the parameters are not integers', function () { + assert.throws(function () { + bitOr(1.1, 1); + }, /Parameters in function bitOr must be integer numbers/); + assert.throws(function () { + bitOr(1, 1.1); + }, /Parameters in function bitOr must be integer numbers/); + assert.throws(function () { + bitOr(1.1, 1.1); + }, /Parameters in function bitOr must be integer numbers/); + assert.throws(function () { + bitOr('1.1', 1); + }, /Parameters in function bitOr must be integer numbers/); + assert.throws(function () { + bitOr(1, '1.1'); + }, /Parameters in function bitOr must be integer numbers/); + assert.throws(function () { + bitOr(bignumber(1.1), 1); + }, /Parameters in function bitOr must be integer numbers/); + assert.throws(function () { + bitOr(1, bignumber(1.1)); + }, /Parameters in function bitOr must be integer numbers/); + assert.throws(function () { + bitOr(bignumber(1.1), bignumber(1)); + }, /Parameters in function bitOr must be integer numbers/); + assert.throws(function () { + bitOr(bignumber(1), bignumber(1.1)); + }, /Parameters in function bitOr must be integer numbers/); + }); + it('should bitwise or strings and matrices element wise', function () { assert.deepEqual(bitOr('42', ['1', 12, '31']), [43, 46, 63]); assert.deepEqual(bitOr(['1', 12, '31'], '42'), [43, 46, 63]); diff --git a/test/function/bitwise/bitXor.test.js b/test/function/bitwise/bitXor.test.js index 900cb30f1..bf0a1d88f 100644 --- a/test/function/bitwise/bitXor.test.js +++ b/test/function/bitwise/bitXor.test.js @@ -78,6 +78,36 @@ describe('bitXor', function () { assert.equal(bitXor(-120, '-86e2'), 8672); }); + it('should throw an error if the parameters are not integers', function () { + assert.throws(function () { + bitXor(1.1, 1); + }, /Parameters in function bitXor must be integer numbers/); + assert.throws(function () { + bitXor(1, 1.1); + }, /Parameters in function bitXor must be integer numbers/); + assert.throws(function () { + bitXor(1.1, 1.1); + }, /Parameters in function bitXor must be integer numbers/); + assert.throws(function () { + bitXor('1.1', 1); + }, /Parameters in function bitXor must be integer numbers/); + assert.throws(function () { + bitXor(1, '1.1'); + }, /Parameters in function bitXor must be integer numbers/); + assert.throws(function () { + bitXor(bignumber(1.1), 1); + }, /Parameters in function bitXor must be integer numbers/); + assert.throws(function () { + bitXor(1, bignumber(1.1)); + }, /Parameters in function bitXor must be integer numbers/); + assert.throws(function () { + bitXor(bignumber(1.1), bignumber(1)); + }, /Parameters in function bitXor must be integer numbers/); + assert.throws(function () { + bitXor(bignumber(1), bignumber(1.1)); + }, /Parameters in function bitXor must be integer numbers/); + }); + it('should xor strings and matrices element wise', function () { assert.deepEqual(bitXor('42', ['1', 12, '31']), [43, 38, 53]); assert.deepEqual(bitXor(['1', 12, '31'], '42'), [43, 38, 53]); diff --git a/test/function/bitwise/leftShift.test.js b/test/function/bitwise/leftShift.test.js index eaed4fb10..8da5478d0 100644 --- a/test/function/bitwise/leftShift.test.js +++ b/test/function/bitwise/leftShift.test.js @@ -42,7 +42,6 @@ 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(-1.9), bignumber(2.9)), bignumber(-4)); assert.deepEqual(leftShift(bignumber(0), bignumber(-2)).toString(), 'NaN'); assert.deepEqual(leftShift(bignumber(Infinity), bignumber(2)), bignumber(Infinity)); assert.deepEqual(leftShift(bignumber(Infinity), bignumber(Infinity)).toString(), 'NaN'); @@ -53,9 +52,7 @@ describe('leftShift', function () { assert.deepEqual(leftShift(bignumber(500), 100), bignumber('633825300114114700748351602688000')); assert.deepEqual(leftShift(2, bignumber(3)), bignumber(16)); assert.deepEqual(leftShift(-1, bignumber(2)), bignumber(-4)); - assert.deepEqual(leftShift(-1.9, bignumber(2.9)), bignumber(-4)); assert.deepEqual(leftShift(bignumber(-1), 2), bignumber(-4)); - assert.deepEqual(leftShift(bignumber(-1.9), 2.9), bignumber(-4)); assert.deepEqual(leftShift(bignumber(0), -2).toString(), 'NaN'); assert.deepEqual(leftShift(bignumber(Infinity), Infinity).toString(), 'NaN'); }); @@ -88,6 +85,36 @@ describe('leftShift', function () { assert.equal(leftShift(-2, '1e2'), -32); }); + it('should throw an error if the parameters are not integers', function () { + assert.throws(function () { + leftShift(1.1, 1); + }, /Parameters in function leftShift must be integer numbers/); + assert.throws(function () { + leftShift(1, 1.1); + }, /Parameters in function leftShift must be integer numbers/); + assert.throws(function () { + leftShift(1.1, 1.1); + }, /Parameters in function leftShift must be integer numbers/); + assert.throws(function () { + leftShift('1.1', 1); + }, /Parameters in function leftShift must be integer numbers/); + assert.throws(function () { + leftShift(1, '1.1'); + }, /Parameters in function leftShift must be integer numbers/); + assert.throws(function () { + leftShift(bignumber(1.1), 1); + }, /Parameters in function leftShift must be integer numbers/); + assert.throws(function () { + leftShift(1, bignumber(1.1)); + }, /Parameters in function leftShift must be integer numbers/); + assert.throws(function () { + leftShift(bignumber(1.1), bignumber(1)); + }, /Parameters in function leftShift must be integer numbers/); + assert.throws(function () { + leftShift(bignumber(1), bignumber(1.1)); + }, /Parameters in function leftShift must be integer numbers/); + }); + it('should element-wise left shift a matrix', function () { var a = math.matrix([1,2]); var b = leftShift(a, 2); diff --git a/test/function/bitwise/rightArithShift.test.js b/test/function/bitwise/rightArithShift.test.js index 241085582..0d118569d 100644 --- a/test/function/bitwise/rightArithShift.test.js +++ b/test/function/bitwise/rightArithShift.test.js @@ -82,6 +82,36 @@ describe('rightArithShift', function () { assert.deepEqual(rightArithShift('-17', bignumber(3)), bignumber(-3)); }); + it('should throw an error if the parameters are not integers', function () { + assert.throws(function () { + rightArithShift(1.1, 1); + }, /Parameters in function rightArithShift must be integer numbers/); + assert.throws(function () { + rightArithShift(1, 1.1); + }, /Parameters in function rightArithShift must be integer numbers/); + assert.throws(function () { + rightArithShift(1.1, 1.1); + }, /Parameters in function rightArithShift must be integer numbers/); + assert.throws(function () { + rightArithShift('1.1', 1); + }, /Parameters in function rightArithShift must be integer numbers/); + assert.throws(function () { + rightArithShift(1, '1.1'); + }, /Parameters in function rightArithShift must be integer numbers/); + assert.throws(function () { + rightArithShift(bignumber(1.1), 1); + }, /Parameters in function rightArithShift must be integer numbers/); + assert.throws(function () { + rightArithShift(1, bignumber(1.1)); + }, /Parameters in function rightArithShift must be integer numbers/); + assert.throws(function () { + rightArithShift(bignumber(1.1), bignumber(1)); + }, /Parameters in function rightArithShift must be integer numbers/); + assert.throws(function () { + rightArithShift(bignumber(1), bignumber(1.1)); + }, /Parameters in function rightArithShift must be integer numbers/); + }); + it('should throw an error if used with a unit', function() { assert.throws(function () {rightArithShift(math.unit('5cm'), 2)}, error.UnsupportedTypeError); assert.throws(function () {rightArithShift(2, math.unit('5cm'))}, error.UnsupportedTypeError); diff --git a/test/function/bitwise/rightLogShift.test.js b/test/function/bitwise/rightLogShift.test.js index ee9120b22..d797e311c 100644 --- a/test/function/bitwise/rightLogShift.test.js +++ b/test/function/bitwise/rightLogShift.test.js @@ -46,6 +46,27 @@ describe('rightLogShift', function () { assert.equal(rightLogShift('-256', '1e2'), 268435440); }); + it('should throw an error if the parameters are not integers', function () { + assert.throws(function () { + rightLogShift(1.1, 1); + }, /Parameters in function rightLogShift must be integer numbers/); + assert.throws(function () { + rightLogShift(1, 1.1); + }, /Parameters in function rightLogShift must be integer numbers/); + assert.throws(function () { + rightLogShift(1.1, 1.1); + }, /Parameters in function rightLogShift must be integer numbers/); + assert.throws(function () { + rightLogShift('1.1', '1.1'); + }, /Parameters in function rightLogShift must be integer numbers/); + assert.throws(function () { + rightLogShift('1.1', 1); + }, /Parameters in function rightLogShift must be integer numbers/); + assert.throws(function () { + rightLogShift(1, '1.1'); + }, /Parameters in function rightLogShift must be integer numbers/); + }); + it('should throw an error if used with a unit', function() { assert.throws(function () {rightLogShift(math.unit('5cm'), 2)}, error.UnsupportedTypeError); assert.throws(function () {rightLogShift(2, math.unit('5cm'))}, error.UnsupportedTypeError); From ece196c53d8577ced66b997f697f1bc7ccef1b72 Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Tue, 16 Dec 2014 08:18:49 -0800 Subject: [PATCH 18/19] Implemented , , and . Will attempt to add to parser. --- lib/function/boolean/and.js | 109 +++++++++++++++ lib/function/boolean/not.js | 65 +++++++++ lib/function/boolean/or.js | 101 ++++++++++++++ lib/math.js | 5 + test/function/boolean/and.test.js | 190 ++++++++++++++++++++++++++ test/function/boolean/not.test.js | 102 ++++++++++++++ test/function/boolean/or.test.js | 218 ++++++++++++++++++++++++++++++ 7 files changed, 790 insertions(+) create mode 100644 lib/function/boolean/and.js create mode 100644 lib/function/boolean/not.js create mode 100644 lib/function/boolean/or.js create mode 100644 test/function/boolean/and.test.js create mode 100644 test/function/boolean/not.test.js create mode 100644 test/function/boolean/or.test.js diff --git a/lib/function/boolean/and.js b/lib/function/boolean/and.js new file mode 100644 index 000000000..892348ea7 --- /dev/null +++ b/lib/function/boolean/and.js @@ -0,0 +1,109 @@ +'use strict'; + +module.exports = function (math) { + var util = require('../../util/index'), + + BigNumber = math.type.BigNumber, + Complex = require('../../type/Complex'), + Unit = require('../../type/Unit'), + collection = require('../../type/collection'), + + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Test whether two values are both defined with a nonzero/nonempty value. + * + * Syntax: + * + * math.and(x, y) + * + * Examples: + * + * math.and(2, 4); // returns true + * + * a = [2, 5, 1]; + * b = [2, 7, 1]; + * c = 0; + * + * math.and(a, b); // returns true + * math.and(a, c); // returns false + * + * See also: + * + * not, or + * + * @param {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix | null | undefined} x First value to check + * @param {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix | null | undefined} y Second value to check + * @return {Boolean} + * Returns true when both inputs are defined with a nonzero/nonempty value. + */ + math.and = function and(x, y) { + if (arguments.length != 2) { + throw new math.error.ArgumentsError('and', arguments.length, 2); + } + + if (isComplex(x)) { + if (x.re == 0 && x.im == 0) { + return false; + } + + return and(true, y); + } + if (isComplex(y)) { + if (y.re == 0 && y.im == 0) { + return false; + } + + return and(x, true); + } + + if (x instanceof BigNumber) { + if (x.isZero() || x.isNaN()) { + return false; + } + + return and(true, y); + } + if (y instanceof BigNumber) { + if (y.isZero() || y.isNaN()) { + return false; + } + + return and(x, true); + } + + if (isUnit(x)) { + if (x.value === null || x.value == 0) { + return false; + } + + return and(true, y); + } + if (isUnit(y)) { + if (y.value === null || y.value == 0) { + return false; + } + + return and(x, true); + } + + if (isCollection(x)) { + if (x.length == 0 || (x.size && x.size() == 0)) { + return false; + } + + return and(true, y); + } + if (isCollection(y)) { + if (y.length == 0 || (y.size && y.size() == 0)) { + return false; + } + + return and(x, true); + } + + return !!(x && y); + }; +}; diff --git a/lib/function/boolean/not.js b/lib/function/boolean/not.js new file mode 100644 index 000000000..b16cd008d --- /dev/null +++ b/lib/function/boolean/not.js @@ -0,0 +1,65 @@ +'use strict'; + +module.exports = function (math) { + var util = require('../../util/index'), + + BigNumber = math.type.BigNumber, + Complex = require('../../type/Complex'), + Unit = require('../../type/Unit'), + collection = require('../../type/collection'), + + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Flips boolean value of a given parameter. + * + * Syntax: + * + * math.not(x) + * + * Examples: + * + * math.not(2); // returns false + * math.not(0); // returns true + * math.not(true); // returns false + * + * a = []; + * b = [2, 7, 1]; + * + * math.and(a); // returns true + * math.and(b); // returns false + * + * See also: + * + * and, or + * + * @param {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix | null | undefined} x First value to check + * @return {Boolean} + * Returns true when input is a zero or empty value. + */ + math.not = function not(x) { + if (arguments.length != 1) { + throw new math.error.ArgumentsError('not', arguments.length, 1); + } + + if (isComplex(x)) { + return x.re == 0 && x.im == 0; + } + + if (x instanceof BigNumber) { + return x.isZero() || x.isNaN(); + } + + if (isUnit(x)) { + return x.value === null || x.value == 0; + } + + if (isCollection(x)) { + return !!(x.length == 0 || (x.size && x.size() == 0)); + } + + return !x; + }; +}; diff --git a/lib/function/boolean/or.js b/lib/function/boolean/or.js new file mode 100644 index 000000000..2f24f2d56 --- /dev/null +++ b/lib/function/boolean/or.js @@ -0,0 +1,101 @@ +'use strict'; + +module.exports = function (math) { + var util = require('../../util/index'), + + BigNumber = math.type.BigNumber, + Complex = require('../../type/Complex'), + Unit = require('../../type/Unit'), + collection = require('../../type/collection'), + + isComplex = Complex.isComplex, + isUnit = Unit.isUnit, + isCollection = collection.isCollection; + + /** + * Test if at least one value is defined with a nonzero/nonempty value. + * + * Syntax: + * + * math.or(x, y) + * + * Examples: + * + * math.or(2, 4); // returns true + * + * a = [2, 5, 1]; + * b = []; + * c = 0; + * + * math.or(a, b); // returns true + * math.or(b, c); // returns false + * + * See also: + * + * and, not + * + * @param {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix | null | undefined} x First value to check + * @param {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix | null | undefined} y Second value to check + * @return {Boolean} + * Returns true when one of the inputs is defined with a nonzero/nonempty value. + */ + math.or = function or(x, y) { + if (arguments.length != 2) { + throw new math.error.ArgumentsError('or', arguments.length, 2); + } + + if (isComplex(x)) { + if (x.re == 0 && x.im == 0) { + return or(false, y); + } + return true; + } + if (isComplex(y)) { + if (y.re == 0 && y.im == 0) { + return or(x, false); + } + return true; + } + + if (x instanceof BigNumber) { + if (x.isZero() || x.isNaN()) { + return or(false, y); + } + return true; + } + if (y instanceof BigNumber) { + if (y.isZero() || y.isNaN()) { + return or(x, false); + } + return true; + } + + if (isUnit(x)) { + if (x.value === null || x.value == 0) { + return or(false, y); + } + return true; + } + if (isUnit(y)) { + if (y.value === null || y.value == 0) { + return or(x, false); + } + return true; + } + + if (isCollection(x)) { + if (x.length == 0 || (x.size && x.size() == 0)) { + return or(false, y); + } + return true; + } + if (isCollection(y)) { + if (y.length == 0 || (y.size && y.size() == 0)) { + return or(x, false); + } + return true; + } + + return !!(x || y); + }; +}; diff --git a/lib/math.js b/lib/math.js index ab28fefaa..aa9f81188 100644 --- a/lib/math.js +++ b/lib/math.js @@ -207,6 +207,11 @@ function create (config) { require('./function/arithmetic/unaryPlus')(math, _config); require('./function/arithmetic/xgcd')(math, _config); + // functions - boolean + require('./function/boolean/and')(math, _config); + require('./function/boolean/not')(math, _config); + require('./function/boolean/or')(math, _config); + // functions - relational require('./function/relational/compare')(math, _config); require('./function/relational/deepEqual')(math, _config); diff --git a/test/function/boolean/and.test.js b/test/function/boolean/and.test.js new file mode 100644 index 000000000..848f9b33b --- /dev/null +++ b/test/function/boolean/and.test.js @@ -0,0 +1,190 @@ +// test and +var assert = require('assert'), + math = require('../../../index'), + error = require('../../../lib/error/index'), + bignumber = math.bignumber, + complex = math.complex, + matrix = math.matrix, + unit = math.unit, + and = math.and; + +describe('and', function () { + + it('should and two numbers correctly', function () { + assert.equal(and(1, 1), true); + assert.equal(and(-1, 1), true); + assert.equal(and(-1, -1), true); + assert.equal(and(0, -1), false); + assert.equal(and(1, 0), false); + assert.equal(and(1, NaN), false); + assert.equal(and(NaN, 1), false); + assert.equal(and(1e10, 0.019209), true); + assert.equal(and(-1.0e-100, 1.0e-100), true); + assert.equal(and(Infinity, -Infinity), true); + }); + + it('should and two complex numbers', function () { + assert.equal(and(complex(1, 1), complex(1, 1)), true); + assert.equal(and(complex(0, 1), complex(1, 1)), true); + assert.equal(and(complex(1, 0), complex(1, 1)), true); + assert.equal(and(complex(1, 1), complex(0, 1)), true); + assert.equal(and(complex(1, 1), complex(1, 0)), true); + assert.equal(and(complex(1, 0), complex(1, 0)), true); + assert.equal(and(complex(0, 1), complex(0, 1)), true); + assert.equal(and(complex(0, 0), complex(1, 1)), false); + assert.equal(and(complex(0, 0), complex(0, 1)), false); + assert.equal(and(complex(0, 0), complex(1, 0)), false); + assert.equal(and(complex(1, 1), complex(0, 0)), false); + assert.equal(and(complex(0, 1), complex(0, 0)), false); + assert.equal(and(complex(1, 0), complex(0, 0)), false); + assert.equal(and(complex(), complex(1, 1)), false); + assert.equal(and(complex(0), complex(1, 1)), false); + assert.equal(and(complex(1), complex(1, 1)), true); + assert.equal(and(complex(1, 1), complex()), false); + assert.equal(and(complex(1, 1), complex(0)), false); + assert.equal(and(complex(1, 1), complex(1)), true); + }); + + it('should and mixed numbers and complex numbers', function () { + assert.equal(and(complex(1, 1), 1), true); + assert.equal(and(complex(1, 1), 0), false); + assert.equal(and(1, complex(1, 1)), true); + assert.equal(and(0, complex(1, 1)), false); + assert.equal(and(complex(0, 0), 1), false); + assert.equal(and(1, complex(0, 0)), false); + }); + + it('should and two booleans', function () { + assert.equal(and(true, true), true); + assert.equal(and(true, false), false); + assert.equal(and(false, true), false); + assert.equal(and(false, false), false); + }); + + it('should and mixed numbers and booleans', function () { + assert.equal(and(2, true), true); + assert.equal(and(2, false), false); + assert.equal(and(0, true), false); + assert.equal(and(true, 2), true); + assert.equal(and(false, 2), false); + }); + + it('should and mixed numbers and null', function () { + assert.equal(and(2, null), false); + assert.equal(and(null, 2), false); + }); + + it('should and mixed numbers and undefined', function () { + assert.equal(and(2, undefined), false); + assert.equal(and(undefined, 2), false); + }); + + it('should and bignumbers', function () { + assert.equal(and(bignumber(1), bignumber(1)), true); + assert.equal(and(bignumber(-1), bignumber(1)), true); + assert.equal(and(bignumber(-1), bignumber(-1)), true); + assert.equal(and(bignumber(0), bignumber(-1)), false); + assert.equal(and(bignumber(1), bignumber(0)), false); + assert.equal(and(bignumber(1), bignumber(NaN)), false); + assert.equal(and(bignumber(NaN), bignumber(1)), false); + assert.equal(and(bignumber('1e+10'), bignumber(0.19209)), true); + assert.equal(and(bignumber('-1.0e-100'), bignumber('1.0e-100')), true); + assert.equal(and(bignumber(Infinity), bignumber(-Infinity)), true); + }); + + it('should and mixed numbers and bignumbers', function () { + assert.equal(and(bignumber(2), 3), true); + assert.equal(and(2, bignumber(2)), true); + assert.equal(and(0, bignumber(2)), false); + assert.equal(and(2, bignumber(0)), false); + assert.equal(and(bignumber(0), 2), false); + assert.equal(and(bignumber(2), 0), false); + }); + + it('should and two units', function () { + assert.equal(and(unit('100cm'), unit('10inch')), true); + assert.equal(and(unit('100cm'), unit('0 inch')), false); + assert.equal(and(unit('0cm'), unit('1m')), false); + assert.equal(and(unit('m'), unit('1m')), false); + assert.equal(and(unit('1dm'), unit('m')), false); + assert.equal(and(unit('-100cm'), unit('-10inch')), true); + assert.equal(and(unit(5, 'km'), unit(100, 'gram')), true); + assert.equal(and(unit(5, 'km'), unit(0, 'gram')), false); + assert.equal(and(unit(0, 'km'), unit(100, 'gram')), false); + }); + + it('should and mixed numbers and units', function () { + assert.equal(and(unit('2m'), 3), true); + assert.equal(and(2, unit('3m')), true); + assert.equal(and(0, unit('2m')), false); + assert.equal(and(2, unit('0m')), false); + assert.equal(and(unit('0in'), 2), false); + assert.equal(and(unit('2in'), 0), false); + }); + + it('should and two strings', function () { + assert.equal(and('0', 'NaN'), true); + + assert.equal(and('abd', ' '), true); + assert.equal(and('abc', ''), false); + assert.equal(and('', 'abd'), false); + assert.equal(and('', ''), false); + }); + + it('should and mixed numbers and strings', function () { + assert.equal(and(1, 'NaN'), true); + assert.equal(and('abd', 1), true); + assert.equal(and(1, ''), false); + assert.equal(and('', 1), false); + }); + + it('should and two arrays', function () { + assert.equal(and([0], [0, 0, 0]), true); + assert.equal(and([], [0, 0, 0]), false); + assert.equal(and(['A', 'B', 'C'], []), false); + assert.equal(and([], []), false); + assert.equal(and([[]], [[]]), true); + assert.equal(and([[[]]], [[]]), true); + }); + + it('should and mixed numbers and arrays', function () { + assert.equal(and(1, [0, 0, 0]), true); + assert.equal(and([0], 1), true); + assert.equal(and(0, [0, 0, 0]), false); + assert.equal(and(['A', 'B', 'C'], 0), false); + assert.equal(and(1, []), false); + assert.equal(and([[]], 1), true); + assert.equal(and([[], []], 1), true); + }); + + it('should and two matrices', function () { + assert.equal(and(matrix([0]), matrix([0, 0, 0])), true); + assert.equal(and(matrix([]), matrix([0, 0, 0])), false); + assert.equal(and(matrix(['A', 'B', 'C']), matrix([])), false); + assert.equal(and(matrix([]), matrix([])), false); + assert.equal(and(matrix([]), matrix([[]])), false); + assert.equal(and(matrix([[]]), matrix([[]])), true); + assert.equal(and(matrix([[[]]]), matrix([[]])), true); + }); + + it('should and mixed numbers and matrices', function () { + assert.equal(and(1, matrix([0, 0, 0])), true); + assert.equal(and(matrix([0]), 1), true); + assert.equal(and(0, matrix([0, 0, 0])), false); + assert.equal(and(matrix(['A', 'B', 'C']), 0), false); + assert.equal(and(1, matrix([])), false); + assert.equal(and(matrix([]), 1), false); + assert.equal(and(matrix([[]]), 1), true); + assert.equal(and(matrix([[], []]), 1), true); + }); + + it('should and two objects', function () { + assert.equal(and(new Date(), new Date()), true); + }); + + it('should throw an error in case of invalid number of arguments', function () { + assert.throws(function () {and(1)}, error.ArgumentsError); + assert.throws(function () {and(1, 2, 3)}, error.ArgumentsError); + }); + +}); diff --git a/test/function/boolean/not.test.js b/test/function/boolean/not.test.js new file mode 100644 index 000000000..932e503ff --- /dev/null +++ b/test/function/boolean/not.test.js @@ -0,0 +1,102 @@ +// test not +var assert = require('assert'), + math = require('../../../index'), + error = require('../../../lib/error/index'), + bignumber = math.bignumber, + complex = math.complex, + matrix = math.matrix, + unit = math.unit, + not = math.not; + +describe('not', function () { + + it('should not numbers correctly', function () { + assert.equal(not(1), false); + assert.equal(not(-1), false); + assert.equal(not(1.23e+100), false); + assert.equal(not(-1.0e-100), false); + assert.equal(not(1.0e-100), false); + assert.equal(not(Infinity), false); + assert.equal(not(-Infinity), false); + assert.equal(not(0), true); + assert.equal(not(NaN), true); + }); + + it('should not complex numbers', function () { + assert.equal(not(complex(1, 1)), false); + assert.equal(not(complex(0, 1)), false); + assert.equal(not(complex(1, 0)), false); + assert.equal(not(complex(0, 0)), true); + assert.equal(not(complex()), true); + assert.equal(not(complex(0)), true); + assert.equal(not(complex(1)), false); + }); + + it('should not booleans', function () { + assert.equal(not(true), false); + assert.equal(not(false), true); + }); + + it('should not null/undefined values', function () { + assert.equal(not(null), true); + assert.equal(not(undefined), true); + }); + + it('should not bignumbers', function () { + assert.equal(not(bignumber(1)), false); + assert.equal(not(bignumber(-1)), false); + assert.equal(not(bignumber(0)), true); + assert.equal(not(bignumber(NaN)), true); + assert.equal(not(bignumber('1e+10')), false); + assert.equal(not(bignumber('-1.0e-100')), false); + assert.equal(not(bignumber('1.0e-100')), false); + assert.equal(not(bignumber(Infinity)), false); + assert.equal(not(bignumber(-Infinity)), false); + }); + + it('should not units', function () { + assert.equal(not(unit('100cm')), false); + assert.equal(not(unit('0 inch')), true); + assert.equal(not(unit('1m')), false); + assert.equal(not(unit('m')), true); + assert.equal(not(unit('-10inch')), false); + }); + + it('should not strings', function () { + assert.equal(not('0'), false); + assert.equal(not('NaN'), false); + + assert.equal(not('abd'), false); + assert.equal(not(''), true); + assert.equal(not('\0'), false); + assert.equal(not(' '), false); + }); + + it('should not arrays', function () { + assert.equal(not([0]), false); + assert.equal(not([0, 0, 0]), false); + assert.equal(not(['A', ['B', 'C']]), false); + assert.equal(not([]), true); + assert.equal(not([[]]), false); + assert.equal(not([[[]]]), false); + }); + + it('should not matrices', function () { + assert.equal(not(matrix([0])), false); + assert.equal(not(matrix([0, 0, 0])), false); + assert.equal(not(matrix(['A', 'B', 'C'])), false); + assert.equal(not(matrix([])), true); + assert.equal(not(matrix([[]])), false); + assert.equal(not(matrix([[[]]])), false); + }); + + it('should not object', function () { + assert.equal(not(new Date()), false); + }); + + it('should throw an error in case of invalid number of arguments', function () { + assert.throws(function () {not()}, error.ArgumentsError); + assert.throws(function () {not(1, 2)}, error.ArgumentsError); + }); + +}); diff --git a/test/function/boolean/or.test.js b/test/function/boolean/or.test.js new file mode 100644 index 000000000..4defcd8ad --- /dev/null +++ b/test/function/boolean/or.test.js @@ -0,0 +1,218 @@ +// test or +var assert = require('assert'), + math = require('../../../index'), + error = require('../../../lib/error/index'), + bignumber = math.bignumber, + complex = math.complex, + matrix = math.matrix, + unit = math.unit, + or = math.or; + +describe('or', function () { + + it('should or two numbers correctly', function () { + assert.equal(or(1, 1), true); + assert.equal(or(-1, 1), true); + assert.equal(or(-1, -1), true); + assert.equal(or(0, -1), true); + assert.equal(or(1, 0), true); + assert.equal(or(1, NaN), true); + assert.equal(or(NaN, 1), true); + assert.equal(or(1e10, 0.019209), true); + assert.equal(or(-1.0e-100, 1.0e-100), true); + assert.equal(or(Infinity, -Infinity), true); + assert.equal(or(NaN, NaN), false); + assert.equal(or(NaN, 0), false); + assert.equal(or(0, NaN), false); + assert.equal(or(0, 0), false); + }); + + it('should or two complex numbers', function () { + assert.equal(or(complex(1, 1), complex(1, 1)), true); + assert.equal(or(complex(0, 1), complex(1, 1)), true); + assert.equal(or(complex(1, 0), complex(1, 1)), true); + assert.equal(or(complex(1, 1), complex(0, 1)), true); + assert.equal(or(complex(1, 1), complex(1, 0)), true); + assert.equal(or(complex(1, 0), complex(1, 0)), true); + assert.equal(or(complex(0, 1), complex(0, 1)), true); + assert.equal(or(complex(0, 0), complex(1, 1)), true); + assert.equal(or(complex(0, 0), complex(0, 1)), true); + assert.equal(or(complex(0, 0), complex(1, 0)), true); + assert.equal(or(complex(1, 1), complex(0, 0)), true); + assert.equal(or(complex(0, 1), complex(0, 0)), true); + assert.equal(or(complex(1, 0), complex(0, 0)), true); + assert.equal(or(complex(), complex(1, 1)), true); + assert.equal(or(complex(0), complex(1, 1)), true); + assert.equal(or(complex(1), complex(1, 1)), true); + assert.equal(or(complex(1, 1), complex()), true); + assert.equal(or(complex(1, 1), complex(0)), true); + assert.equal(or(complex(1, 1), complex(1)), true); + assert.equal(or(complex(0, 0), complex(0, 0)), false); + assert.equal(or(complex(), complex()), false); + }); + + it('should or mixed numbers and complex numbers', function () { + assert.equal(or(complex(1, 1), 1), true); + assert.equal(or(complex(1, 1), 0), true); + assert.equal(or(1, complex(1, 1)), true); + assert.equal(or(0, complex(1, 1)), true); + assert.equal(or(complex(0, 0), 1), true); + assert.equal(or(1, complex(0, 0)), true); + assert.equal(or(0, complex(0, 0)), false); + assert.equal(or(complex(0, 0), 0), false); + }); + + it('should or two booleans', function () { + assert.equal(or(true, true), true); + assert.equal(or(true, false), true); + assert.equal(or(false, true), true); + assert.equal(or(false, false), false); + }); + + it('should or mixed numbers and booleans', function () { + assert.equal(or(2, true), true); + assert.equal(or(2, false), true); + assert.equal(or(0, true), true); + assert.equal(or(0, false), false); + assert.equal(or(true, 2), true); + assert.equal(or(false, 2), true); + assert.equal(or(false, 0), false); + }); + + it('should or mixed numbers and null', function () { + assert.equal(or(2, null), true); + assert.equal(or(null, 2), true); + assert.equal(or(null, null), false); + }); + + it('should or mixed numbers and undefined', function () { + assert.equal(or(2, undefined), true); + assert.equal(or(undefined, 2), true); + assert.equal(or(undefined, undefined), false); + }); + + it('should or bignumbers', function () { + assert.equal(or(bignumber(1), bignumber(1)), true); + assert.equal(or(bignumber(-1), bignumber(1)), true); + assert.equal(or(bignumber(-1), bignumber(-1)), true); + assert.equal(or(bignumber(0), bignumber(-1)), true); + assert.equal(or(bignumber(1), bignumber(0)), true); + assert.equal(or(bignumber(1), bignumber(NaN)), true); + assert.equal(or(bignumber(NaN), bignumber(1)), true); + assert.equal(or(bignumber('1e+10'), bignumber(0.19209)), true); + assert.equal(or(bignumber('-1.0e-100'), bignumber('1.0e-100')), true); + assert.equal(or(bignumber(Infinity), bignumber(-Infinity)), true); + assert.equal(or(bignumber(NaN), bignumber(NaN)), false); + assert.equal(or(bignumber(NaN), bignumber(0)), false); + assert.equal(or(bignumber(0), bignumber(NaN)), false); + assert.equal(or(bignumber(0), bignumber(0)), false); + }); + + it('should or mixed numbers and bignumbers', function () { + assert.equal(or(bignumber(2), 3), true); + assert.equal(or(2, bignumber(2)), true); + assert.equal(or(0, bignumber(2)), true); + assert.equal(or(2, bignumber(0)), true); + assert.equal(or(bignumber(0), 2), true); + assert.equal(or(bignumber(0), 0), false); + assert.equal(or(bignumber(2), 0), true); + assert.equal(or(bignumber(0), 0), false); + }); + + it('should or two units', function () { + assert.equal(or(unit('100cm'), unit('10inch')), true); + assert.equal(or(unit('100cm'), unit('0 inch')), true); + assert.equal(or(unit('0cm'), unit('1m')), true); + assert.equal(or(unit('m'), unit('1m')), true); + assert.equal(or(unit('1dm'), unit('m')), true); + assert.equal(or(unit('dm'), unit('m')), false); + assert.equal(or(unit('-100cm'), unit('-10inch')), true); + assert.equal(or(unit(5, 'km'), unit(100, 'gram')), true); + assert.equal(or(unit(5, 'km'), unit(0, 'gram')), true); + assert.equal(or(unit(0, 'km'), unit(100, 'gram')), true); + assert.equal(or(unit(0, 'km'), unit(0, 'gram')), false); + }); + + it('should or mixed numbers and units', function () { + assert.equal(or(2, unit('3m')), true); + assert.equal(or(0, unit('2m')), true); + assert.equal(or(2, unit('0m')), true); + assert.equal(or(0, unit('0m')), false); + assert.equal(or(unit('0in'), 2), true); + assert.equal(or(unit('2in'), 0), true); + assert.equal(or(unit('0in'), 0), false); + }); + + it('should or two strings', function () { + assert.equal(or('0', 'NaN'), true); + + assert.equal(or('abd', ' '), true); + assert.equal(or('abc', ''), true); + assert.equal(or('', 'abd'), true); + assert.equal(or('', ''), false); + assert.equal(or(' ', ''), true); + }); + + it('should or mixed numbers and strings', function () { + assert.equal(or(1, 'NaN'), true); + assert.equal(or('abd', 1), true); + assert.equal(or(1, ''), true); + assert.equal(or(0, ''), false); + assert.equal(or('', 1), true); + assert.equal(or('', 0), false); + }); + + it('should or two arrays', function () { + assert.equal(or([0], [0, 0, 0]), true); + assert.equal(or([], [0, 0, 0]), true); + assert.equal(or(['A', 'B', 'C'], []), true); + assert.equal(or([], []), false); + assert.equal(or([[]], [[]]), true); + assert.equal(or([[[]]], [[]]), true); + }); + + it('should or mixed numbers and arrays', function () { + assert.equal(or(1, [0, 0, 0]), true); + assert.equal(or([0], 1), true); + assert.equal(or(0, [0, 0, 0]), true); + assert.equal(or(['A', 'B', 'C'], 0), true); + assert.equal(or(1, []), true); + assert.equal(or(0, []), false); + assert.equal(or([], 0), false); + assert.equal(or([[]], 1), true); + assert.equal(or([[], []], 1), true); + }); + + it('should or two matrices', function () { + assert.equal(or(matrix([0]), matrix([0, 0, 0])), true); + assert.equal(or(matrix([]), matrix([0, 0, 0])), true); + assert.equal(or(matrix(['A', 'B', 'C']), matrix([])), true); + assert.equal(or(matrix([]), matrix([])), false); + assert.equal(or(matrix([]), matrix([[]])), true); + assert.equal(or(matrix([[]]), matrix([[]])), true); + assert.equal(or(matrix([[[]]]), matrix([[]])), true); + }); + + it('should or mixed numbers and matrices', function () { + assert.equal(or(1, matrix([0, 0, 0])), true); + assert.equal(or(matrix([0]), 1), true); + assert.equal(or(0, matrix([0, 0, 0])), true); + assert.equal(or(matrix(['A', 'B', 'C']), 0), true); + assert.equal(or(0, matrix([])), false); + assert.equal(or(1, matrix([])), true); + assert.equal(or(matrix([]), 0), false); + assert.equal(or(matrix([]), 1), true); + assert.equal(or(matrix([[]]), 1), true); + assert.equal(or(matrix([[], []]), 1), true); + }); + + it('should or two objects', function () { + assert.equal(or(new Date(), new Date()), true); + }); + + it('should throw an error in case of invalid number of arguments', function () { + assert.throws(function () {or(1)}, error.ArgumentsError); + assert.throws(function () {or(1, 2, 3)}, error.ArgumentsError); + }); + +}); From 6817f8fefd6b7c0b94e23b17bf341b3c08a39169 Mon Sep 17 00:00:00 2001 From: Favian Contreras Date: Tue, 16 Dec 2014 08:26:32 -0800 Subject: [PATCH 19/19] Strange, phantom file and.js in the relational folder...Deleted it. --- lib/function/relational/and.js | 109 --------------------------------- 1 file changed, 109 deletions(-) delete mode 100644 lib/function/relational/and.js diff --git a/lib/function/relational/and.js b/lib/function/relational/and.js deleted file mode 100644 index 608e62c90..000000000 --- a/lib/function/relational/and.js +++ /dev/null @@ -1,109 +0,0 @@ -'use strict'; - -module.exports = function (math) { - var util = require('../../util/index'), - - BigNumber = math.type.BigNumber, - Complex = require('../../type/Complex'), - Unit = require('../../type/Unit'), - collection = require('../../type/collection'), - - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; - - /** - * Test whether two values are both defined with a nonzero/nonempty value. - * - * Syntax: - * - * math.and(x, y) - * - * Examples: - * - * math.and(2, 4); // returns true - * - * a = [2, 5, 1]; - * b = [2, 7, 1]; - * c = 0; - * - * math.and(a, b); // returns true - * math.and(a, c); // returns false - * - * See also: - * - * not, or - * - * @param {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix | null | undefined} x First value to check - * @param {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix | null | undefined} y Second value to check - * @return {Boolean | Array | Matrix} - * Returns true when both inputs are defined with a nonzero/nonempty value. - */ - math.and = function and(x, y) { - if (arguments.length != 2) { - throw new math.error.ArgumentsError('and', arguments.length, 2); - } - - if (isComplex(x)) { - if (x.re == 0 && x.im == 0) { - return false; - } - - return and(true, y); - } - if (isComplex(y)) { - if (y.re == 0 && y.im == 0) { - return false; - } - - return and(x, true); - } - - if (x instanceof BigNumber) { - if (x.isZero()) { - return false; - } - - return and(true, y); - } - if (y instanceof BigNumber) { - if (y.isZero()) { - return false; - } - - return and(x, true); - } - - if (isUnit(x)) { - if (x.value === null || x.value == 0) { - return false; - } - - return and(true, y); - } - if (isUnit(y)) { - if (y.value === null || y.value == 0) { - return false; - } - - return and(x, true); - } - - if (isCollection(x)) { - if (x.length == 0) { - return false; - } - - return and(true, y); - } - if (isCollection(y)) { - if (y.length == 0) { - return false; - } - - return and(x, true); - } - - return x && y; - }; -};