diff --git a/lib/function/arithmetic/mod.js b/lib/function/arithmetic/mod.js index 02339b6d6..52349766f 100644 --- a/lib/function/arithmetic/mod.js +++ b/lib/function/arithmetic/mod.js @@ -1,7 +1,9 @@ 'use strict'; function factory (type, config, load, typed) { - var collection = load(require('../../type/collection')); + + var matrix = load(require('../construction/matrix')); + var elementWiseOperations = load(require('../../type/matrix/util/elementWiseOperations')); /** * Calculates the modulus, the remainder of an integer division. @@ -39,18 +41,100 @@ function factory (type, config, load, typed) { * @return {Number | BigNumber | Array | Matrix} Returns the remainder of `x` divided by `y`. */ var mod = typed('mod', { + 'number, number': _mod, 'BigNumber, BigNumber': function (x, y) { return y.isZero() ? x : x.mod(y); }, + + 'Matrix, Matrix': function (x, y) { + // result + var c; - 'Array | Matrix, any': function (x, y) { - return collection.deepMap2(x, y, mod); + // process matrix storage + switch (x.storage()) { + case 'sparse': + switch (y.storage()) { + case 'sparse': + // mod(sparse, sparse) + c = elementWiseOperations.algorithm5(x, y, mod, false); + break; + default: + // mod(sparse, dense) + c = elementWiseOperations.algorithm2(y, x, mod, true); + break; + } + break; + default: + switch (y.storage()) { + case 'sparse': + // mod(dense, sparse) + c = elementWiseOperations.algorithm3(x, y, mod, false); + break; + default: + // mod(dense, dense) + c = elementWiseOperations.algorithm11(x, y, mod, false); + break; + } + break; + } + return c; + }, + + 'Array, Array': function (x, y) { + // use matrix implementation + return mod(matrix(x), matrix(y)).valueOf(); }, - 'any, Array | Matrix': function (x, y) { - return collection.deepMap2(x, y, mod); + 'Array, Matrix': function (x, y) { + // use matrix implementation + return mod(matrix(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return mod(x, matrix(y)); + }, + + 'Matrix, any': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = elementWiseOperations.algorithm9(x, y, mod, false); + break; + default: + c = elementWiseOperations.algorithm12(x, y, mod, false); + break; + } + return c; + }, + + 'any, Matrix': function (x, y) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = elementWiseOperations.algorithm10(y, x, mod, true); + break; + default: + c = elementWiseOperations.algorithm12(y, x, mod, true); + break; + } + return c; + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return elementWiseOperations.algorithm12(matrix(x), y, mod, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return elementWiseOperations.algorithm12(matrix(y), x, mod, true).valueOf(); } }); diff --git a/lib/function/arithmetic/round.js b/lib/function/arithmetic/round.js index 194677fb9..efb1e4ea6 100644 --- a/lib/function/arithmetic/round.js +++ b/lib/function/arithmetic/round.js @@ -4,7 +4,12 @@ var isInteger = require('../../util/number').isInteger; var toFixed = require('../../util/number').toFixed; function factory (type, config, load, typed) { + var collection = load(require('../../type/collection')); + var matrix = load(require('../construction/matrix')); + var equal = load(require('../relational/equal')); + var zeros = load(require('../matrix/zeros')); + var elementWiseOperations = load(require('../../type/matrix/util/elementWiseOperations')); /** * Round a value towards the nearest integer. @@ -38,6 +43,7 @@ function factory (type, config, load, typed) { * @return {Number | BigNumber | Complex | Array | Matrix} Rounded value */ var round = typed('round', { + 'number': Math.round, 'number, number': function (x, n) { @@ -84,12 +90,49 @@ function factory (type, config, load, typed) { return collection.deepMap(x, round, true); }, - 'Array | Matrix, number | BigNumber': function (x, n) { - return collection.deepMap2(x, n, round); + 'Matrix, number | BigNumber': function (x, y) { + // result + var c; + // check storage format + switch (x.storage()) { + case 'sparse': + c = elementWiseOperations.algorithm9(x, y, round, false); + break; + default: + c = elementWiseOperations.algorithm12(x, y, round, false); + break; + } + return c; }, - 'number | Complex | BigNumber, Array | Matrix': function (x, n) { - return collection.deepMap2(x, n, round); + 'number | Complex | BigNumber, Matrix': function (x, y) { + // check scalar is zero + if (!equal(x, 0)) { + // result + var c; + // check storage format + switch (y.storage()) { + case 'sparse': + c = elementWiseOperations.algorithm10(y, x, round, true); + break; + default: + c = elementWiseOperations.algorithm12(y, x, round, true); + break; + } + return c; + } + // do not execute algorithm, result will be a zero matrix + return zeros(y.size(), y.storage()); + }, + + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return elementWiseOperations.algorithm12(matrix(x), y, round, false).valueOf(); + }, + + 'number | Complex | BigNumber, Array': function (x, y) { + // use matrix implementation + return elementWiseOperations.algorithm12(matrix(y), x, round, true).valueOf(); } }); diff --git a/test/function/arithmetic/mod.test.js b/test/function/arithmetic/mod.test.js index 7a9b0e7fb..508b244c9 100644 --- a/test/function/arithmetic/mod.test.js +++ b/test/function/arithmetic/mod.test.js @@ -4,10 +4,11 @@ var approx = require('../../../tools/approx'); var math = require('../../../index'); var bignumber = math.bignumber; var matrix = math.matrix; -var range = math.range; +var sparse = math.sparse; var mod = math.mod; describe('mod', function() { + it('should calculate the modulus of booleans correctly', function () { assert.equal(mod(true, true), 0); assert.equal(mod(false, true), 0); @@ -38,17 +39,17 @@ describe('mod', function() { }); it('should throw an error if the modulus is negative', function() { - assert.throws(function () {mod(10, -4)}); + assert.throws(function () {mod(10, -4);}); }); it('should throw an error if used with wrong number of arguments', function() { - assert.throws(function () {mod(1)}, /TypeError: Too few arguments/); - assert.throws(function () {mod(1,2,3)}, /TypeError: Too many arguments/); + assert.throws(function () {mod(1);}, /TypeError: Too few arguments/); + assert.throws(function () {mod(1,2,3);}, /TypeError: Too many arguments/); }); it('should throw an error if used with wrong type of arguments', function() { - assert.throws(function () {mod(1, 'string')}, /TypeError: Unexpected type of argument/); - assert.throws(function () {mod('string', bignumber(2))}, /TypeError: Unexpected type of argument/); + assert.throws(function () {mod(1, 'string');}, /TypeError: Unexpected type of argument/); + assert.throws(function () {mod('string', bignumber(2));}, /TypeError: Unexpected type of argument/); }); it('should calculate the modulus of bignumbers', function() { @@ -75,8 +76,8 @@ describe('mod', function() { assert.deepEqual(mod(bignumber(0), 3), bignumber(0)); assert.deepEqual(mod(bignumber(7), 0), bignumber(7)); - assert.throws(function () {mod(7/3, bignumber(2))}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); - assert.throws(function () {mod(bignumber(7).div(3), 1/3)}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {mod(7/3, bignumber(2));}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); + assert.throws(function () {mod(bignumber(7).div(3), 1/3);}, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/); }); it('should calculate the modulus of mixed booleans and bignumbers', function() { @@ -87,24 +88,78 @@ describe('mod', function() { }); it('should throw an error if used on complex numbers', function() { - assert.throws(function () {mod(math.complex(1,2), 3)}, TypeError); - assert.throws(function () {mod(3, math.complex(1,2))}, TypeError); - assert.throws(function () {mod(bignumber(3), math.complex(1,2))}, TypeError); + assert.throws(function () {mod(math.complex(1,2), 3);}, TypeError); + assert.throws(function () {mod(3, math.complex(1,2));}, TypeError); + assert.throws(function () {mod(bignumber(3), math.complex(1,2));}, TypeError); }); it('should an throw an error if used on a string', function() { - assert.throws(function () {mod('string', 3)}, TypeError); - assert.throws(function () {mod(5, 'string')}, TypeError); + assert.throws(function () {mod('string', 3);}, TypeError); + assert.throws(function () {mod(5, 'string');}, TypeError); }); - it('should perform element-wise modulus on a matrix', function() { - approx.deepEqual(mod([-4,-3,-2,-1,0,1,2,3,4], 3), [2,0,1,2,0,1,2,0,1]); - approx.deepEqual(mod(matrix([-4,-3,-2,-1,0,1,2,3,4]), 3), matrix([2,0,1,2,0,1,2,0,1])); + describe('Array', function () { + + it('should perform element-wise modulus on array and scalar', function() { + approx.deepEqual(mod([[-4, -3, 0, -1], [0, 1, 2, 3]], 3), [[2, 0, 0, 2], [0, 1, 2, 0]]); + approx.deepEqual(mod(3, [[4, 3], [2, 1]]), [[3, 0], [1, 0]]); + }); + + it('should perform element-wise modulus on array and array', function() { + approx.deepEqual(mod([[-40, -31], [11, -23]], [[3, 7], [1, 3]]), [[2, 4], [0, 1]]); + }); + + it('should perform element-wise modulus on array and dense matrix', function() { + approx.deepEqual(mod([[-40, -31], [11, -23]], matrix([[3, 7], [1, 3]])), matrix([[2, 4], [0, 1]])); + }); + + it('should perform element-wise modulus on array and sparse matrix', function() { + approx.deepEqual(mod([[-40, -31], [11, -23]], sparse([[3, 7], [1, 3]])), matrix([[2, 4], [0, 1]])); + }); }); + describe('DenseMatrix', function () { + + it('should perform element-wise modulus on dense matrix and scalar', function() { + approx.deepEqual(mod(matrix([[-4, -3, 0, -1], [0, 1, 2, 3]]), 3), matrix([[2, 0, 0, 2], [0, 1, 2, 0]])); + approx.deepEqual(mod(3, matrix([[4, 3], [2, 1]])), matrix([[3, 0], [1, 0]])); + }); + + it('should perform element-wise modulus on dense matrix and array', function() { + approx.deepEqual(mod(matrix([[-40, -31], [11, -23]]), [[3, 7], [1, 3]]), matrix([[2, 4], [0, 1]])); + }); + + it('should perform element-wise modulus on dense matrix and dense matrix', function() { + approx.deepEqual(mod(matrix([[-40, -31], [11, -23]]), matrix([[3, 7], [1, 3]])), matrix([[2, 4], [0, 1]])); + }); + + it('should perform element-wise modulus on dense matrix and sparse matrix', function() { + approx.deepEqual(mod(matrix([[-40, -31], [11, -23]]), sparse([[3, 7], [1, 3]])), matrix([[2, 4], [0, 1]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should perform element-wise modulus on sparse matrix and scalar', function() { + approx.deepEqual(mod(sparse([[-4, -3, 0, -1], [0, 1, 2, 3]]), 3), sparse([[2, 0, 0, 2], [0, 1, 2, 0]])); + approx.deepEqual(mod(3, sparse([[4, 3], [2, 1]])), matrix([[3, 0], [1, 0]])); + }); + + it('should perform element-wise modulus on sparse matrix and array', function() { + approx.deepEqual(mod(sparse([[-40, -31], [11, -23]]), [[3, 7], [1, 3]]), sparse([[2, 4], [0, 1]])); + }); + + it('should perform element-wise modulus on sparse matrix and dense matrix', function() { + approx.deepEqual(mod(sparse([[-40, -31], [11, -23]]), matrix([[3, 7], [1, 3]])), sparse([[2, 4], [0, 1]])); + }); + + it('should perform element-wise modulus on sparse matrix and sparse matrix', function() { + approx.deepEqual(mod(sparse([[-40, -31], [11, -23]]), sparse([[3, 7], [1, 3]])), sparse([[2, 4], [0, 1]])); + }); + }); + it('should LaTeX mod', function () { var expression = math.parse('mod(11,2)'); assert.equal(expression.toTex(), '\\left(11\\mod2\\right)'); }); - }); diff --git a/test/function/arithmetic/round.test.js b/test/function/arithmetic/round.test.js index 4bbed2ac4..5cb2f7dcd 100644 --- a/test/function/arithmetic/round.test.js +++ b/test/function/arithmetic/round.test.js @@ -1,9 +1,10 @@ // test round var assert = require('assert'), approx = require('../../../tools/approx'), - error = require('../../../lib/error/index'), math = require('../../../index'), bignumber = math.bignumber, + matrix = math.matrix, + sparse = math.sparse, round = math.round; describe('round', function() { @@ -83,6 +84,42 @@ describe('round', function() { assert.deepEqual(round([1.7,2.3]), [2,2]); assert.deepEqual(round(math.matrix([1.7,2.3])).valueOf(), [2, 2]); }); + + describe('Array', function () { + + it('should round array', function () { + assert.deepEqual(round([1.7, 2.3]), [2, 2]); + }); + + it('should round array and scalar', function () { + assert.deepEqual(round([1.7777, 2.3456], 3), [1.778, 2.346]); + assert.deepEqual(round(3.12385, [2, 3]), [3.12, 3.124]); + }); + }); + + describe('DenseMatrix', function () { + + it('should round dense matrix', function () { + assert.deepEqual(round(matrix([[1.7, 2.3], [8.987, -3.565]])), matrix([[2, 2], [9, -4]])); + }); + + it('should round dense matrix and scalar', function () { + assert.deepEqual(round(matrix([[1.7777, 2.3456],[-90.8272, 0]]), 3), matrix([[1.778, 2.346], [-90.827, 0]])); + assert.deepEqual(round(3.12385, matrix([[2, 3], [0, 2]])), matrix([[3.12, 3.124],[3, 3.12]])); + }); + }); + + describe('SparseMatrix', function () { + + it('should round sparse matrix', function () { + assert.deepEqual(round(sparse([[1.7, 0], [8.987, -3.565]])), sparse([[2, 0], [9, -4]])); + }); + + it('should round sparse matrix and scalar', function () { + assert.deepEqual(round(sparse([[1.7777, 2.3456],[-90.8272, 0]]), 3), sparse([[1.778, 2.346], [-90.827, 0]])); + assert.deepEqual(round(3.12385, sparse([[2, 3], [0, 2]])), matrix([[3.12, 3.124],[3, 3.12]])); + }); + }); it('should LaTeX round', function () { var expr1 = math.parse('round(1.1)');