From 950c27df3e98529cffdccaf9ff03fddf7a09e34a Mon Sep 17 00:00:00 2001 From: jos Date: Wed, 24 Dec 2014 14:51:45 +0100 Subject: [PATCH] Removed the circular dependency between `divide` and `inv` (introduced `_divide`) --- lib/function/arithmetic/_divide.js | 126 +++++++++++++++++++++++++++++ lib/function/arithmetic/divide.js | 116 ++------------------------ lib/function/matrix/inv.js | 34 ++++---- lib/math.js | 1 + 4 files changed, 149 insertions(+), 128 deletions(-) create mode 100644 lib/function/arithmetic/_divide.js diff --git a/lib/function/arithmetic/_divide.js b/lib/function/arithmetic/_divide.js new file mode 100644 index 000000000..6886a2bf4 --- /dev/null +++ b/lib/function/arithmetic/_divide.js @@ -0,0 +1,126 @@ +'use strict'; + +module.exports = function(math) { + var util = require('../../util/index'); + + var BigNumber = math.type.BigNumber; + var Complex = require('../../type/Complex'); + var Matrix = require('../../type/Matrix'); + var Unit = require('../../type/Unit'); + + var isNumber = util.number.isNumber; + var isBoolean = util['boolean'].isBoolean; + var isComplex = Complex.isComplex; + var isUnit = Unit.isUnit; + + /** + * Divide two scalar values, `x / y`. + * This function is meant for internal use: it is used by the public functions + * `divide` and `inv`. + * + * This function does not support collections (Array or Matrix), and does + * not validate the number of of inputs. + * + * @param {Number | BigNumber | Boolean | Complex | Unit | null} x Numerator + * @param {Number | BigNumber | Boolean | Complex | null} y Denominator + * @return {Number | BigNumber | Complex | Unit} Quotient, `x / y` + * @private + */ + math._divide = function _divide(x, y) { + if (isNumber(x)) { + if (isNumber(y)) { + // number / number + return x / y; + } + else if (isComplex(y)) { + // number / complex + return _divideComplex(new Complex(x, 0), y); + } + } + + if (isComplex(x)) { + if (isComplex(y)) { + // complex / complex + return _divideComplex(x, y); + } + else if (isNumber(y)) { + // complex / number + return _divideComplex(x, new Complex(y, 0)); + } + } + + 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.div(y); + } + + // downgrade to Number + return _divide(x.toNumber(), y); + } + if (y instanceof BigNumber) { + // try to convert to big number + 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.div(y) + } + + // downgrade to Number + return _divide(x, y.toNumber()); + } + + if (isUnit(x)) { + if (isNumber(y)) { + var res = x.clone(); + res.value = ((res.value === null) ? res._normalize(1) : res.value) / y; + return res; + } + } + + if (isBoolean(x) || x === null) { + return _divide(+x, y); + } + if (isBoolean(y) || y === null) { + return _divide(x, +y); + } + + throw new math.error.UnsupportedTypeError('divide', math['typeof'](x), math['typeof'](y)); + }; + + /** + * Divide two complex numbers. x / y or divide(x, y) + * @param {Complex} x + * @param {Complex} y + * @return {Complex} res + * @private + */ + function _divideComplex (x, y) { + var den = y.re * y.re + y.im * y.im; + if (den != 0) { + return new Complex( + (x.re * y.re + x.im * y.im) / den, + (x.im * y.re - x.re * y.im) / den + ); + } + else { + // both y.re and y.im are zero + return new Complex( + (x.re != 0) ? (x.re / 0) : 0, + (x.im != 0) ? (x.im / 0) : 0 + ); + } + } +}; diff --git a/lib/function/arithmetic/divide.js b/lib/function/arithmetic/divide.js index 8ff8cb24a..610b09a3e 100644 --- a/lib/function/arithmetic/divide.js +++ b/lib/function/arithmetic/divide.js @@ -1,19 +1,8 @@ 'use strict'; module.exports = function(math) { - var util = require('../../util/index'), - - BigNumber = math.type.BigNumber, - Complex = require('../../type/Complex'), - Matrix = require('../../type/Matrix'), - Unit = require('../../type/Unit'), - collection = require('../../type/collection'), - - isNumber = util.number.isNumber, - isBoolean = util['boolean'].isBoolean, - isComplex = Complex.isComplex, - isUnit = Unit.isUnit, - isCollection = collection.isCollection; + var collection = require('../../type/collection'); + var isCollection = collection.isCollection; /** * Divide two values, `x / y`. @@ -46,74 +35,11 @@ module.exports = function(math) { * @param {Number | BigNumber | Boolean | Complex | Array | Matrix | null} y Denominator * @return {Number | BigNumber | Complex | Unit | Array | Matrix} Quotient, `x / y` */ - math.divide = function divide(x, y) { + math.divide = function(x, y) { if (arguments.length != 2) { throw new math.error.ArgumentsError('divide', arguments.length, 2); } - if (isNumber(x)) { - if (isNumber(y)) { - // number / number - return x / y; - } - else if (isComplex(y)) { - // number / complex - return _divideComplex(new Complex(x, 0), y); - } - } - - if (isComplex(x)) { - if (isComplex(y)) { - // complex / complex - return _divideComplex(x, y); - } - else if (isNumber(y)) { - // complex / number - return _divideComplex(x, new Complex(y, 0)); - } - } - - 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.div(y); - } - - // downgrade to Number - return divide(x.toNumber(), y); - } - if (y instanceof BigNumber) { - // try to convert to big number - 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.div(y) - } - - // downgrade to Number - return divide(x, y.toNumber()); - } - - if (isUnit(x)) { - if (isNumber(y)) { - var res = x.clone(); - res.value = ((res.value === null) ? res._normalize(1) : res.value) / y; - return res; - } - } - if (isCollection(x)) { if (isCollection(y)) { // TODO: implement matrix right division using pseudo inverse @@ -124,7 +50,7 @@ module.exports = function(math) { } else { // matrix / scalar - return collection.deepMap2(x, y, divide); + return collection.deepMap2(x, y, math._divide); } } @@ -133,37 +59,7 @@ module.exports = function(math) { return math.multiply(x, math.inv(y)); } - if (isBoolean(x) || x === null) { - return divide(+x, y); - } - if (isBoolean(y) || y === null) { - return divide(x, +y); - } - - throw new math.error.UnsupportedTypeError('divide', math['typeof'](x), math['typeof'](y)); + // divide two scalars + return math._divide(x, y); }; - - /** - * Divide two complex numbers. x / y or divide(x, y) - * @param {Complex} x - * @param {Complex} y - * @return {Complex} res - * @private - */ - function _divideComplex (x, y) { - var den = y.re * y.re + y.im * y.im; - if (den != 0) { - return new Complex( - (x.re * y.re + x.im * y.im) / den, - (x.im * y.re - x.re * y.im) / den - ); - } - else { - // both y.re and y.im are zero - return new Complex( - (x.re != 0) ? (x.re / 0) : 0, - (x.im != 0) ? (x.im / 0) : 0 - ); - } - } }; diff --git a/lib/function/matrix/inv.js b/lib/function/matrix/inv.js index dffba3582..b738745a6 100644 --- a/lib/function/matrix/inv.js +++ b/lib/function/matrix/inv.js @@ -1,10 +1,8 @@ 'use strict'; module.exports = function (math) { - var util = require('../../util/index'), - string = util.string, - - Matrix = require('../../type/Matrix'); + var util = require('../../util/index'); + var Matrix = require('../../type/Matrix'); /** * Calculate the inverse of a square matrix. @@ -34,25 +32,25 @@ module.exports = function (math) { switch (size.length) { case 0: // scalar - return math.divide(1, x); + return math._divide(1, x); case 1: // vector if (size[0] == 1) { if (x instanceof Matrix) { return new Matrix([ - math.divide(1, x.valueOf()[0]) + math._divide(1, x.valueOf()[0]) ]); } else { return [ - math.divide(1, x[0]) + math._divide(1, x[0]) ]; } } else { throw new RangeError('Matrix must be square ' + - '(size: ' + string.format(size) + ')'); + '(size: ' + util.string.format(size) + ')'); } case 2: @@ -72,13 +70,13 @@ module.exports = function (math) { } else { throw new RangeError('Matrix must be square ' + - '(size: ' + string.format(size) + ')'); + '(size: ' + util.string.format(size) + ')'); } default: // multi dimensional array throw new RangeError('Matrix must be two dimensional ' + - '(size: ' + string.format(size) + ')'); + '(size: ' + util.string.format(size) + ')'); } }; @@ -100,7 +98,7 @@ module.exports = function (math) { throw Error('Cannot calculate inverse, determinant is zero'); } return [[ - math.divide(1, value) + math._divide(1, value) ]]; } else if (rows == 2) { @@ -111,12 +109,12 @@ module.exports = function (math) { } return [ [ - math.divide(matrix[1][1], d), - math.divide(math.unaryMinus(matrix[0][1]), d) + math._divide(matrix[1][1], d), + math._divide(math.unaryMinus(matrix[0][1]), d) ], [ - math.divide(math.unaryMinus(matrix[1][0]), d), - math.divide(matrix[0][0], d) + math._divide(math.unaryMinus(matrix[1][0]), d), + math._divide(matrix[0][0], d) ] ]; } @@ -163,7 +161,7 @@ module.exports = function (math) { if(r != c) { // eliminate value at column c and row r if (Ar[c] != 0) { - f = math.divide(math.unaryMinus(Ar[c]), Ac[c]); + f = math._divide(math.unaryMinus(Ar[c]), Ac[c]); // add (f * row c) to row r to eliminate the value // at column c @@ -180,10 +178,10 @@ module.exports = function (math) { // divide each value on row r with the value at Acc f = Ac[c]; for (s = c; s < cols; s++) { - Ar[s] = math.divide(Ar[s], f); + Ar[s] = math._divide(Ar[s], f); } for (s = 0; s < cols; s++) { - Br[s] = math.divide(Br[s], f); + Br[s] = math._divide(Br[s], f); } } } diff --git a/lib/math.js b/lib/math.js index 33248e6d8..521ede4ef 100644 --- a/lib/math.js +++ b/lib/math.js @@ -182,6 +182,7 @@ function create (config) { require('./function/arithmetic/add')(math, _config); require('./function/arithmetic/ceil')(math, _config); require('./function/arithmetic/cube')(math, _config); + require('./function/arithmetic/_divide')(math, _config); require('./function/arithmetic/divide')(math, _config); require('./function/arithmetic/dotDivide')(math, _config); require('./function/arithmetic/dotMultiply')(math, _config);