Subversion Repositories JSX

Compare Revisions

Last modification

Ignore whitespace Rev 524 → Rev 525

/trunk/math/float.js
4,12 → 4,12
* @requires types.js
*
* @section Copyright & Disclaimer
*
*
* @author
* (C) 2000-2012 Thomas Lahn <math.js@PointedEars.de>
*
* @partof PointedEars' JavaScript Extensions (JSX)
*
*
* JSX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
42,7 → 42,7
 
/**
* Returns the numerical value of an object.
*
*
* @param obj : Object
* @return {number}
* <code>NaN</code> if <var>obj</var> does not refer to an object
55,18 → 55,18
&& typeof obj.valueOf == "function")
? obj.valueOf()
: value;
 
if (typeof value == "number")
{
return value;
}
 
return NaN;
};
 
/**
* Returns the value of the smallest argument.
*
*
* @return {number}
* The value of the smallest argument.
* If an argument is an object but not an <code>Array</code>,
80,11 → 80,11
*/
jsx.math.min = (function () {
var getValue = jsx.math.getValue;
 
return function () {
var result = Number.POSITIVE_INFINITY;
var min_el;
 
for (var i = 0, len = arguments.length; i < len; ++i)
{
var a = arguments[i];
123,7 → 123,7
result = a;
}
}
 
return result;
};
}());
130,7 → 130,7
 
/**
* Returns the value of the greatest argument.
*
*
* @return {number}
* The value of the greatest argument.
* If an argument is an object but not an <code>Array</code>,
144,10 → 144,10
*/
jsx.math.max = (function () {
var getValue = jsx.math.getValue;
 
return function () {
var result = Number.NEGATIVE_INFINITY;
 
for (var i = 0, len = arguments.length; i < len; ++i)
{
var a = arguments[i], max_el;
186,7 → 186,7
result = a;
}
}
 
return result;
};
}());
193,7 → 193,7
 
/**
* Returns the average value of the arguments.
*
*
* @return number
* The average value of the arguments.
* If an argument is an object but not an <code>Array</code>,
206,11 → 206,11
*/
jsx.math.avg = (function () {
var getValue = jsx.math.getValue;
 
return function () {
var sum = 0;
var count = 0;
 
for (var i = 0, len = arguments.length; i < len; i++)
{
var a = arguments[i];
245,7 → 245,7
sum += parseFloat(a);
}
}
 
return (sum / count);
};
}());
252,7 → 252,7
 
