Fixed in mod for negative numerators. Added more input validation. Added tests

This commit is contained in:
josdejong 2013-05-29 20:14:51 +02:00
parent 33bbd402b2
commit 0b2e28403b
7 changed files with 115 additions and 49 deletions

View File

@ -14,7 +14,8 @@ https://github.com/josdejong/mathjs
- Moved the parse code from prototype math.expr.Parser to function math.parse,
simplified Parser a little bit.
- Strongly simplified the code of Scope and Workspace.
- Minor bug fixes.
- Fixed function mod for negative numerators, and added error messages in case
of wrong input.
## 2013-05-18, version 0.8.2

View File

@ -723,6 +723,7 @@ Version 2.0:
- A basic set of functions covering all common mathematical areas.
- Functions and data types for numeral systems: Bin, Oct, Hex, Dec.
- Arbitrary precision calculations with a BigNumber data type.
- Support for derived units (like km/h, kg*m/s2, etc).
## License

55
math.js
View File

@ -7,7 +7,7 @@
* mathematical functions, and a flexible expression parser.
*
* @version 0.8.3-SNAPSHOT
* @date 2013-05-27
* @date 2013-05-29
*
* @license
* Copyright (C) 2013 Jos de Jong <wjosdejong@gmail.com>
@ -5409,28 +5409,14 @@ math.mod = function mod(x, y) {
throw newArgumentsError('mod', arguments.length, 2);
}
// TODO: only handle integer values in mod?
if (isNumber(x)) {
if (isNumber(y)) {
// number % number
return x % y;
}
else if (y instanceof Complex && y.im == 0) {
// number % complex
return x % y.re;
}
}
else if (x instanceof Complex && x.im == 0) {
if (isNumber(y)) {
// complex * number
return x.re % y;
}
else if (y instanceof Complex && y.im == 0) {
// complex * complex
return x.re % y.re;
}
// see http://functions.wolfram.com/IntegerFunctions/Mod/
if (isNumber(x) && isNumber(y)) {
// number % number
return _mod(x, y);
}
// TODO: implement mod for complex values
if (x instanceof Array || x instanceof Matrix ||
y instanceof Array || y instanceof Matrix) {
@ -5445,6 +5431,33 @@ math.mod = function mod(x, y) {
throw newUnsupportedTypeError('mod', x, y);
};
/**
* Calculate the modulus of two numbers
* @param {Number} x
* @param {Number} y
* @returns {number} res
* @private
*/
function _mod(x, y) {
if (y > 0) {
if (x > 0) {
return x % y;
}
else if (x == 0) {
return 0;
}
else { // x < 0
return x - y * Math.floor(x / y);
}
}
else if (y == 0) {
return x;
}
else { // y < 0
// TODO: implement mod for a negative divisor
throw new Error('Cannot calculate mod for a negative divisor');
}
}
/**
* Multiply two values.
*

8
math.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -15,28 +15,14 @@ math.mod = function mod(x, y) {
throw newArgumentsError('mod', arguments.length, 2);
}
// TODO: only handle integer values in mod?
if (isNumber(x)) {
if (isNumber(y)) {
// number % number
return x % y;
}
else if (y instanceof Complex && y.im == 0) {
// number % complex
return x % y.re;
}
}
else if (x instanceof Complex && x.im == 0) {
if (isNumber(y)) {
// complex * number
return x.re % y;
}
else if (y instanceof Complex && y.im == 0) {
// complex * complex
return x.re % y.re;
}
// see http://functions.wolfram.com/IntegerFunctions/Mod/
if (isNumber(x) && isNumber(y)) {
// number % number
return _mod(x, y);
}
// TODO: implement mod for complex values
if (x instanceof Array || x instanceof Matrix ||
y instanceof Array || y instanceof Matrix) {
@ -50,3 +36,31 @@ math.mod = function mod(x, y) {
throw newUnsupportedTypeError('mod', x, y);
};
/**
* Calculate the modulus of two numbers
* @param {Number} x
* @param {Number} y
* @returns {number} res
* @private
*/
function _mod(x, y) {
if (y > 0) {
if (x > 0) {
return x % y;
}
else if (x == 0) {
return 0;
}
else { // x < 0
return x - y * Math.floor(x / y);
}
}
else if (y == 0) {
return x;
}
else { // y < 0
// TODO: implement mod for a negative divisor
throw new Error('Cannot calculate mod for a negative divisor');
}
}

View File

@ -1,2 +1,39 @@
// test mod
var assert = require('assert'),
approx = require('../../../tools/approx.js'),
math = require('../../../math.js'),
matrix = math.matrix,
range = math.range,
mod = math.mod;
// TODO: test mod
// test parser
approx.equal(math.eval('8 % 3'), 2);
approx.equal(math.eval('mod(8, 3)'), 2);
// test number
approx.equal(mod(7, 2), 1);
approx.equal(mod(9, 3), 0);
approx.equal(mod(10, 4), 2);
assert.throws(function () {mod(10, -4)});
approx.equal(mod(-10, 4), 2);
assert.throws(function () {mod(-10, -4)});
approx.equal(mod(8.2, 3), 2.2);
approx.equal(mod(4, 1.5), 1);
approx.equal(mod(0, 3), 0);
// test wrong number of arguments
assert.throws(function () {mod(1)}, SyntaxError);
assert.throws(function () {mod(1,2,3)}, SyntaxError);
// test complex
assert.throws(function () {mod(math.complex(1,2), 3)}, TypeError);
assert.throws(function () {mod(3, math.complex(1,2))}, TypeError);
// test string
assert.throws(function () {mod('string', 3)}, TypeError);
assert.throws(function () {mod(5, 'string')}, TypeError);
// test array, matrix, range
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]));
approx.deepEqual(mod(range(-4,4), 3), [2,0,1,2,0,1,2,0,1]);

View File

@ -1,4 +1,4 @@
// TODO: test subset
// test subset
var assert = require('assert'),
math = require('../../../math.js'),
subset = math.subset,
@ -128,7 +128,7 @@ assert.deepEqual(parser.eval('a(:,2)'), matrix([[2],[4]]));
assert.deepEqual(parser.eval('a(:,2) = [-2;-4]'), matrix([[1,-2],[3,-4]]));
assert.deepEqual(parser.eval('b=123'), 123);
assert.deepEqual(parser.eval('b(1)'), 123);
// assert.deepEqual(parser.eval('b(1,1)'), 123); // TODO: should be supported
// assert.deepEqual(parser.eval('b(1,1)'), 123); // TODO: should be supported?
assert.deepEqual(parser.eval('b(1)=456'), 456);
assert.deepEqual(parser.eval('b'), 456);
assert.deepEqual(parser.eval('c="hello"'), "hello");