/**
* Returns the arithmetic median of the arguments.
*
*
* The [arithmetic (one-dimensional)] median is [defined] as
* the numerical value separating the higher half of a sample
* from the lower half of a sample. If there is an even number
259,7 → 259,7
* of observations, then there is no single middle value; the
* median is then […] defined to be the mean of the two middle
* values. (From Wikipedia, the free encyclopedia)
*
*
* @return number
* The arithmetic median of the arguments.
* If an argument is an object but not an <code>Array</code>,
272,11 → 272,11
*/
jsx.math.median = (function () {
var getValue = jsx.math.getValue;
 
return function () {
var values = [];
var result;
 
for (var i = 0, len = arguments.length; i < len; i++)
{
var a = arguments[i];
307,9 → 307,9
values.push(parseFloat(a));
}
}
 
values.sort(function (a, b) { return a - b; });
 
len = values.length;
if (len > 1)
{
409,7 → 409,7
they could succeed
*/
}
 
var e = Math.pow(10, n);
 
var k = (Math.round(x * e) / e).toString();
417,7 → 417,7
and not all JavaScript capable browsers support it.
Use the String(...) function instead.
*/
 
if (k.indexOf('.') == -1){k += '.';
/* Sometimes it is not desired to have the decimal point
when dealing with integers. The function does not allow
470,7 → 470,7
{
iSigDecimals = 0;
}
 
/*
* Returns the number itself when called with invalid arguments,
* so further calculations will not fail because of a wrong
488,14 → 488,14
{
i = String(n).length - 1;
}
 
if (String(n).substring(0, i).length <= -iSigDecimals)
{
return n;
}
 
var k = Math.round(n * e) / e;
 
if (arguments.length < 3)
{
iForceDecimals = 0;
508,7 → 508,7
{
k += ".";
}
 
for (i = k.slice(k.indexOf(".") + 1).length;
i < iForceDecimals;
i++)
516,7 → 516,7
k += "0";
}
}
 
if (bForceLeadingZero && String(k).charAt(0) == ".")
{
k = "0" + k;
536,7 → 536,7
k = k.substring(0, i) + sDecSeparator + k.slice(i + 1);
}
}
 
return k;
};
 
568,7 → 568,7
var
currentPeriod = s.substring(2, i),
rx = new RegExp("^\\d*\\.\\d*(" + currentPeriod + ")+$");
 
if (rx.test(s))
{
return currentPeriod;
589,13 → 589,13
* II: 10x = 1.111111111111111
* II - I: 9x = 1
* x = 1/9
*
*
* 1. Y = periodLength(X)
* 2. Z = X * 10^Y
* 3. A = Z - X
* 4. RESULT = 'A "/" (10^Y - 1)'
*/
 
var y = jsx.math.getPeriod(fDec).length;
var z = fDec * Math.pow(10, y);
var dividend = Math.round(z - fDec);
608,9 → 608,9
dividend /= d;
divisor /= d;
}
 
var result = dividend + "/" + divisor;
 
return result;
};
 
622,106 → 622,61
jsx.math.UNIT_GRAD = 2;
 
/**
* Unlike the {@link js#Math built-in methods}, the following
* functions accept a second argument to determine if the argument
* should be handled as radian (dtRad == 0 [default];
* x = n*[0..2*Math.PI], degree (dtDeg == 1; x = n*[0..360])
* or gradian (dtGrad == 2; x = n*[0..400] gon) value.
* Converts an angle to another unit
*
* @param {Number} value
* Angle to convert
* @param {number} unit2
* Target unit. Use the {@link jsx.math.UNIT_RAD jsx.math.UNIT_*})
* properties.
* @param {number} unit1
* Source unit. The default is radians ({@link jsx.math.UNIT_RAD}).
*/
 
/**
* Returns the sine of an angle.
*
* Call this method instead of <code>jsx.math.sinX()</code>,
* which is deprecated.
*
* @param x : number
* @param iArgType : number
* @return number
* The sine of <var>x</var>
*/
jsx.math.sin = function(x, iArgType) {
switch (iArgType)
jsx.math.convertAngle = function (value, unit2, unit1) {
switch (unit1)
{
case jsx.math.UNIT_DEG:
x = x/180 * Math.PI;
value = value/180 * Math.PI;
break;
 
case jsx.math.UNIT_GRAD:
x = x/200 * Math.PI;
value = value/200 * Math.PI;
break;
}
 
return Math.sin(x);
};
 
/* (non-JSdoc)
* @deprecated
*/
jsx.math.sinX = jsx.math.sin;
 
/**
* Returns the cosine of an angle.
*
* Call this method instead of <code>jsx.math.cosX()</code>,
* which is deprecated.
*
* @param x : number
* @param iArgType : number
* @return number
* The cosine of <var>x</var>
*/
jsx.math.cos = function(x, iArgType) {
switch (iArgType)
switch (unit2)
{
case jsx.math.UNIT_DEG:
x = x/180 * Math.PI;
value = value / Math.PI * 180;
break;
 
case jsx.math.UNIT_GRAD:
x = x/200 * Math.PI;
value = value / Math.PI * 200;
}
return Math.cos(x);
 
return value;
};
 
/* (non-JSdoc)
* @deprecated
*/
jsx.math.cosX = jsx.math.cos;
 
/**
* Returns the tangent of an angle.
*
*
* Call this method instead of <code>jsx.math.tanX()</code>,
* which is deprecated.
*
* @param x : number
* @param iArgType : number
* @return number
* The tangent of <var>x</var>. If @link{js#Math.tan()} is
* undefined, it uses @link{jsx.math#sin()} and
* @link{jsx.math#cos()}.
*
* @param {number} x
* @return {number}
* The tangent of <var>x</var>. If {@link Math.tan()} is
* not a function, it uses {@link Math.sin()} and
* {@link Math.cos()}.
* @requires jsx.object#isMethod()
*/
jsx.math.tan = function(x, iArgType) {
var jsx_object = jsx.object;
switch (iArgType)
jsx.math.tan = function (x) {
if (typeof Math.tan == "function")
{
case jsx.math.UNIT_DEG:
x = x/180 * Math.PI;
break;
case jsx.math.UNIT_GRAD:
x = x/200 * Math.PI;
}
if (jsx_object.isMethod(Math, "tan"))
{
return Math.tan(x);
}
return (jsx.math.sin(x) / jsx.math.cos(x));
 
return (Math.sin(x) / Math.cos(x));
};
 
/* (non-JSdoc)
729,89 → 684,6
*/
jsx.math.tanX = jsx.math.tan;
 
/** @subsection Complex numbers */
 
/**
* @param nRe : number
* @param nIm : number
*/
jsx.math.Complex = function (nRe, nIm) {
Number.call(this);
this.re = Number(nRe) || 0;
this.im = Number(nIm) || 0;
};
 
jsx.math.Complex.extend(Number);
 
/**
* @param a : Complex
* @param b : Complex
* @return Complex
* The complex sum of <var>a</var> and <var>b</var>
*/
jsx.math.addComplex =
jsx.math.Complex.prototype.add = function (a, b) {
var result = null;
var math = jsx.math;
 
if (this instanceof math.Complex)
{
b = a;
a = this;
}
 
if (a && b)
{
if (!(a instanceof math.Complex))
{
a = new math.Complex(a);
}
 
if (!(b instanceof math.Complex))
{
b = new math.Complex(b);
}
 
return new math.Complex(a.re + b.re, a.im + b.im);
}
};
 
/**
* @param a : Complex
* @param b : Complex
* @return Complex
* The complex product of <var>a</var> and <var>b</var>
*/
jsx.math.mulComplex =
jsx.math.Complex.prototype.mul = function(a, b) {
var result = null;
 
if (this instanceof jsx.math.Complex)
{
b = a;
a = this;
}
 
if (a && b)
{
if (!(a instanceof jsx.math.Complex))
{
a = new jsx.math.Complex(a);
}
 
if (!(b instanceof jsx.math.Complex))
{
b = new jsx.math.Complex(b);
}
// a.re, a.im b.re, b.im
// (a, b ) * (c, d ) = (a * c - b * d, a * d + b * c)
return new jsx.math.Complex(
a.re * b.re - a.im * b.im,
a.re * b.im + a.im * b.re);
}
};
 
/*
* TODO: Hyperbolic functions
*/
/trunk/math/complex.js
0,0 → 1,218
/**
* <title>PointedEars' JSX: Math Library: Complex arithmetics</title>
* @requires math.js
*
* @section Copyright & Disclaimer
*
* @author
* (C) 2013 Thomas Lahn &lt;math.js@PointedEars.de&gt;
*
* @partof PointedEars' JavaScript Extensions (JSX)
*
* JSX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JSX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JSX. If not, see <http://www.gnu.org/licenses/>.
*/
 
/**
* @namespace
*/
jsx.math.complex = (/** @constructor */ function () {
/* Imports */
var _isObject = jsx.object.isObject;
var _math = jsx.math;
var _add = _math.add;
var _sub = _math.sub;
var _mul = _math.mul;
var _div = _math.div;
var _pow = _math.pow;
var _sqrt = _math.sqrt;
 
/* Private variables */
var _rx_decimal_integer_literal = /(?:0|[1-9]\d*)/;
var _rx_exponent_part = /[eE][+-]?\d+/;
var _rx_decimal_literal = new RegExp(
_rx_decimal_integer_literal.source + "(?:\\.\\d*)?(?:" + _rx_exponent_part.source + ")?");
var _rx_hex_integer_literal = /0[xX][0-9a-fA-F]+(?:\.[0-9a-fA-F]*)?/;
var _rx_numeric_literal = new RegExp(
"((" + _rx_hex_integer_literal.source + ")|" + _rx_decimal_literal.source + ")");
var _rx_complex_literal = new RegExp(
"^\\s*" + _rx_numeric_literal.source
+ "\\s*(?:([+-])\\s*" + _rx_numeric_literal.source + "[ij])?");
 
/**
* A complex number consists of a real and an imaginary part.
*
* It can be visualized as being an point in a plane with a
* two-dimensional Cartesian coordinate system in which
* the real part is measured on one axis and the imaginary
* part on the other.
*
* @function
*/
var _Complex = jsx.object.extend(
/**
* @constructor
* @param {Number} re
* @param {Number} im
*/
function (re, im) {
if (!(this instanceof _Complex))
{
return new _Complex(re, im);
}
 
this.re = _isObject(re) ? re : +re;
this.im = _isObject(im) ? im : +im;
},
{
/**
* @memberOf jsx.math.complex.Complex
* @param {String} s
*/
parse: function (s) {
var m = s.match(_rx_complex_literal);
if (!m || !m[1])
{
return Number.NaN;
}
 
return new _Complex(
parseFloat(m[1], m[2] ? 16 : 10),
(m[3] == "-" ? -1 : 1) * parseFloat(m[4], m[5] ? 16 : 10) || 0);
}
}
).extend(Number, {
/**
* @memberOf jsx.math.complex.Complex.prototype
* @param {_Complex} a
* @param {_Complex} b
* @return {_Complex}
* The complex sum of <var>a</var> and <var>b</var>
*/
add: function (operand) {
if (!(operand instanceof _Complex))
{
operand = new _Complex(operand);
}
 
return new _Complex(_add(this.re, operand.re), _add(this.im, operand.im));
},
 
/**
* @param {_Complex} a
* @param {_Complex} b
* @return {_Complex}
* The complex product of <var>a</var> and <var>b</var>
*/
mul: function (operand) {
var result = null;
 
if (!(operand instanceof _Complex))
{
operand = new _Complex(operand);
}
 
// a.re, a.im b.re, b.im
// (a, b ) * (c, d ) = (a * c - b * d, a * d + b * c)
return new _Complex(
_sub(_mul(this.re, operand.re), _mul(this.im, operand.im)),
_add(_mul(this.re, operand.im), _mul(this.im, operand.re)));
},
 
sqrt: function () {
function sgn (x)
{
if (x == 0)
{
return 0;
}
return x / Math.abs(x);
}
 
if (this.im == 0)
{
return _sqrt(this.re);
}
 
return new _Complex(
_sqrt(
_div(
_add(
this.re,
_sqrt(_add(_pow(this.re, 2), _pow(this.im, 2)))
),
2
)
),
_mul(
sgn(this.im),
_sqrt(
_div(
_add(
_mul(this.re, -1),
_sqrt(_add(_pow(this.re, 2), _pow(this.im, 2)))
),
2
)
)
)
);
},
 
/**
* Returns this object as a string.
*
* (<code>{re: 1, im: 2}</code> → <code>"1 + 2j"</code>)
*
* @param {string} imUnit
* The unit to use for the imaginary part. The default
* is <code>"j"</code> (see above), but sometimes people
* prefer <code>"i"</code> and can pass that instead.
* @return {string}
*/
toString: function (imUnit) {
if (!imUnit)
{
imUnit = "j";
}
 
var re = this.re;
var im = this.im;
 
return ((re || "")
+ (im
? (re && im >= 0 ? "+" : "") + im + imUnit
: ""))
|| "0";
},
 
/**
* @return {number|_Complex}
*/
valueOf: function () {
if (!this.im)
{
return new this.re;
}
 
return this;
}
});
 
return {
/**
* @memberOf jsx.math.complex
*/
Complex: _Complex
};
}());
Property changes:
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: trunk/math/rational.js
===================================================================
--- trunk/math/rational.js (nonexistent)
+++ trunk/math/rational.js (revision 525)
@@ -0,0 +1,376 @@
+/**
+ * <title>PointedEars' JSX: Math Library: Rational arithmetics</title>
+ * @requires object.js
+ * @requires types.js
+ *
+ * @section Copyright & Disclaimer
+ *
+ * @author
+ * (C) 2013 Thomas Lahn &lt;math.js@PointedEars.de&gt;
+ *
+ * @partof PointedEars' JavaScript Extensions (JSX)
+ *
+ * JSX is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JSX is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JSX. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+if (typeof jsx == "undefined")
+{
+ /**
+ * @namespace
+ */
+ var jsx = {};
+}
+
+if (typeof jsx.math == "undefined")
+{
+ /**
+ * @namespace
+ */
+ jsx.math = {};
+}
+
+/**
+ * @namespace
+ */
+jsx.math.rational = (function () {
+ /* Imports */
+ var _gcd;
+ function _get_gcd ()
+ {
+ if (!_gcd)
+ {
+ _gcd = jsx.math.integer.gcd;
+ }
+
+ return _gcd;
+ }
+
+ /**
+ * Returns the value of this fraction as a {@link Number}.
+ *
+ * @return {number}
+ */
+ function _toNumber ()
+ {
+ return this.numerator / this.denominator;
+ }
+
+ var _rx = /((\d+)\s+)?(\d+)[\/∕](\d+)/;
+
+ var _Fraction = jsx.object.extend(
+ /**
+ * A fraction is a rational number, a numerator divided by
+ * a denominator.
+ *
+ * @constructor
+ * @param {jsx.math.rational.Fraction|Number|String} numerator
+ * @param {Number} denominator
+ * @param {boolean} _dontReduce
+ * <code>true</code> if the fraction should not be reduced
+ * even though {@link jsx.math.rational.Fraction.autoreduce}
+ * is set. Required for proper operation of some calling methods.
+ */
+ function jsx_math_rational_Fraction (numerator, denominator, _dontReduce) {
+ /* Called as a function? */
+ if (!(this instanceof _Fraction))
+ {
+ return new _Fraction(numerator, denominator, _dontReduce);
+ }
+
+ if (numerator instanceof _Fraction)
+ {
+ /* Clone object */
+ var num = numerator.numerator;
+ var denom = numerator.denominator;
+ }
+ else if (numerator && typeof numerator.valueOf() == "string")
+ {
+ /* Parse fraction string */
+ var m;
+ if ((m = numerator.match(_rx)))
+ {
+ var integer_part = m[2];
+ num = m[3];
+ denom = m[4];
+
+ if (integer_part)
+ {
+ num = (+num) + (integer_part) * denom;
+ }
+ }
+ else
+ {
+ jsx.throwThis(jsx.InvalidArgumentError);
+ }
+ }
+ else
+ {
+ num = numerator;
+ denom = (typeof denominator != "undefined" ? denominator : 1);
+ }
+
+ this.numerator = +num;
+ this.denominator = +denom;
+
+ if (_Fraction.autoReduce && !_dontReduce)
+ {
+ return this.reduce();
+ }
+ },
+ {
+ /**
+ * If <code>true</code> calls
+ * {@link jsx.math.rational.Fraction.prototype.reduce() reduce()}
+ * on results automatically. The default is <code>false</code>
+ * for better performance.
+ *
+ * @memberOf jsx.math.rational.Fraction
+ */
+ autoReduce: false,
+
+ /**
+ * Converts two fractions into like quantities
+ * and returns the result.
+ *
+ * <code>(</code>1∕2<code>,</code> 2∕3<code>)</code>
+ * → <code>[</code>3∕6<code>,</code> 4∕6<code>]</code>
+ *
+ * @param {_Fraction} a
+ * @param {_Fraction} b
+ * @return {Array[_Fraction, _Fraction]}
+ */
+ like: function (a, b) {
+ if (!(a instanceof _Fraction))
+ {
+ a = new _Fraction(a);
+ }
+
+ if (!(b instanceof _Fraction))
+ {
+ b = new _Fraction(b);
+ }
+
+ var denom = a.denominator * b.denominator;
+
+ return [
+ new _Fraction(a.numerator * b.denominator, denom, true),
+ new _Fraction(b.numerator * a.denominator, denom, true)
+ ];
+ }
+ }
+ ).extend(null, {
+ /* Unary operators */
+ /**
+ * Returns the complement of this fraction with regard to addition.
+ *
+ * 1∕2 → −1∕2
+ *
+ * @memberOf jsx.math.rational.Fraction.prototype
+ * @return {_Fraction}
+ */
+ negate: function () {
+ return new _Fraction(-this.numerator, this.denominator);
+ },
+
+ /* Binary operators */
+ /**
+ * Adds two fractions and returns the result.
+ *
+ * (1∕2) + (2∕3) → 7∕6
+ *
+ * @param {_Fraction} operand
+ * @return {_Fraction}
+ */
+ add: function (operand) {
+ if (!(operand instanceof _Fraction))
+ {
+ operand = new _Fraction(operand);
+ }
+
+ var likes = _Fraction.like(this, operand);
+
+ return new _Fraction(
+ likes[0].numerator + likes[1].numerator,
+ likes[0].denominator
+ );
+ },
+
+ /**
+ * Subtracts a fraction from another and returns the result.
+ *
+ * (2∕3) − (1∕2) ≡ (2∕3) + (−1∕2) → 1∕6
+ *
+ * @param {_Fraction} operand
+ * @return {_Fraction}
+ */
+ subtract: function (operand) {
+ if (!(operand instanceof _Fraction))
+ {
+ operand = new _Fraction(operand);
+ }
+
+ return this.add(this, operand.negate());
+ },
+
+ /**
+ * Multiplies two fractions and returns the result.
+ *
+ * (1∕2) × (2∕3) → 2∕6
+ *
+ * @param {_Fraction} operand
+ * @return {_Fraction}
+ */
+ multiply: function (operand) {
+ if (!(operand instanceof _Fraction))
+ {
+ operand = new _Fraction(operand);
+ }
+
+ return new _Fraction(
+ this.numerator * operand.numerator,
+ this.denominator * operand.denominator
+ );
+ },
+
+ /**
+ * Divides a fraction by another and returns the result.
+ *
+ * (1∕2) ∕ (4∕6) ≡ (1∕2) × (6∕4) → 6∕8
+ * @param {_Fraction} operand
+ * @return {_Fraction}
+ */
+ divide: function (operand) {
+ if (!(operand instanceof _Fraction))
+ {
+ operand = new _Fraction(operand);
+ }
+
+ return new _Fraction(
+ this.numerator * operand.denominator,
+ this.denominator * operand.numerator
+ );
+ },
+
+ /* Equivalent transformations */
+ /**
+ * Extends a fraction by a factor.
+ *
+ * 1∕2 × 2 → 2∕4
+ *
+ * @param {Number} factor
+ * @return {_Fraction}
+ * @see #reduce()
+ */
+ extend: function (factor) {
+ return this.multiply(new _Fraction(factor, factor));
+ },
+
+ /**
+ * Reduces a fraction to its simplest equivalent.
+ *
+ * 4∕8 → 1∕2
+ *
+ * @return {_Fraction}
+ * @see #extend()
+ */
+ reduce: function () {
+ var num = this.numerator;
+ var denom = this.denominator;
+ var gcd = _get_gcd()(num, denom);
+
+ if (gcd > 1)
+ {
+ return new _Fraction(num / gcd, denom / gcd, true);
+ }
+
+ return new _Fraction(this, null, true);
+ },
+
+ /**
+ * Returns the reciprocal of this fraction.
+ *
+ * 2∕3 → 3∕2
+ *
+ * @return {_Fraction}
+ */
+ reciprocal: function () {
+ return new _Fraction(this.denominator, this.numerator);
+ },
+
+ toNumber: _toNumber,
+
+ /* Conversion */
+ /**
+ * Returns the string representation of this fraction.
+ *
+ * @return {string}
+ */
+ toString: function () {
+ var num = this.numerator;
+ var denom = this.denominator;
+ return (num ? num + (denom != 1 ? "/" + denom : "") : "0");
+ },
+
+ /**
+ * Returns this fraction as a vulgar fraction.
+ *
+ * 5∕3 → <code>[1, </code>2∕3<code>]</code>
+ *
+ * @return {Array[int, _Fraction]}
+ */
+ toVulgar: function () {
+ var integer_part =
+ (this.numerator - (this.numerator % this.denominator))
+ / this.denominator;
+
+ return [
+ integer_part,
+ new _Fraction(
+ this.numerator - (integer_part * this.denominator),
+ this.denominator
+ )
+ ];
+ },
+
+ /**
+ * Returns this fraction as a vulgar fraction string.
+ *
+ * 5∕3 → <code>"1 2∕3"</code>
+ *
+ * @return {string}
+ */
+ toVulgarString: function () {
+ var vulgar = this.toVulgar();
+ var integer_part = vulgar[0];
+ var fraction_part = vulgar[1];
+
+ return (integer_part ? integer_part : "")
+ + (fraction_part.numerator
+ ? (integer_part ? " " : "") + fraction_part.toString()
+ : (integer_part ? "" : "0"));
+ },
+
+ /**
+ * @see #toNumber()
+ */
+ valueOf: _toNumber
+ });
+
+ return {
+ /**
+ * @memberOf jsx.math.rational
+ */
+ Fraction: _Fraction
+ };
+}());
\ No newline at end of file
/trunk/math/rational.js
Property changes:
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: trunk/math/algebra.js
===================================================================
--- trunk/math/algebra.js (revision 524)
+++ trunk/math/algebra.js (revision 525)
@@ -1,15 +1,14 @@
/**
* <title>PointedEars' JSX: Math Library: Linear Algebra</title>
* @requires object.js
- * @requires types.js
*
* @section Copyright & Disclaimer
- *
+ *
* @author
- * (C) 2000-2011 Thomas Lahn &lt;math.js@PointedEars.de&gt;
+ * (C) 2000-2011, 2013 Thomas Lahn &lt;js@PointedEars.de&gt;
*
* @partof PointedEars' JavaScript Extensions (JSX)
- *
+ *
* JSX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@@ -24,42 +23,446 @@
* along with JSX. If not, see <http://www.gnu.org/licenses/>.
*/
-/** @subsection Matrix Operations */
+(function () {
+ /* Imports */
+ var _isArray = jsx.object.isArray;
+ var _get = jsx.array.get;
+ var _math = jsx.math;
+ var _add = _math.add;
+ var _sub = _math.sub;
+ var _mul = _math.mul;
+ var _pow = _math.pow;
+ var _sqrt = _math.sqrt;
-/**
- * Creates a <code>Matrix</code> object encapsulating an m × n matrix
- * represented by an array of arrays.
- *
- * Different to a "multi-dimensional" array, a <code>Matrix</code>'s
- * elements are indexed (like in math) starting from 1, i. e. the
- * first element of the first row has the coordinates <code>[1, 1]</code>.
- *
- * @param rows : optional Array
- * The array containing the elements of the new matrix or the number
- * of rows of the new matrix.
- * If not provided, the matrix has only one element, <code>0</code>.
- * @param columns: optional Number
- * The number of columns of the matrix, if <var>rows</var> is not an
- * <code>Array</code>
- * @param fill: optional Number
- * The number the matrix should be filled with, if <var>rows</var>
- * is not an <code>Array</code>. The default is <code>0</code>.
- */
-jsx.math.Matrix = (function () {
- var isMethod = jsx.object.isMethod;
+ var _Tensor = (
+ /**
+ * Creates a <code>Tensor</code> object encapsulating
+ * an tensor represented by an array of arrays.
+ *
+ * A tensor is a generalization of scalars, vectors, and
+ * matrices to an arbitrary number of indices. The rank
+ * of a tensor specifies the number of its indices: A scalar
+ * is a tensor of rank 0 (no index), a vector of rank 1,
+ * a matrix of rank 2, aso.
+ *
+ * @constructor
+ * @param {Array} components
+ * @return {jsx.math.Tensor} when called as a factory
+ */
+ function (components) {
+ if (!(this instanceof _Tensor))
+ {
+ return new _Tensor(components);
+ }
- return function (rows, columns, fill) {
- this.data = [0];
+ /**
+ * The components of this tensor
+ * @type Array
+ */
+ this.data = components || [0];
+ }
+ ).extend(null, {
+ /* Initialisers */
- if (rows)
+ /**
+ * Fills this tensor with components.
+ *
+ * @memberOf jsx.math.Tensor.prototype
+ * @param {Array} dimensions (optional)
+ * The array containing the dimensions of the tensor.
+ * If not provided, the tensor is the scalar <code>0</code>.
+ * @param {Number|Function} fill (optional)
+ * The value the tensor should be filled with. If a function,
+ * the return value of the function for each component, whereas
+ * the function is passed the indices of the component as
+ * argument list. The default is <code>0</code>.
+ * @todo
+ */
+ fill: function (dimensions, fill) {
+ return jsx.throwThis(_math.NotImplementedError);
+ },
+
+ /* Information methods */
+
+ /**
+ * Returns a component of this tensor by coordinates,
+ * or a copy of of it as an <code>Array</code>.
+ *
+ * @param {Array} coords (optional)
+ * @return {any|Array}
+ */
+ "get": function (coords) {
+ var data = this.data.map(function (row) {
+ return _isArray(row) ? row.slice() : row;
+ }).slice();
+
+ if (_isArray(coords))
+ {
+ for (var i = 0, len = coords.length; i < len; ++i)
+ {
+ var coord = coords[i];
+
+ data = data[coord];
+
+ if (!data)
+ {
+ break;
+ }
+ }
+ }
+
+ return data;
+ },
+
+ /**
+ * Sets a component of this tensor by coordinates.
+ *
+ * @param {Array} coords
+ * @param {any} value
+ * @return {any}
+ * The new component value
+ */
+ "set": function (coords, value) {
+ var tmp = this.data;
+
+ var i = 0;
+ for (var len = coords.length; i < len - 1; ++i)
+ {
+ var coord = coords[i];
+ if (coord < 0)
+ {
+ jsx.throwThis("jsx.math.CoordinateError");
+ return;
+ }
+
+ if (i < len - 1)
+ {
+ if (!_isArray(tmp[coord]))
+ {
+ tmp[coord] = [];
+ }
+
+ tmp = tmp[coord];
+ }
+ }
+
+ var last_coord = _get(coords, -1);
+ tmp[last_coord] = value;
+
+ return tmp[last_coord];
+ },
+
+ /**
+ * Returns the size of this tensor, i.e. the
+ * maximum of used indexes + 1, per index.
+ *
+ * @return {Array}
+ * @todo
+ */
+ size: function () {
+ return jsx.throwThis(_math.NotImplementedError);
+
+ var data = this.data;
+ var sizes = [data.length];
+ var index = 1;
+
+ while (_isArray(data = data[0]))
+ {
+ sizes[i++] = Math.max.apply(data.map(function (e) {
+ return e.length;
+ }));
+ }
+
+ return sizes;
+ },
+
+ /**
+ * Returns the rank of this tensor, i.e. the
+ * maximum number of used indexes.
+ *
+ * @return {number}
+ */
+ rank: function () {
+ return this.size().length;
+ },
+
+ /* Basic operations */
+
+ /**
+ * Returns the sum of this tensor and compatible one.
+ *
+ * <p>Example:</p><pre>
+ * [[[[1]], …], …] + [[[[1]], …], …] = [[[[2]], …], …]
+ * a_0,0,0,0=1 + b_0,0,0,0=1 = c_0,0,0,0=2</pre>
+ * @param {jsx.math.Tensor} tensor2
+ * @return {jsx.math.Tensor}
+ */
+ add: function (tensor2) {
+ var data = this.get();
+ var data2 = tensor2.get();
+
+ for (var i = data.length; i--;)
+ {
+ var row = data[i];
+ if (typeof row == "number")
+ {
+ data[i] = _add(data[i], data2[i]);
+ }
+ else
+ {
+ for (var j = row.length; j--;)
+ {
+ if (_isArray(row[j]))
+ {
+ row[j] = _Tensor(row[j]).add(_Tensor(data2[i][j])).get();
+ }
+ else
+ {
+ row[j] = _add(row[j], data2[i][j]);
+ }
+ }
+ }
+ }
+
+ return new this.constructor(data);
+ },
+
+ /**
+ * Returns the difference between this tensor and a compatible one.
+ *
+ * @param {jsx.math.Tensor|Number} m2
+ * @return {jsx.math.Tensor}
+ */
+ sub: function (tensor2) {
+ return this.add(_mul(tensor2, -1));
+ }
+ });
+
+ var _Vector = (function () {
+ /**
+ * Returns the result of multiplication of this vector with a value.
+ * <p>
+ * Returns the result of multiplication of this vector
+ * by a scalar, or the cross product of this vector and
+ * another vector.
+ * </p><p>
+ * The cross product is only defined for three-dimensional vectors.
+ * It is a vector that is orthogonal to both the operand vectors,
+ * considering their direction.
+ * </p>
+ * @param {Number|jsx.math.Vector} value
+ * @return {jsx.math.Vector}
+ * <code>this</code> × <code><var>vector2</var></code>
+ * @throws {jsx.InvalidArgumentError}
+ * if the vectors are not compatible
+ */
+ function _cross (value)
{
- if (jsx.types.isArray(rows))
+ var data = this.get();
+
+ if (!(value instanceof _Matrix))
{
- if (isMethod(rows, "slice"))
+ /* Scalar multiplication */
+ for (var i = data.length; i--;)
{
+ for (var j = data[i].length; j--;)
+ {
+ data[i][j] = _mul(data[i][j], value);
+ }
+ }
+
+ return new _Matrix(data);
+ }
+
+ var data2 = value.get();
+
+ var len = data.length;
+ var len2 = data2.length;
+ if (len != 3 || len2 != 3 || len != len2)
+ {
+ return jsx.throwThis(jsx.InvalidArgumentError,
+ [null,
+ this + " and " + value,
+ "two three-dimensional vectors"]);
+ }
+
+ return new Vector([
+ _sub(_mul(data[1], data2[2]), _mul(data[2], data2[1])),
+ _sub(_mul(data[0], data2[2]), _mul(data[2], data2[0])),
+ _sub(_mul(data[0], data2[1]), _mul(data[1], data2[0]))
+ ]);
+ }
+
+ var _Vector = (
+ /**
+ * @constructor
+ */
+ function jsx_math_Vector (components) {
+ if (!(this instanceof _Vector))
+ {
+ return new _Vector(components);
+ }
+
+ this.data = components || [0];
+ }
+ ).extend(_Tensor, {
+ /* Information methods */
+
+ /**
+ * Returns the magnitude (or length) of this vector.
+ *
+ * @memberOf jsx.math.Vector.prototype
+ * @return {number}
+ */
+ mag: function () {
+ var sum = 0;
+
+ var components = this.get();
+ for (var i = components.length; i--;)
+ {
+ sum = _add(sum, _pow(components[i], 2));
+ }
+
+ return _sqrt(sum);
+ },
+
+ /**
+ * Returns the angle between this vector and another vector.
+ *
+ * @param {jsx.math.Vector} vector2
+ * @return {number}
+ * Angle between this vector and <code><var>vector2</var></code>
+ * in radians.
+ */
+ angle: function (vector2) {
+ return Math.acos(this.dot(vector2) / (this.mag() * vector2.mag()));
+ },
+
+ /* Operations */
+
+ cross: _cross,
+ mul: _cross,
+
+ /**
+ * Returns the dot product of this vector and another vector.
+ * <p>
+ * The dot product is defined for two vectors of arbitrary,
+ * but equal dimension. It is a scalar that can be used to
+ * determine the angle between the two vectors.
+ * </p>
+ * @param {jsx.math.Vector} vector2
+ * @return {any} <code><var>this</var></code> · <code><var>vector2</var></code>
+ * @see #angle(jsx.math.Vector)
+ * @throws {jsx.InvalidArgumentErrror}
+ * if the dimensions of the vectors are not equal
+ */
+ dot: function (vector2) {
+ var result = 0;
+ var data = this.get();
+ var data2 = vector2.get();
+
+ for (var i = data.length; i--;)
+ {
+ result = _add(result, _mul(data[i], data2[i]));
+ }
+
+ return result;
+ },
+
+ /**
+ * Returns the Hadamard/Schur/entrywise product of two matrices.
+ *
+ * @param {jsx.math.Vector} vector2
+ * @return {jsx.math.Vector}
+ */
+ mulEntrywise: function (vector2) {
+ var data = this.get();
+ var data2 = vector2.get();
+
+ for (var i = data.length; i--;)
+ {
+ data[i] *= data2[i];
+ }
+
+ return new _Vector(data);
+ }
+ });
+
+ return _Vector;
+ }());
+
+ /** @subsection Matrix algrebra */
+
+ var _Matrix = jsx.object.extend(
+ /**
+ * Creates a <code>Matrix</code> object encapsulating
+ * an m × n matrix and associated operations.
+ *
+ * The matrix components are represented by
+ * an <Code>Array</code> of <code>Array</code>s.
+ *
+ * @constructor
+ * @param {Array|Number|Null|Undefined} rows (optional)
+ * The <code>Array</code> of <code>Arrays</code> containing
+ * the components of the new matrix, or the number of its rows.
+ * The default (used when the argument is a null-value),
+ * or <code>null</code> is <code>1</code>, which creates a
+ * matrix that transforms like a scalar if
+ * <code><var>columns</var> is a null-value,
+ * and like a row vector if <code><var>columns</var> > 1</code>.
+ * @param {Number|Null|Undefined} columns (optional)
+ * The number of columns of the matrix; ignored if <var>rows</var>
+ * is an <code>Array</code>. Otherwise, the default is <code>1</code>,
+ * which creates a matrix that transforms like a scalar if
+ * <code><var>rows</var> is a null-value</code>, and like a
+ * column vector if <code><var>rows</var> > 1</code>.
+ * @param {Number|Function|any} fill (optional)
+ * The value the matrix should be filled with. A <code>Number</code>,
+ * or a <code>Function</code> returning a <code>Number</code>,
+ * is preferred (as being ideal for further computations),
+ * but not required.
+ *
+ * If a <code>Function</code>, the return value of the
+ * <code>Function</code> for each component is used, where
+ * the <code>Function</code> is passed the indices of
+ * the component as arguments, and the <code>this</code>
+ * value is set to the new instance. (For example, specify
+ * <code><var>rows</var> === <var>columns</var></code>
+ * and {@link jsx.math.Matrix.KRONECKER_DELTA}
+ * to create an identity/unit matrix.)
+ * The default is <code>undefined</code>.
+ * @return {jsx.math.Matrix} when called as a factory
+ * @throws {jsx.math.DimensionError}
+ * if the matrix has less than 1 row or a row has less
+ * than 1 column.
+ */
+ function jsx_math_Matrix (rows, columns, fill) {
+ if (!(this instanceof _Matrix))
+ {
+ return _Matrix.construct(arguments);
+ }
+
+ this.data = [];
+
+ if (_isArray(rows))
+ {
+ if (rows.length < 1)
+ {
+ return jsx.throwThis(_math.DimensionError);
+ }
+
+ /* Set Matrix from Array */
+ if (typeof rows.slice == "function")
+ {
for (var i = rows.length; i--;)
{
- this.data[i] = rows[i].slice();
+ var row = rows[i];
+ if (row.length < 1)
+ {
+ return jsx.throwThis(_math.DimensionError);
+ }
+
+ this.data[i] = _isArray(row) ? row.slice() : row;
}
}
else
@@ -67,6 +470,11 @@
for (var i = rows.length; i--;)
{
var row = rows[i];
+ if (row.length < 1)
+ {
+ return jsx.throwThis(_math.DimensionError);
+ }
+
this.data[i] = [];
for (var j = row.length; j--;)
{
@@ -77,209 +485,486 @@
}
else
{
+ /* Build Matrix by dimensions */
var a = [];
- var tmp = [];
- tmp.length = columns;
-
- if (typeof fill == "undefined")
+ /* null or undefined */
+ if (rows == null)
{
- fill = 0;
+ rows = 1;
}
-
- for (var j = 0; j < columns; ++j)
+
+ if (!rows || rows < 1)
{
- tmp[j] = fill;
+ return jsx.throwThis(_math.DimensionError);
}
+ if (columns == null)
+ {
+ columns = 1;
+ }
+
+ if (columns < 1)
+ {
+ return jsx.throwThis(_math.DimensionError);
+ }
+
for (var i = 0; i < rows; ++i)
{
- if (i == 0)
+ var tmp = [];
+ tmp.length = columns;
+
+ for (var j = 0; j < columns; ++j)
{
+ tmp[j] = (typeof fill == "function"
+ ? fill.call(this, i, j)
+ : fill);
+ }
+
+ if (tmp.length > 1)
+ {
a.push(tmp);
}
else
{
- a.push(tmp.slice());
+ a.push(tmp[0]);
}
}
this.data = a;
}
+ },
+ {
+ /**
+ * The Kronecker delta function.
+ *
+ * Takes two arguments, <var>i</var> amd <var>j</var>, and
+ * returns <code>1</code> if they are equal after implicit
+ * type conversion, <code>0</code> otherwise.
+ * Useful for creating identity/unit matrices.
+ *
+ * @param {Number|any} i
+ * @param {Number|any} j
+ * @memberOf jsx.math.Matrix
+ * @return {number}
+ * @see jsx.matrix.Matrix(Number, Number, Function)
+ */
+ KRONECKER_DELTA: function (i, j) { return +(i == j); }
}
- };
-}());
+ ).extend(_Tensor, {
+ /* Information methods */
-/**
- * @param A
- * @return number
- * the row dimension of <code>A</code>;
- * 1 if <code>A</code> is a scalar,
- * greater than 1 if <code>A</code> is a vector or a matrix.
- *
- * <pre>
- * Term X x dimRow(x)
- * --------------------------------------------------------
- * scalar 1 1 1
- *
- * mX1 col vector (1)
- * (2) [1, 2, ..., m] m
- * (.)
- * (m)
- *
- * 1Xn row vector (1 2 ... n) [[1, 2, ..., n]] 1
- *
- * (1 2 ... n) [[1, 2, ..., n],
- * mXn matrix (2 . ... .) [2, ... ], m
- * (. . ... .) [... ],
- * (m . ... .) [m, ... ]]
- * </pre>
- */
-jsx.math.Matrix.dimRow = function(A) {
- return (Array.isArray(A)
- ? A.length
- : 1);
-};
+ /**
+ * Returns the size of this matrix, i.e. the
+ * numbers of rows, and the numbers of columns per row.
+ *
+ * @memberOf jsx.math.Matrix.prototype
+ * @return {Array}
+ */
+ size: function () {
+ var data = this.data;
+ var _size = [data.length, data[0].length];
+ _size.rows = _size[0];
+ _size.columns = _size[1];
-/**
- * @param a
- * @return number
- * The column dimension of <code>A</code>, provided all
- * rows of <code>A</code> have the same length (as the first one);
- * 0 if <code>A</code> is a scalar,
- * greater than 0 if <code>A</code> is a vector or a matrix.
- *
- * <pre>
- * Term X x dimCol(x)
- * --------------------------------------------------------
- * scalar 1 1 0
- *
- * mX1 col vector (1)
- * (2) [1, 2, ..., m] 1
- * (.)
- * (m)
- *
- * 1Xn row vector (1 2 ... n) [[1, 2, ..., n]] n
- *
- * (1 2 ... n) [[1, 1, ..., n],
- * mXn matrix (2 . ... .) [2, ... ], n
- * (. . ... .) [... ],
- * (m . ... .) [m, ... ]]
- * </pre>
- */
-jsx.math.Matrix.dimCol = function(a) {
- return (
- typeof (a = a[0]) != "undefined"
- ? (Array.isArray(a[0]) ? a[0].length : 1)
- : 0);
-};
+ return _size;
+ },
-/**
- * @param a
- * @return the square root of the product of A's row dimension
- * and its column dimension. The return value indicates
- * whether a matrix A is square or not; for square matrices,
- * the return value is an integer.
- * @see jsx.math#add()
- */
-jsx.math.Matrix.dim = function(a) {
- return Math.sqrt(jsx.math.Matrix.dimRow(a) * jsx.math.Matrix.dimCol(a));
-};
+ /* Basic operations */
-jsx.math.Matrix.prototype = {
- constructor: Math.Matrix,
-
- putValue: function (coords, value) {
- var tmp = this.data;
-
- for (var i = 0, len = coords.length; i < len - 1; ++i)
- {
- var arg = coords[i] - 1;
- if (arg < 0)
+ /**
+ * Returns the result of multiplication of this matrix with a value.
+ * <p>
+ * Returns the result of multiplication of this matrix
+ * by a scalar, or of linear algebraic matrix multiplication
+ * with another, compatible matrix.
+ * </p>
+ * @param {Number|jsx.math.Matrix} value
+ * @return {jsx.math.Matrix} <code>this</code> × <code><var>value</var></code>
+ * @throws {jsx.InvalidArgumentError}
+ * if the matrices are not compatible (the row dimension
+ * of this matrix must equal the column dimension of
+ * the other one).
+ */
+ mul: function (value) {
+ var data = this.get();
+
+ if (!(value instanceof _Matrix))
{
- jsx.throwThis("jsx.math.CoordinateError");
- return;
+ /* Scalar multiplication */
+ for (var i = data.length; i--;)
+ {
+ for (var j = data[i].length; j--;)
+ {
+ data[i][j] = _mul(data[i][j], value);
+ }
+ }
+
+ return new _Matrix(data);
}
-
- if (typeof tmp[arg] == "undefined")
+
+ var data2 = value.get();
+ var m = new _Matrix();
+ var num_rows = data.length;
+ var num_rows2 = data2.length;
+
+ for (var k = 0, num_cols2 = data2[0].length; k < num_cols2; ++k)
{
- tmp[arg] = [];
+ for (var i = 0; i < num_rows; ++i)
+ {
+ var this_row = data[i];
+ var sum = 0;
+
+ for (var j = 0, num_cols = this_row.length; j < num_cols; ++j)
+ {
+ if (j > num_rows2 - 1)
+ {
+ return jsx.throwThis(jsx.InvalidArgumentError,
+ ["Incompatible matrices",
+ "m1.size() === [m, n]; m2.size() === [n, x]",
+ this.size() + ", " + value.size()]);
+ }
+
+ sum = _add(sum, _mul(data[i][j], data2[j][k]));
+ }
+
+ m.set([i, k], sum);
+ }
}
- tmp = tmp[arg];
- }
-
- var lastCoord = coords.slice(coords.length - 1);
- if (lastCoord < 1)
- {
- jsx.throwThis("jsx.math.CoordinateError");
- return;
- }
-
- tmp[lastCoord - 1] = value;
+ return m;
+ },
- return tmp[lastCoord - 1];
- },
+ /**
+ * Returns the Hadamard/Schur/entrywise product of two matrices.
+ *
+ * @param {jsx.math.Matrix} m2
+ * @return {jsx.math.Matrix}
+ */
+ mulEntrywise: function (matrix2) {
+ var data = this.get();
+ var data2 = matrix2.get();
- getValue: function (coords) {
- var tmp = this.data;
+ for (var i = data.length; i--;)
+ {
+ for (var j = data[i].length; j--;)
+ {
+ data[i][j] = _mul(data[i][j], data2[i][j]);
+ }
+ }
- for (var i = 0, len = coords.length; i < len; ++i)
- {
- var arg = coords[i] - 1;
- tmp = tmp[arg];
+ return new _Matrix(data);
+ },
- if (typeof tmp == "undefined")
+ /**
+ * Returns the Kronecker product of two matrices.
+ *
+ * @param {Matrix} matrix2
+ * @return {jsx.math.Matrix}
+ * @todo
+ */
+ mulKronecker: function (matrix2) {
+ var rows = this.get();
+ var rows2 = matrix2.get();
+ var size = this.size();
+ var size2 = matrix2.size();
+ var new_matrix = new _Matrix(size.rows * size2.rows, size.columns * size2.columns);
+ var new_data = new_matrix.get();
+ var new_size = new_matrix.size();
+
+// return jsx.throwThis(jsx.math.NotImplementedError);
+
+ var new_row = new_size.rows - 1;
+
+ for (var i = rows.length; i--;)
{
- break;
+ var row = rows[i];
+ var len2 = row.length;
+
+ for (var m = rows2.length; m--;)
+ {
+ var new_column = new_size.columns - 1;
+ var m2_row = rows2[m];
+ var len4 = m2_row.length;
+
+ for (var j = len2; j--;)
+ {
+ for (var n = len4; n--;)
+ {
+ new_data[new_row][new_column--] = _mul(row[j], m2_row[n]);
+ }
+ }
+
+ --new_row;
+ }
}
- }
- return tmp;
- },
+ return new _Matrix(new_data);
+ },
- inc: function (coords) {
- var
- v = +this.getValue.apply(this, coords);
+ /**
+ * Increases a component of this matrix by 1
+ */
+ inc: function (coords) {
+ var v = +this.get.apply(this, coords);
- return this.putValue.apply(
- this, coords.concat((isNaN(v) ? 0 : +v) + 1));
- },
-
- toString:
+ return this.set.apply(this, coords.concat((isNaN(v) ? 0 : v) + 1));
+ },
+
/**
- * Returns the matrix converted to string, i.e.
- * elements of arrays arranged in rows and columns.
+ * Divides each component of this matrix by a value,
+ * and returns the resulting matrix.
+ *
+ * @param {Number} value
+ * @return {jsx.math.Matrix}
+ */
+ div: function (value) {
+ if (value instanceof _Matrix)
+ {
+ return jsx.throwThis(jsx.InvalidArgumentError, [null, "Number", value]);
+ }
+
+ return this.mul(1 / value);
+ },
+
+ /**
+ * Applies a mapping callback to each component of this matrix
+ * and returns the result.
+ *
+ * @param {Function} callback
+ * Called for each component, with the component, its
+ * coordinates as an <code>Array</code>, and this
+ * <code>Matrix</code> as argument list. Its return value
+ * is used as the returned new component value.
+ * @param {Object} thisValue (optional)
+ * The callbacks <code>this</code> value. The default
+ * is this <code>Matrix</code>.
+ * @return {jsx.math.Matrix}
+ */
+ map: function (callback, thisValue) {
+ return new _Matrix(this.get().map(function (row, rowIndex, matrix) {
+ return row.map(function (component, columnIndex) {
+ return callback.call(thisValue, component, [rowIndex, columnIndex], matrix);
+ });
+ }));
+ },
+
+ /**
+ * Computes the square root of each component of this matrix
+ * and returns the result.
+ *
+ * @return {jsx.math.Matrix}
+ */
+ sqrt: function () {
+ return this.map(function (component) {
+ return _sqrt(component);
+ });
+ },
+
+ /**
+ * Returns the transpose of this matrix
+ *
+ * @return {jsx.math.Matrix}
+ */
+ transpose: function () {
+ var size = this.size();
+ var transposed = new _Matrix(size.columns, size.rows).get();
+
+ var data = this.get();
+ for (var i = data.length; i--;)
+ {
+ var row = data[i];
+
+ for (var j = row.length; j--;)
+ {
+ transposed[j][i] = row[j];
+ }
+ }
+
+ return new _Matrix(transposed);
+ },
+
+ /* Row operations */
+
+ /**
+ * Switches two rows of a matrix and returns the result.
+ *
+ * @param {Number} row1
+ * @param {Number} row2
+ * @return {jsx.math.Matrix}
+ */
+ switchRows: function (row1, row2) {
+ var rows = this.get();
+
+ var tmp = rows[row1];
+ rows[row1] = rows[row2];
+ rows[row2] = tmp;
+
+ return new _Matrix(rows);
+ },
+
+ /**
+ * Multiplies each element in a row by a non-zero constant.
+ *
+ * @param {Number} rowIndex
+ * @param {Number} factor
+ * @return {jsx.math.Matrix}
+ */
+ mulRow: function (rowIndex, factor) {
+ if (factor == 0)
+ {
+ return jsx.throwThis(jsx.InvalidArgumentError,
+ ["Factor must not be 0"]);
+ }
+
+ var rows = this.get();
+ var row = rows[rowIndex];
+
+ if (!row)
+ {
+ return jsx.throwThis(jsx.InvalidArgumentError,
+ ["No such row index", rowIndex]);
+ }
+
+ for (var j = row.length; j--;)
+ {
+ row[j] = _mul(row[j], factor);
+ }
+
+ return new _Matrix(rows);
+ },
+
+ /* Methods for square matrices */
+
+ /* Information methods */
+
+ /**
+ * Returns the trace of this matrix.
+ *
+ * The trace of a matrix is the sum of its main diagonal
+ * components. It is therefore only defined for square
+ * matrices.
+ *
+ * @return {number}
+ * @throws {TypeError}
+ * if the matrix has no or broken rows, or is not square
+ */
+ trace: function () {
+ var result;
+ var data = this.data;
+
+ for (var i = 0, len = data.length; i < len; ++i)
+ {
+ var row = data[i];
+ if (!row)
+ {
+ return jsx.throwThis("TypeError", "No or broken rows");
+ }
+
+ var component = row[i];
+ if (!component)
+ {
+ return jsx.throwThis("TypeError", "Not a square matrix");
+ }
+
+ if (typeof result == "undefined")
+ {
+ result = component;
+ }
+ else
+ {
+ result = _add(result, component);
+ }
+ }
+
+ return result;
+ },
+
+ /**
+ * Returns the determinant of this matrix.
+ *
+ * @return {Number}
+ * <code>NaN</code> if one or more components could not
+ * be converted to <code>Number</code>, or more than one
+ * component was not finite. <code>Infinity</code> or
+ * <code>-Infinity</code> if one component was not finite.
+ * @throws {TypeError} if the Matrix is not square
+ */
+ det: function () {
+ var result = 0;
+ var data = this.data;
+ var num_rows = data.length;
+ var first_row = data[0];
+ var num_cols = first_row.length;
+
+ if (num_rows != num_cols)
+ {
+ return jsx.throwThis("TypeError", "Not a square matrix");
+ }
+
+ if (num_cols == 2)
+ {
+ return data[0][0] * data[1][1] - data[0][1] * data[1][0];
+ }
+
+ for (var col = 0; col < num_cols; ++col)
+ {
+ var product1 = data[0][col];
+ var product2 = product1;
+ var offset = 0;
+
+ for (var row = 1; row < num_cols; ++row)
+ {
+ ++offset;
+ var this_row = data[row];
+ product1 = _mul(product1, this_row[(col + offset) % num_cols]);
+ product2 = _mul(product2, _get(this_row, col - offset));
+ }
+
+ result = _add(result, _sub(product1, product2));
+ }
+
+ return result;
+ },
+
+ /**
+ * Returns the human-readable string representation of this
+ * matrix, i.e. elements of arrays arranged in rows and columns.
* Makes use of string.js#format() if available.
- *
- * @param m : optional Matrix
- * @return string
+ *
+ * @param {String} prefix (optional)
+ * Prefix for the second, third, aso. row. <code>" "</code>
+ * is useful in consoles where the output is prefixed by
+ * <kbd>"</kbd>. The default is the empty string.
+ * @return {string}
* @todo
*/
- function(m) {
- if (!m)
+ toString: function (prefix) {
+ var m;
+ if ((m = this.get()))
{
- m = this;
- }
-
- if ((m = m.data))
- {
var
as = [],
- bHasFormat = (typeof format != "undefined"),
- maxLen;
-
- if (bHasFormat)
+ /* FIXME */
+ _sprintf = jsx.object.getFeature(jsx, "string", "sprintf"),
+ max_len;
+
+ if (_sprintf)
{
- maxLen = Math.max(m);
+ /* TODO: Calculate optimum width per column */
+ max_len = Math.max.apply(Math, m.map(function (row) {
+ return Math.max.apply(Math, row.map(function (component) {
+ return component.toString().length;
+ }));
+ }));
}
-
+
for (var i = 0, len = m.length; i < len; i++)
{
var row = m[i];
- if (bHasFormat)
+ if (_sprintf)
{
- as[i] = format("%*$s", row, maxLen + 1);
+ as[i] = _sprintf("%*a", row, max_len + 1);
}
else
{
@@ -286,241 +971,133 @@
as[i] = row.join(" ");
}
}
- }n
-
- return as.join("\n");
+ }
+
+ return as.join("\n" + (prefix || ""));
},
- minor:
/**
- * Returns the minor of the matrix, i.e. the matrix produced
- * by removing the original's first row and i-th column.
- *
- * @param i : number
- * @param m : optional Matrix
- * @return string
- * @todo
+ * Returns the minor of this matrix.
+ *
+ * @param {Number} column
+ * @return {jsx.math.Matrix}
+ * The matrix produced by removing this matrix's first row
+ * and <code><var>column</var></code>-th column (counting
+ * from 0).
*/
- function (i, m) {
- if (!m)
+ minor: function (column) {
+ var data = this.get().slice(1);
+
+ for (var j = data.length; j--;)
{
- m = this;
+ data[j].splice(column, 1);
}
-
- if ((m = m.data))
- {
- m = new Math.Matrix(m);
- m.data = m.data.slice(1);
- var j;
- for (m, j = (m = m.data).length; j--;)
- {
- m[j].splice(i, 1);
- }
- }
-
- return m;
+
+ return new _Matrix(data);
}
-};
+ });
-/**
- * @param a
- * @param b
- * @return Array
- * The sum of the matrixes <var>a</var> and <var>b</var>
- */
-jsx.math.add = function(a, b) {
- /*
- * x00 x01 x02 y00 y01 y02 x00+y00 x01+y01 x02+y02
- * x10 x11 x12 + y10 y11 y12 = x10+y10 x11+y11 x12+y12
- * x20 x21 x22 y20 y21 y22 x20+y20 x21+y21 x22+y22
+ jsx.object.extend(jsx.math, {
+ Tensor: _Tensor,
+ Vector: _Vector,
+ Matrix: _Matrix
+ });
+
+ /**
+ * Computes the intersection of two orthotopes (intervals, rectangles,
+ * rectangular cuboids, etc.)
+ * <pre>
+ * ,------------------.
+ * | ,----+------.
+ * | |/ / | |
+ * | | / /| |
+ * | `----+------'
+ * `------------------'
+ * </pre>
+ * <p>
+ * Each orthotope is given as a list of Arrays of numbers (which may
+ * be encapsulated in a Vector), where each Array or Vector consists
+ * of the coordinates of the adjacent vertices of the orthotope
+ * (for a rectangle, the x and y coordinates of the left top and
+ * right bottom corners). FIXME: Not reliable in 3D+!
+ * </p><p>
+ * If you need to compute the intersection of more than two
+ * orthotopes, you can compute the intersection of their
+ * intersections.
+ * </p>
+ * @param orthotope1 : Array[Array[double]|Math.Vector]
+ * First orthotope
+ * @param orthotope2 : Array[Array[double]|Math.Vector]
+ * Second orthotope
+ * @return Array[Array|Vector]
+ * An Array of two Arrays or Vectors of, each of which holds one
+ * vector pointing to an adjacent vertex of the resulting orthotope
+ * that includes all points that the input orthotopes have in common.
*/
- var result = new Array();
+ _math.intersect = function (orthotope1, orthotope2) {
+ var result = [[], []];
- var dimARow,
- dimACol = jsx.math.dimCol(a),
- dimBRow,
- dimBCol = Math.dimCol(b);
- if ((dimARow = jsx.math.dimRow(a)) == (dimBRow = Math.dimRow(b))
- && (dimACol == dimBCol))
- {
- for (var i = 0; i < dimARow; i++)
+ var ortho1LeftTop = orthotope1[0];
+ for (var i = ortho1LeftTop.length; i--;)
{
- result[i] = [];
- for (var j = 0; j < dimACol; j++)
- {
- result[i][j] = a[i][j] + b[i][j];
- }
+ result[0][i] = (ortho1LeftTop[i] < orthotope2[0][i])
+ ? orthotope2[0][i]
+ : ortho1LeftTop[i];
}
- }
- else
- {
- throwException(new Math.InvalidOperandError(
- "First matrix's dimension (" + dimARow + "," + dimACol
- + ") != second matrix's dimension (" + dimBRow + ", " + dimBCol + ")"));
- return null;
- }
-
- return result;
-};
-/**
- * This routine uses the dimensions of <var>a</var> and <var>b</var>
- * to choose the corresponding multiplication routine. The argument
- * dimensions, the dimension of the corresponding result, and the
- * multiplication routine that is called are shown in the following
- * table.
- <pre>
- B
+ var ortho1RightBottom = orthotope1[1];
+ for (i = ortho1RightBottom.length; i--;)
+ {
+ result[1][i] = (ortho1RightBottom[i] > orthotope2[1][i])
+ ? orthotope2[1][i]
+ : ortho1RightBottom[i];
+ }
- A qXn 1Xn qX1
- Matrix row Vector col Vector scalar
+ return result;
+ };
- mXq mXn Matrix ERROR mX1 col Vector mXq Matrix
- Matrix MatrixMatrixMultiply MatrixVectorMultiply MatrixScalarMultiply
+ /**
+ * @constructor
+ * @extends jsx.InvalidArgumentError
+ */
+ _math.DimensionError = function () {
+ arguments.callee._super.call(this, "Dimension must be 1 or greater");
+ };
- 1Xq 1Xn row Vector ERROR scalar 1Xq Vector
- row Vector VectorMatrixMultiply VectorScalarMultiply
+ _math.DimensionError.extend(jsx.InvalidArgumentError, {
+ /**
+ * @memberOf jsx.math.DimensionError.prototype
+ */
+ name: "jsx.math.DimensionError"
+ });
- mX1 ERROR mXn Matrix (outer product) ERROR mX1 Vector
- col Vector OuterProductMatrix VectorScalarMultiply
+ /**
+ * @constructor
+ * @extends jsx.InvalidArgumentError
+ */
+ _math.CoordinateError = function () {
+ arguments.callee._super.call(this, "Coordinate must be 0 or greater");
+ };
- qXn Matrix 1Xn row Vector qX1 col Vector scalar
- scalar MatrixScalarMultiply VectorScalarMultiply VectorScalarMultiply standard multipliction
- </pre>
+ _math.CoordinateError.extend(jsx.InvalidArgumentError, {
+ /**
+ * @memberOf jsx.math.CoordinateError.prototype
+ */
+ name: "jsx.math.CoordinateError"
+ });
- * @param a
- * @param b
- * @return number|Array
- * @throws Math#InvalidOperandError
- */
-jsx.math.multiply = function(a, b) {
- /*
- * a00 a01 ... b00 b01 ...
- * a10 a11 ... * b10 b11 ...
- * ... ... ... ... ... ...
- *
- * a00*b00+a01*b10+...*... a00*b01+a01*b11+...*... a00*...+a01*...+...*...
- * = a10*b10+a11*b10+...*... a10*b01+a11*b11+...*... a00*...+a01*...+...*...
- * ...*...+...*...+...+... ...*b01+...*b11+...*... a00*...+a01*...+...*...
+ /**
+ * @constructor
+ * @extends jsx.Error
*/
-
- var dimRowA = Math.dimRow(a);
- var dimColA = Math.dimCol(a);
- var dimRowB = Math.dimRow(b);
- var dimColB = Math.dimCol(b);
- if ((dimRowA && dimColA) || (dimRowB && dimColB))
- {
- if (dimRowA || dimRowB)
- {
-// if (dimRowX && d
- var result = matrixMatrixMultiply(a, b);
- }
- else if (Array.isArray(a) && !Array.isArray(b))
- {
- if (Array.isArray(a[0]))
- {
- // ...
- }
- result = matrix;
- }
-
- result = new Array();
- // matrixMultiply
- }
- else
- {
- result = a * b;
- }
-
- var x_len = a.length;
- var y_len = b.length;
- for (var i = 0, j, xi_len, sum = 0, k;
- i < x_len;
- i++)
- {
- result[i] = new Array();
- xi_len = a[i].length;
- for (j = 0;
- j < xi_len;
- j++, sum = 0)
- {
- if (y_len != xi_len)
- {
- jsx.throwThis(new jsx.math.InvalidOperandError(
- "First matrix's column dimension (" + xi_len
- + ") != second matrix's row dimension (" + y_len + ")"));
- return null;
- }
- sum += a[i][k] + b[k][i];
- }
- result[i][j] = sum;
- }
-
- if (result.length == 1 && result[i].length == 1)
- {
- result = result[0][0];
- }
-
- return result;
-};
+ _math.NotImplementedError = function () {
+ arguments.callee._super.call(this, "Not implemented");
+ };
-/**
- * Computes the intersection of two orthotopes (intervals, rectangles,
- * rectangular cuboids, etc.)
- * <pre>
- * ,------------------.
- * | ,----+------.
- * | |/ / | |
- * | | / /| |
- * | `----+------'
- * `------------------'
- * </pre>
- * <p>
- * Each orthotope is given as a list of Arrays of numbers (which may
- * be encapsulated in a Vector), where each Array or Vector consists
- * of the coordinates of the adjacent vertices of the orthotope
- * (for a rectangle, the x and y coordinates of the left top and
- * right bottom corners). FIXME: Not reliable in 3D+!
- * </p><p>
- * If you need to compute the intersection of more than two
- * orthotopes, you can compute the intersection of their
- * intersections.
- * </p>
- * @param orthotope1 : Array[Array[double]|Math.Vector]
- * First orthotope
- * @param orthotope2 : Array[Array[double]|Math.Vector]
- * Second orthotope
- * @return Array[Array|Vector]
- * An Array of two Arrays or Vectors of, each of which holds one
- * vector pointing to an adjacent vertex of the resulting orthotope
- * that includes all points that the input orthotopes have in common.
- */
-jsx.math.intersect = function (orthotope1, orthotope2) {
- var result = [[], []];
-
- var ortho1LeftTop = orthotope1[0];
- for (var i = ortho1LeftTop.length; i--;)
- {
- result[0][i] = (ortho1LeftTop[i] < orthotope2[0][i])
- ? orthotope2[0][i]
- : ortho1LeftTop[i];
- }
-
- var ortho1RightBottom = orthotope1[1];
- for (i = ortho1RightBottom.length; i--;)
- {
- result[1][i] = (ortho1RightBottom[i] > orthotope2[1][i])
- ? orthotope2[1][i]
- : ortho1RightBottom[i];
- }
-
- return result;
-};
-
-jsx.math.CoordinateError = function () {
- arguments.callee._super.call(this, "Coordinate must be 1 or greater")
-};
-
-jsx.math.CoordinateError.extend(jsx.InvalidArgumentError, {
- name: "jsx.math.CoordinateError"
-});
\ No newline at end of file
+ _math.NotImplementedError.extend(jsx.Error, {
+ /**
+ * @memberOf jsx.math.NotImplementedError.prototype
+ */
+ name: "jsx.math.NotImplementedError"
+ });
+}());
\ No newline at end of file
/trunk/math/integer.js
4,12 → 4,12
* @requires types.js
*
* @section Copyright & Disclaimer
*
*
* @author
* (C) 2000-2011 Thomas Lahn &lt;math.js@PointedEars.de&gt;
*
* @partof PointedEars' JavaScript Extensions (JSX)
*
*
* JSX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
24,43 → 24,66
* along with JSX. If not, see <http://www.gnu.org/licenses/>.
*/
 
/**
* Returns the greatest common divisor (GCD) of two integers
* <code>a</code> and <code>b</code>, implementing (the optimized form of) the
* Euclidean algorithm (also called Euclid's algorithm). The
* GCD of two integer arguments is the largest positive integer
* that both arguments are integer multiples of, i.e. by which
* either argument can be divided without remainder. Since
* integers are required, the floor of <code>a</code> and <code>b</code> will
* be used for computation.
*
* @param a : number
* @param b : number
* @return type number
* The GCD of <code>a</code> and <code>b</code>;
* <code>NaN</code> if an argument is not a number.
* @see Math#floor(number)
*/
Math.gcd = function(a, b) {
if (isNaN(a) || isNaN(b))
{
return Number.NaN;
}
if (typeof jsx == "undefined")
{
var jsx = {};
}
 
a = Math.floor(a);
b = Math.floor(b);
var c;
if (typeof jsx.math == "undefined")
{
jsx.math = {};
}
 
while (b != 0)
{
c = a % b;
a = b;
b = c;
jsx.math.integer = {
/**
* Returns the greatest common divisor (GCD) of two integers
* <code>a</code> and <code>b</code>, implementing (the optimized form of) the
* Euclidean algorithm (also called Euclid's algorithm). The
* GCD of two integer arguments is the largest positive integer
* that both arguments are integer multiples of, i.e. by which
* either argument can be divided without remainder. Since
* integers are required, the floor of <code>a</code> and <code>b</code> will
* be used for computation.
*
* @memberOf jsx.math.integer
* @param a : number
* @param b : number
* @return type number
* The GCD of <code>a</code> and <code>b</code>;
* <code>NaN</code> if an argument is not a number.
* @see Math#floor(number)
*/
gcd: function (a, b) {
if (isNaN(a) || isNaN(b))
{
return Number.NaN;
}
 
a = Math.floor(a);
b = Math.floor(b);
var c;
 
while (b != 0)
{
c = a % b;
a = b;
b = c;
}
 
return Math.abs(a);
}
 
return Math.abs(a);
};
 
if (jsx.options.augmentBuiltins)
{
jsx.object.extend(Math, {
/**
* @memberOf Math
*/
gcd: jsx.math.integer.gcd
});
}
 
/**
* Returns the greatest common divisor (GCD) of two or more
* integers, implementing (the optimized form of) the Euclidean
104,7 → 127,7
{
return Number.NaN;
}
 
if (!a || !b)
{
return 0;
112,7 → 135,7
 
a = Math.floor(a);
b = Math.floor(b);
 
return ((a * b) / Math.gcd(a, b));
};
 
167,7 → 190,7
* Unlike common recursive implementations, the algorithm is
* implemented iterative here, saving stack space and thus
* allowing larger factorials to be computed.
*
*
* @throws Math#OverflowError
*/
Math.fac = function(n) {
188,7 → 211,7
break;
}
}
 
return result;
};
 
225,7 → 248,7
* roots of certain negative values, like root(-9,
* 1/3) cannot be computed (results in NaN there)
* but should be.
*
*
* @author
* (c) 2000-2004 Thomas Lahn &lt;math.js@PointedEars.de&gt;
* @param nBase : number
267,7 → 290,7
"power(" + nBase + ", " + nExponent + ")"));
}
}
 
return result;
};
 
319,3 → 342,54
Math.rec = function(x) {
return (1 / x);
};
 
/**
* Finds prime numbers within a range
*
* @param {int} upperBounds
* The upper bounds of the half-open interval [2, ceil(upperBounds)),
* that is, the smallest integer that should not be considered
* in the search.
* @return {Object}
* An object whose property names are the primes within range.
* Use {@link Object#keys()} to get an {@link Array} of
* <code><em>string</em></code> values; use
* {@link Array.prototype#map} to get an <code>Array</code>
* of {@link Number} values.
* NOTE: As of ECMAScript Edition 5.1, an <code>Array</code>
* is limited to 2^32-1 elements. Use {@link jsx.array.BigArray}
* to process this <code>Object</code> efficiently.
*/
Math.primes = function (upperBounds) {
var not_prime = Object.create(null);
var prime = Object.create(null);
var i = 2;
var upperLimit = Math.sqrt(upperLimit);
 
while (i < upperLimit)
{
prime[i] = true;
 
for (var mult = i * i; mult < upperBounds; mult += i)
{
not_prime[mult] = true;
}
 
while (not_prime[++i])
{
;
}
}
 
for (; i < upperBounds; ++i)
{
if (!not_prime[i])
{
prime[i] = true;
}
 
delete not_prime[i];
}
 
return prime;
};
/trunk/math.js
6,7 → 6,7
* @section Copyright & Disclaimer
*
* @author
* (C) 2000-2011, 2013 Thomas Lahn &lt;math.js@PointedEars.de&gt;
* (C) 2000-2011, 2013, 2014 Thomas Lahn &lt;math.js@PointedEars.de&gt;
*
* @partof PointedEars' JavaScript Extensions (JSX)
*
31,110 → 31,223
* Refer math.htm file for general documentation.
*/
 
if (typeof jsx == "undefined")
{
/**
* @namespace
*/
var jsx = {};
}
 
/**
* @namespace
*/
jsx.math = {
version: "1.16.$Rev$",
copyright: "Copyright \xA9 1999-2011, 2013",
author: "Thomas Lahn",
email: "math.js@PointedEars.de",
path: "http://pointedears.de/scripts/"
};
// jsx.math.docURL = jsx.math.path + "math.htm";
jsx.math = (/** @constructor */ function () {
/* Imports */
var _isNativeMethod = jsx.object.isNativeMethod;
 
/* User interface language */
jsx.math.language = "en";
/* Private variables */
 
/** @section Exceptions */
/**
* @function
*/
var _MathError = (
/**
* @constructor
* @param {string} sError
* @param {string} sMessage
*/
function (sError, sMessage) {
this.constructor._super.call(this,
"math.js Error: "
+ (typeof sError[jsx.math.language] != "undefined"
? sError[jsx.math.language]
: sError["en"])
+ " " + (sMessage || ""));
}
).extend(jsx.Error);
 
jsx.math.msgInvArg = {
'en': 'Invalid function argument',
'de': 'Ungültiges Funktionsargument'
};
var _msgInvArg = {
'en': 'Invalid function argument',
'de': 'Ungültiges Funktionsargument'
};
 
jsx.math.msgArgMissing = {
'en': 'Required argument missing',
'de': 'Erforderliches Argument fehlt'
};
var _msgArgMissing = {
'en': 'Required argument missing',
'de': 'Erforderliches Argument fehlt'
};
 
jsx.math.msgInvOp = {
'en': 'Invalid operand',
'de': 'Ungültiger Operand'
};
var _msgInvOp = {
'en': 'Invalid operand',
'de': 'Ungültiger Operand'
};
 
jsx.math.msgOverflow = {
'en': 'Overflow',
'de': 'Überlauf'
};
var _msgOverflow = {
'en': 'Overflow',
'de': 'Überlauf'
};
 
jsx.math.msgUnderflow = {
'en': 'Underflow',
'de': 'Unterlauf'
};
var _msgUnderflow = {
'en': 'Underflow',
'de': 'Unterlauf'
};
 
jsx.math.msgDivByZero = {
'en': 'Division by zero',
'de': 'Division durch Null'
};
var _msgDivByZero = {
'en': 'Division by zero',
'de': 'Division durch Null'
};
 
/**
* @param sError
* @param sMessage
*/
jsx.math.MathError = function(sError, sMessage) {
this.constructor._super.call(this,
"math.js Error: "
+ (typeof sError[jsx.math.language] != "undefined"
? sError[jsx.math.language]
: sError["en"])
+ " " + (sMessage || ""));
};
jsx.math.MathError.extend(jsx.Error);
return {
/**
* @memberOf jsx.math
*/
version: "1.16.$Rev$",
copyright: "Copyright \xA9 1999-2011, 2013",
author: "Thomas Lahn",
email: "math.js@PointedEars.de",
path: "http://pointedears.de/scripts/",
 
/**
* @param sMethodCall
* @param iErrorCode
* @todo
*/
jsx.math.InvalidArgumentError = function(sMethodCall, iErrorCode) {
var sSubErrType = jsx.math.msgInvArg;
/** User interface language */
language: "en",
 
switch (iErrorCode)
{
case -1:
sSubErrType = jsx.math.msgArgMissing;
break;
}
/** @section Exceptions */
 
jsx.math.MathError.call(this, sSubErrType);
};
msgInvArg: _msgInvArg,
msgArgMissing: _msgArgMissing,
msgInvOp: _msgInvOp,
msgOverflow: _msgOverflow,
msgUnderflow: _msgUnderflow,
msgDivByZero: _msgDivByZero,
 
jsx.math.InvalidOperandError = function() {
jsx.math.MathError.call(this, jsx.math.msgInvOp);
};
MathError: _MathError,
 
jsx.math.OverflowError = function() {
jsx.math.MathError.call(jsx.math.msgOverflow);
};
/**
* @param {string} sMethodCall
* @param {int} iErrorCode
* @todo
*/
InvalidArgumentError: (
function (sMethodCall, iErrorCode) {
var sSubErrType = _msgInvArg;
 
jsx.math.UnderflowError = function() {
jsx.math.MathError.call(jsx.math.msgUnderflow);
};
switch (iErrorCode)
{
case -1:
sSubErrType = _msgArgMissing;
break;
}
 
jsx.math.DivisionByZeroError = function() {
jsx.math.MathError.call(jsx.math.msgDivByZero);
};
_MathError.call(this, sSubErrType);
}
).extend(_MathError),
 
InvalidOperandError: function() {
_MathError.call(this, _msgInvOp);
},
 
OverflowError: (function() {
_MathError.call(_msgOverflow);
}).extend(_MathError),
 
UnderflowError: (function() {
_MathError.call(_msgUnderflow);
}).extend(_MathError),
 
DivisionByZeroError: (function() {
_MathError.call(_msgDivByZero);
}).extend(_MathError),
 
/**
* General addition
*
* @param op1
* @param op2
* @return {any}
*/
add: function (op1, op2) {
if (_isNativeMethod(op1, "add"))
{
return op1.add(op2);
}
 
return op1 + op2;
},
 
/**
* General subtraction
*
* @param op1
* @param op2
* @return {any}
*/
sub: function (op1, op2) {
if (_isNativeMethod(op1, "sub"))
{
return op1.sub(op2);
}
 
return op1 - op2;
},
 
/**
* General multiplication
*
* @param op1
* @param op2
* @return {any}
*/
mul: function (op1, op2) {
if (_isNativeMethod(op1, "mul"))
{
return op1.mul(op2);
}
 
return op1 * op2;
},
 
/**
* General division
*
* @param op1
* @param op2
* @return {any}
*/
div: function (op1, op2) {
if (_isNativeMethod(op1, "div"))
{
return op1.div(op2);
}
 
return op1 / op2;
},
 
/**
* General exponentiation
*
* @param op1
* @param op2
* @return {any}
*/
pow: function (op1, op2) {
if (_isNativeMethod(op1, "pow"))
{
return op1.pow(op2);
}
 
return Math.pow(op1, op2);
},
 
/**
* General square root
*
* @param op
* @return {any}
*/
sqrt: function (op) {
if (_isNativeMethod(op, "sqrt"))
{
return op.sqrt();
}
 
return Math.sqrt(op);
}
};
}());
 
// jsx.math.docURL = jsx.math.path + "math.htm";
 
/*
* TODO:
 
/trunk/test/math-test.js
0,0 → 1,320
function runTests ()
{
var assert = jsx.test.assert;
var assertObjectEquals = jsx.test.assertObjectEquals;
var assertArrayEquals = jsx.test.assertArrayEquals;
 
jsx.test.runner.run({
tests: [
{
file: "math/float.js",
feature: "jsx.math.getValue(falseValue)",
description: "return <code>NaN</code>",
code: function () {
assert(isNaN(jsx.math.getValue()));
assert(isNaN(jsx.math.getValue(false)));
assert(isNaN(jsx.math.getValue(0)));
assert(isNaN(jsx.math.getValue(null)));
assert(isNaN(jsx.math.getValue('')));
}
},
{
file: "math/float.js",
feature: "jsx.math.getValue(obj)",
description: "<code>obj.valueOf()</code> does not exist, return <code>NaN</code>",
code: function () {
assert(isNaN(jsx.math.getValue(jsx.object.getDataObject())));
assert(isNaN(jsx.math.getValue({valueOf: 42})));
}
},
{
file: "math/float.js",
feature: "jsx.math.getValue(obj)",
description: "<code>obj.valueOf()</code> does not return number, return <code>NaN</code>",
code: function () {
assert(isNaN(jsx.math.getValue({valueOf: function () { return false; }})));
}
},
{
file: "math/float.js",
feature: "jsx.math.getValue(obj)",
description: "<code>obj.valueOf()</code> returns number, return the return value",
code: function () {
assert(jsx.math.getValue({valueOf: function () { return 42; }}) === 42);
}
},
{
file: "math/float.js",
feature: "jsx.math.min()",
description: "No arguments, return <code>Number.POSITIVE_INFINITY</code>",
code: function () {
assert(jsx.math.min() === Number.POSITIVE_INFINITY);
}
},
{
file: "math/float.js",
feature: "jsx.math.min(number)",
description: "return <code>number</code>",
code: function () {
assert(jsx.math.min(42) === 42);
}
},
{
file: "math/float.js",
feature: "jsx.math.min(-1, 1, 0)",
description: "return <code>-1</code>",
code: function () {
assert(jsx.math.min(-1, 1, 0) === -1);
}
},
{
file: "math/float.js",
feature: "jsx.math.min(0, -1, 1)",
description: "return <code>-1</code>",
code: function () {
assert(jsx.math.min(0, -1, 1) === -1);
}
},
{
file: "math/float.js",
feature: "jsx.math.min(1, 0, -1)",
description: "return <code>-1</code>",
code: function () {
assert(jsx.math.min(1, 0, -1) === -1);
}
},
{
file: "math/float.js",
feature: "jsx.math.min([-1, 1, 0])",
description: "return <code>-1</code>",
code: function () {
assert(jsx.math.min([-1, 1, 0]) === -1);
}
},
{
file: "math/float.js",
feature: "jsx.math.min(-2, [-1, 1, 0])",
description: "return <code>-2</code>",
code: function () {
assert(jsx.math.min(-2, [-1, 1, 0]) === -2);
}
},
{
file: "math/float.js",
feature: "jsx.math.min([-1, 1, 0], -2)",
description: "return <code>-2</code>",
code: function () {
assert(jsx.math.min([-1, 1, 0], -2) === -2);
}
},
{
file: "math/float.js",
feature: "jsx.math.min([-1, 1, -2], 0)",
description: "return <code>-2</code>",
code: function () {
assert(jsx.math.min([-1, 1, -2], 0) === -2);
}
},
{
file: "math/float.js",
feature: "jsx.math.min(1, {valueOf: function () { return -1; }, x: -2})",
description: "return <code>-1</code>",
code: function () {
assert(jsx.math.min(1, {valueOf: function () { return -1; }, x: -2}) === -1);
}
},
{
file: "math/float.js",
feature: "jsx.math.min(0, {x: -1, y: -2, z: 1})",
description: "return <code>-2</code>",
code: function () {
assert(jsx.math.min(0, {x: -1, y: -2, z: 1}) === -2);
}
},
{
file: "math/float.js",
feature: "jsx.math.min(0, {x: {y: -2}, z: -1})",
description: "return <code>-2</code>",
code: function () {
assert(jsx.math.min(0, {x: {y: -2}, z: -1}) === -2);
}
},
{
file: "math/float.js",
feature: "jsx.math.max()",
description: "No arguments, return <code>Number.NEGATIVE_INFINITY</code>",
code: function () {
assert(jsx.math.max() === Number.NEGATIVE_INFINITY);
}
},
{
file: "math/float.js",
feature: "jsx.math.max(number)",
description: "return <code>number</code>",
code: function () {
assert(jsx.math.max(42) === 42);
}
},
{
file: "math/float.js",
feature: "jsx.math.max(-1, 1, 0)",
description: "return <code>1</code>",
code: function () {
assert(jsx.math.max(-1, 1, 0) === 1);
}
},
{
file: "math/float.js",
feature: "jsx.math.max(0, -1, 1)",
description: "return <code>1</code>",
code: function () {
assert(jsx.math.max(0, -1, 1) === 1);
}
},
{
file: "math/float.js",
feature: "jsx.math.max(1, 0, -1)",
description: "return <code>1</code>",
code: function () {
assert(jsx.math.max(1, 0, -1) === 1);
}
},
{
file: "math/float.js",
feature: "jsx.math.max([1, -1, 0])",
description: "return <code>1</code>",
code: function () {
assert(jsx.math.max([1, -1, 0]) === 1);
}
},
{
file: "math/float.js",
feature: "jsx.math.max(2, [-1, 1, 0])",
description: "return <code>2</code>",
code: function () {
assert(jsx.math.max(2, [-1, 1, 0]) === 2);
}
},
{
file: "math/float.js",
feature: "jsx.math.max([1, -1, 0], 2)",
description: "return <code>2</code>",
code: function () {
assert(jsx.math.max([1, -1, 0], 2) === 2);
}
},
{
file: "math/float.js",
feature: "jsx.math.max([1, -1, 2], 0)",
description: "return <code>2</code>",
code: function () {
assert(jsx.math.max([1, -1, 2], 0) === 2);
}
},
{
file: "math/float.js",
feature: "jsx.math.max(-1, {valueOf: function () { return 1; }, x: 0})",
description: "return <code>1</code>",
code: function () {
assert(jsx.math.max(-1, {valueOf: function () { return 1; }, x: 0}) === 1);
}
},
{
file: "math/float.js",
feature: "jsx.math.max(0, {x: 1, y: 2, z: -1})",
description: "return <code>2</code>",
code: function () {
assert(jsx.math.max(0, {x: 1, y: 2, z: -1}) === 2);
}
},
{
file: "math/float.js",
feature: "jsx.math.max(-1, {x: {y: 1}, z: 0})",
description: "return <code>1</code>",
code: function () {
assert(jsx.math.max(-1, {x: {y: 1}, z: 0}) === 1);
}
},
 
{
file: "math/integer.js",
feature: "Math.primes(10)",
description: "return <code>{2: true, 3: true, 5: true, 7: true}</code>",
code: function () {
assertObjectEquals(
{2: true, 3: true, 5: true, 7: true},
Math.primes(10));
}
},
 
{
file: "math/algebra.js",
feature: "new jsx.math.Matrix()",
description: "return <code>[undefined] : Matrix</code>",
code: function () {
assertArrayEquals([void 0], new jsx.math.Matrix().get());
}
},
{
file: "math/algebra.js",
feature: "new jsx.math.Matrix(0)",
description: "throw <code>jsx.math.DimensionError</code>",
code: function () {
var fail = false;
 
jsx.tryThis(
function () {
new jsx.math.Matrix(0);
},
function (e) {
if (e.constructor == jsx.math.DimensionError)
{
fail = true;
jsx.dmsg(e);
}
else
{
jsx.rethrowThis(e);
}
}
);
 
assert(fail);
}
},
{
file: "math/algebra.js",
feature: "new jsx.math.Matrix(1)",
description: "return <code>[undefined] : Matrix</code>",
code: function () {
assertArrayEquals([void 0], new jsx.math.Matrix(1).get());
}
},
{
file: "math/algebra.js",
feature: "new jsx.math.Matrix(1, 0)",
description: "throw <code>jsx.math.DimensionError</code>",
code: function () {
var fail = jsx.tryThis(
function () {
return !(new jsx.math.Matrix(1, 0));
},
function (e) {
jsx.dmsg(e);
return (e instanceof jsx.math.DimensionError);
}
);
 
assert(fail);
}
}
]
});
}
 
// var d = new Date(), n = 0.09;
// alert([
// n + " + 0.09 = " + (new Float(n)).add(0.09),
// n + " + 0.09 = " + (n + 0.09),
// (new Date() - d) + " ms"
// ].join("\n"));
Property changes:
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property