Merge pull request #515 from ericman314/complex-units

Added support for complex units
This commit is contained in:
Jos de Jong 2015-12-24 16:11:15 +01:00
commit 02a2bbe9fb
28 changed files with 252 additions and 48 deletions

View File

@ -63,11 +63,7 @@ function factory (type, config, load, typed) {
},
'Unit': function(x) {
// This gives correct, but unexpected, results for units with an offset.
// For example, abs(-283.15 degC) = -263.15 degC !!!
var ret = x.clone();
ret.value = abs(ret.value);
return ret;
return x.abs();
}
});

View File

@ -172,30 +172,39 @@ function factory (type, config, load, typed) {
* @private
*/
function _cbrtUnit(x) {
var negate = isNegative(x.value);
if (negate) {
x.value = unaryMinus(x.value);
}
// TODO: create a helper function for this
var third;
if (x.value && x.value.isBigNumber) {
third = new type.BigNumber(1).div(3);
}
else if (x.value && x.value.isFraction) {
third = new type.Fraction(1, 3);
if(x.value && x.value.isComplex) {
var result = x.clone();
result.value = 1.0;
result = result.pow(1.0/3); // Compute the units
result.value = _cbrtComplex(x.value); // Compute the value
return result;
}
else {
third = 1/3;
var negate = isNegative(x.value);
if (negate) {
x.value = unaryMinus(x.value);
}
// TODO: create a helper function for this
var third;
if (x.value && x.value.isBigNumber) {
third = new type.BigNumber(1).div(3);
}
else if (x.value && x.value.isFraction) {
third = new type.Fraction(1, 3);
}
else {
third = 1/3;
}
var result = x.pow(third);
if (negate) {
result.value = unaryMinus(result.value);
}
return result;
}
var result = x.pow(third);
if (negate) {
result.value = unaryMinus(result.value);
}
return result;
}
cbrt.toTex = '\\sqrt[3]{${args[0]}}';

View File

@ -36,13 +36,13 @@ function factory(type, config, load, typed) {
return x.mul(y);
},
'number | Fraction | BigNumber, Unit': function (x, y) {
'number | Fraction | BigNumber | Complex, Unit': function (x, y) {
var res = y.clone();
res.value = (res.value === null) ? res._normalize(x) : multiplyScalar(res.value, x);
return res;
},
'Unit, number | Fraction | BigNumber': function (x, y) {
'Unit, number | Fraction | BigNumber | Complex': function (x, y) {
var res = x.clone();
res.value = (res.value === null) ? res._normalize(y) : multiplyScalar(res.value, y);
return res;

View File

@ -5,7 +5,8 @@ var format = require('../../utils/number').format;
function factory (type, config, load, typed) {
// TODO: remove dependency on Unit, not good for modularization
var Unit = load(require('./../unit/Unit'));
// Update: Unit.hasBase now accepts a String, so no need to use Unit.BASE_UNITS
// var Unit = load(require('./../unit/Unit'));
/**
* @constructor Complex
@ -317,7 +318,7 @@ function factory (type, config, load, typed) {
var r = arguments[0],
phi = arguments[1];
if (isNumber(r)) {
if (phi && phi.isUnit && phi.hasBase(Unit.BASE_UNITS.ANGLE)) {
if (phi && phi.isUnit && phi.hasBase('ANGLE')) {
// convert unit to a number in radians
phi = phi.toNumber('rad');
}

View File

@ -9,11 +9,13 @@ function factory (type, config, load, typed) {
var multiply = load(require('../../function/arithmetic/multiplyScalar'));
var divide = load(require('../../function/arithmetic/divideScalar'));
var pow = load(require('../../function/arithmetic/pow'));
var abs = load(require('../../function/arithmetic/abs'));
var equal = load(require('../../function/relational/equal'));
var isNumeric = load(require('../../function/utils/isNumeric'));
var format = load(require('../../function/utils/format'));
var getTypeOf = load(require('../../function/utils/typeof'));
var toNumber = load(require('../../type/number'));
var Complex = load(require('../../type/complex/Complex'));
/**
* @constructor Unit
@ -29,7 +31,7 @@ function factory (type, config, load, typed) {
* var c = math.in(a, new Unit(null, 'm'); // 0.05 m
* var d = new Unit(9.81, "m/s^2"); // 9.81 m/s^2
*
* @param {number | BigNumber | Fraction | boolean} [value] A value like 5.2
* @param {number | BigNumber | Fraction | Complex | boolean} [value] A value like 5.2
* @param {string} [name] A unit name like "cm" or "inch", or a derived unit of the form: "u1[^ex1] [u2[^ex2] ...] [/ u3[^ex3] [u4[^ex4]]]", such as "kg m^2/s^2", where each unit appearing after the forward slash is taken to be in the denominator. "kg m^2 s^-2" is a synonym and is also acceptable. Any of the units can include a prefix.
*/
function Unit(value, name) {
@ -37,8 +39,8 @@ function factory (type, config, load, typed) {
throw new Error('Constructor must be called with the new operator');
}
if (value != undefined && !isNumeric(value)) {
throw new TypeError('First parameter in Unit constructor must numeric');
if (!(value === undefined || isNumeric(value) || value.isComplex)) {
throw new TypeError('First parameter in Unit constructor must be number, BigNumber, Fraction, Complex, or undefined');
}
if (name != undefined && (typeof name !== 'string' || name == '')) {
throw new TypeError('Second parameter in Unit constructor must be a string');
@ -564,10 +566,18 @@ function factory (type, config, load, typed) {
/**
* check if this unit has given base unit
* If this unit is a derived unit, this will ALWAYS return false, since by definition base units are not derived.
* @param {BASE_UNITS | undefined} base
* @param {BASE_UNITS | STRING | undefined} base
*/
Unit.prototype.hasBase = function (base) {
if(typeof(base) === "string") {
base = BASE_UNITS[base];
}
if(!base)
return false;
// All dimensions must be the same
for(var i=0; i<BASE_DIMENSIONS.length; i++) {
if (Math.abs(this.dimensions[i] - base.dimensions[i]) > 1e-12) {
@ -692,9 +702,10 @@ function factory (type, config, load, typed) {
res.value = pow(res.value, p);
// only allow numeric output, we don't want to return a Complex number
if (!isNumeric(res.value)) {
res.value = NaN;
}
//if (!isNumeric(res.value)) {
// res.value = NaN;
//}
// Update: Complex supported now
}
else {
res.value = null;
@ -705,6 +716,25 @@ function factory (type, config, load, typed) {
return res;
};
/**
* Calculate the absolute value of a unit
* @param {number | Fraction | BigNumber} x
* @returns {Unit} The result: |x|, absolute value of x
*/
Unit.prototype.abs = function () {
// This gives correct, but unexpected, results for units with an offset.
// For example, abs(-283.15 degC) = -263.15 degC !!!
var ret = this.clone();
ret.value = abs(ret.value);
for(var i in ret.units) {
if(ret.units[i].unit.name === 'VA' || ret.units[i].unit.name === 'VAR') {
ret.units[i].unit = UNITS["W"];
}
}
return ret;
};
/**
* Convert the unit to a specific unit name.
@ -958,6 +988,27 @@ function factory (type, config, load, typed) {
// Simplfy the unit list, if necessary
this.simplifyUnitListLazy();
// Apply some custom logic for handling VA and VAR. The goal is to express the value of the unit as a real value, if possible. Otherwise, use a real-valued unit instead of a complex-valued one.
var isImaginary = false;
var isReal = true;
if(typeof(this.value) !== 'undefined' && this.value !== null && this.value.isComplex) {
// TODO: Make this better, for example, use relative magnitude of re and im rather than absolute
isImaginary = Math.abs(this.value.re) < 1e-14;
isReal = Math.abs(this.value.im) < 1e-14;
}
for(var i in this.units) {
if(this.units[i].unit) {
if(this.units[i].unit.name === 'VA' && isImaginary) {
this.units[i].unit = UNITS["VAR"];
}
else if(this.units[i].unit.name === 'VAR' && !isImaginary) {
this.units[i].unit = UNITS["VA"];
}
}
}
// Now apply the best prefix
// Units must have only one unit and not have the fixPrefix flag set
if (this.units.length === 1 && !this.fixPrefix) {
@ -972,6 +1023,9 @@ function factory (type, config, load, typed) {
var value = this._denormalize(this.value);
var str = (this.value !== null) ? format(value, options || {}) : '';
var unitStr = this.formatUnits();
if(this.value && this.value.isComplex) {
str = "(" + str + ")"; // Surround complex values with ( ) to enable better parsing
}
if(unitStr.length > 0 && str.length > 0) {
str += " ";
}
@ -1000,14 +1054,16 @@ function factory (type, config, load, typed) {
// Note: the units value can be any numeric type, but to find the best
// prefix it's enough to work with limited precision of a regular number
var absValue = Math.abs(toNumber(this.value));
// Update: using mathjs abs since we also allow complex numbers
var absValue = abs(this.value);
var absUnitValue = abs(this.units[0].unit.value);
var bestPrefix = this.units[0].prefix;
if (absValue === 0) {
return bestPrefix;
}
var power = this.units[0].power;
var bestDiff = Math.abs(
Math.log(absValue / Math.pow(bestPrefix.value * this.units[0].unit.value, power)) / Math.LN10 - 1.2);
Math.log(absValue / Math.pow(bestPrefix.value * absUnitValue, power)) / Math.LN10 - 1.2);
var prefixes = this.units[0].unit.prefixes;
for (var p in prefixes) {
@ -1016,7 +1072,7 @@ function factory (type, config, load, typed) {
if (prefix.scientific) {
var diff = Math.abs(
Math.log(absValue / Math.pow(prefix.value * this.units[0].unit.value, power)) / Math.LN10 - 1.2);
Math.log(absValue / Math.pow(prefix.value * absUnitValue, power)) / Math.LN10 - 1.2);
if (diff < bestDiff
|| (diff === bestDiff && prefix.name.length < bestPrefix.name.length)) {
@ -2196,6 +2252,23 @@ function factory (type, config, load, typed) {
offset: 0
},
// Electrical power units
VAR: {
name: 'VAR',
base: BASE_UNITS.POWER,
prefixes: PREFIXES.SHORT,
value: new Complex(0,1),
offset: 0
},
VA: {
name: 'VA',
base: BASE_UNITS.POWER,
prefixes: PREFIXES.SHORT,
value: 1,
offset: 0
},
// Pressure
Pa: {
name: 'Pa',
@ -2553,6 +2626,10 @@ function factory (type, config, load, typed) {
return new type.Fraction(x);
},
Complex: function (x) {
return x;
},
number: function (x) {
return x;
}

View File

@ -40,7 +40,7 @@ function factory (type, config, load, typed) {
return type.Unit.parse(x); // a unit with value, like '5cm'
},
'number | BigNumber | Fraction, string': function (value, unit) {
'number | BigNumber | Fraction | Complex, string': function (value, unit) {
return new type.Unit(value, unit);
},

View File

@ -81,6 +81,9 @@ describe('abs', function () {
u = math.abs(math.unit(math.fraction(2,3), 'm'));
assert.equal(u.toString(), '2/3 m');
u = math.abs(math.unit(math.complex(-4, 3), 'in'));
assert.equal(u.toString(), '5 in');
});
it('should throw an error in case of invalid number of arguments', function() {

View File

@ -96,6 +96,8 @@ describe('add', function() {
approx.deepEqual(add(math.unit(5, 'km'), math.unit(100, 'mile')), math.unit(165.93, 'km'));
approx.deepEqual(add(math.unit(math.fraction(1,3), 'm'), math.unit(math.fraction(1,3), 'm')).toString(), '2/3 m');
approx.deepEqual(add(math.unit(math.complex(-3, 2), 'g'), math.unit(math.complex(5, -6), 'g')).toString(), '(2 - 4i) g');
});
it('should throw an error for two measures of different units', function() {

View File

@ -106,6 +106,9 @@ describe('cbrt', function() {
assert.deepEqual(cbrt(math.unit(math.bignumber(27), 'm^3')).value, math.bignumber(3));
assert(cbrt(math.unit(math.bignumber(-27), 'm^3')).value.isBigNumber);
assert.deepEqual(cbrt(math.unit(math.bignumber(-27), 'm^3')).value, math.bignumber(-3));
assert(cbrt(math.unit(math.complex(-46, 9), 's^3')).value.isComplex);
approx.deepEqual(cbrt(math.unit(math.complex(-46, 9), 's^3')).value, math.complex(2, 3));
});
it('should throw an error when used with a string', function() {

View File

@ -130,6 +130,8 @@ describe('divide', function() {
assert.equal(divide(10, math.unit('4 mg/s')).toString(), '2.5 s / mg');
assert.equal(divide(10, math.unit(math.fraction(4), 'mg/s')).toString(), '5/2 s / mg');
approx.equal(math.format(divide(10, math.unit(math.complex(1,2), 'm/s')), 14), '(2 - 4i) s / m');
});
it('should divide two units', function() {
@ -138,6 +140,10 @@ describe('divide', function() {
var a = math.unit(math.fraction(75), 'mi/h');
var b = math.unit(math.fraction(40), 'mi/gal');
assert.equal(divide(a, b).to('gal/minute').toString(), '1/32 gal / minute');
var c = math.unit(math.complex(21, 1), 'kg');
var d = math.unit(math.complex(2, -3), 's');
assert.equal(divide(c, d).toString(), "(3 + 5i) kg / s");
});
it('should divide one valued unit by a valueless unit and vice-versa', function() {

View File

@ -148,6 +148,9 @@ describe('multiply', function() {
assert.equal(multiply(3, unit(math.fraction(1,4), 'm')).toString(), '3/4 m');
assert.equal(multiply(math.fraction(1,4), unit(3, 'm')).toString(), '3/4 m');
assert.equal(multiply(unit(3, 'm'), math.fraction(1,4)).toString(), '3/4 m');
assert.equal(multiply(unit(math.complex(9, 8), 'm'), 2).toString(), '(18 + 16i) m');
assert.equal(math.format(multiply(unit(math.complex(2, 3), 'g'), math.complex(4, 5)), 14), '(-7 + 22i) g');
});
it('should multiply a number and a unit without value correctly', function() {
@ -165,6 +168,7 @@ describe('multiply', function() {
assert.equal(multiply(unit('65 mi/h'), unit('2 h')).to('mi').toString(), '130 mi');
assert.equal(multiply(unit('2 L'), unit('1 s^-1')).toString(), '2 L / s');
assert.equal(multiply(unit('2 m/s'), unit('0.5 s/m')).toString(), '1');
assert.equal(multiply(unit(math.complex(3,-4), 'N'), unit(math.complex(7,-2), 'm')).toString(), '(13 - 34i) J');
});
it('should multiply valueless units correctly', function() {
@ -193,12 +197,12 @@ describe('multiply', function() {
assert.equal(multiply(unit('inch'), bignumber(2)).toString(), '2 inch');
});
it('should throw an error in case of unit non-numeric argument', function() {
// Multiplying two units is supported now --ericman314
// Multiplying two units is supported now
//assert.throws(function () {multiply(math.unit('5cm'), math.unit('4cm'));}, /TypeError: Unexpected type/);
assert.throws(function () {multiply(math.unit('5cm'), math.complex('2+3i'));}, /TypeError: Unexpected type/);
assert.throws(function () {multiply(math.complex('2+3i'), math.unit('5cm'));}, /TypeError: Unexpected type/);
// Complex units are supported now
//assert.throws(function () {multiply(math.unit('5cm'), math.complex('2+3i'));}, /TypeError: Unexpected type/);
//assert.throws(function () {multiply(math.complex('2+3i'), math.unit('5cm'));}, /TypeError: Unexpected type/);
});

View File

@ -4,6 +4,7 @@ var approx = require('../../../tools/approx');
var math = require('../../../index');
var bignumber = math.bignumber;
var fraction = math.fraction;
var complex = math.complex;
describe('sign', function() {
it('should calculate the sign of a boolean', function () {
@ -51,6 +52,8 @@ describe('sign', function() {
assert.deepEqual(math.sign(math.unit(bignumber(-5), 'cm')), bignumber(-1));
assert.deepEqual(math.sign(math.unit(fraction(5), 'cm')), fraction(1));
assert.deepEqual(math.sign(math.unit(fraction(-5), 'cm')), fraction(-1));
assert.deepEqual(math.sign(math.unit(complex(3,4), 'mi')), complex(0.6,0.8));
});
it('should throw an error when used with a string', function() {

View File

@ -69,9 +69,10 @@ describe('sqrt', function() {
assert.equal(sqrt(math.unit('4 kg')).toString(), '2 kg^0.5');
});
it('should return NaN when computing the square root of a negative unit', function() {
it('should return a Unit with a Complex value when computing the square root of a negative unit', function() {
// Update this when support for complex units is added
assert.equal(sqrt(math.unit('-25 m^2/s^2')).toString(), 'NaN m / s');
//assert.equal(sqrt(math.unit('-25 m^2/s^2')).toString(), 'NaN m / s');
assert.equal(math.format(sqrt(math.unit('-25 m^2/s^2')), 14), '(5i) m / s');
});
it('should throw an error when used with a string', function() {

View File

@ -94,6 +94,9 @@ describe('subtract', function() {
approx.deepEqual(subtract(math.unit(5, 'km'), math.unit(100, 'mile')), math.unit(-155.93, 'km'));
assert.deepEqual(subtract(math.unit(math.bignumber(5), 'km'), math.unit(math.bignumber(2), 'km')), math.unit(math.bignumber(3), 'km'));
assert.deepEqual(subtract(math.unit(math.complex(10,10), 'K'), math.unit(math.complex(3,4), 'K')), math.unit(math.complex(7,6), 'K'));
assert.deepEqual(subtract(math.unit(math.complex(10,10), 'K'), math.unit(3, 'K')), math.unit(math.complex(7,10), 'K'));
});
it('should throw an error if subtracting two quantities of different units', function() {

View File

@ -3,6 +3,7 @@ var assert = require('assert');
var math = require('../../../index');
var bignumber = math.bignumber;
var fraction = math.fraction;
var complex = math.complex;
describe('unaryMinus', function() {
it('should return unary minus of a boolean', function () {
@ -52,6 +53,7 @@ describe('unaryMinus', function() {
it('should perform unary minus of a unit', function() {
assert.equal(math.unaryMinus(math.unit(5, 'km')).toString(), '-5 km');
assert.equal(math.unaryMinus(math.unit(fraction(2/3), 'km')).toString(), '-2/3 km');
assert.equal(math.unaryMinus(math.unit(complex(2,-4), 'gal')).toString(), '(-2 + 4i) gal');
});
it('should perform element-wise unary minus on a matrix', function() {

View File

@ -99,6 +99,8 @@ describe('cos', function() {
assert(cos(unit(math.bignumber(45), 'deg')).isBigNumber);
approx.equal(cos(unit(math.bignumber(45), 'deg')).toNumber(), 0.707106781186548);
approx.deepEqual(cos(unit(complex(1,1), 'rad')), complex(0.833730025131149, -0.988897705762865));
});
it('should throw an error if called with an invalid unit', function() {

View File

@ -64,6 +64,8 @@ describe('cosh', function() {
assert(cosh(unit(math.bignumber(90), 'deg')).isBigNumber);
approx.equal(cosh(unit(math.bignumber(90), 'deg')).toNumber(), 2.5091784786581);
approx.deepEqual(cosh(math.unit(complex('2 + i'), 'rad')), complex(2.0327230070197, 3.0518977991518));
});
it('should throw an error if called with an invalid unit', function() {

View File

@ -82,6 +82,8 @@ describe('cot', function() {
assert(cot(unit(math.bignumber(45), 'deg')).isBigNumber);
approx.equal(cot(unit(math.bignumber(45), 'deg')).toNumber(), 1);
approx.deepEqual(cot(math.unit(complex('1+i'), 'rad')), complex(0.217621561854403, -0.868014142895925));
});
it('should throw an error if called with an invalid unit', function() {

View File

@ -52,6 +52,8 @@ describe('coth', function() {
assert(coth(unit(math.bignumber(90), 'deg')).isBigNumber);
approx.equal(coth(unit(math.bignumber(90), 'deg')).toNumber(), 1.0903314107274);
approx.deepEqual(coth(math.unit(complex('2 + i'), 'rad')), complex(0.98432922645819, -0.032797755533753));
});
it('should throw an error if called with an invalid unit', function() {

View File

@ -73,6 +73,8 @@ describe('csc', function() {
assert(csc(unit(math.bignumber(45), 'deg')).isBigNumber);
approx.equal(csc(unit(math.bignumber(45), 'deg')).toNumber(), 1.41421356237310);
approx.deepEqual(csc(unit(complex('1+i'), 'rad')), complex(0.621518017170428, -0.303931001628426));
});
it('should throw an error if called with an invalid unit', function() {

View File

@ -55,6 +55,8 @@ describe('csch', function() {
assert(csch(unit(math.bignumber(90), 'deg')).isBigNumber);
approx.equal(csch(unit(math.bignumber(90), 'deg')).toNumber(), 0.4345372080947);
approx.deepEqual(csch(unit(complex('2 + i'), 'rad')), complex(0.14136302161241, -0.22837506559969));
});
it('should throw an error if called with an invalid unit', function() {

View File

@ -82,6 +82,8 @@ describe('sec', function() {
assert(sec(unit(math.bignumber(45), 'deg')).isBigNumber);
approx.equal(sec(unit(math.bignumber(45), 'deg')).toNumber(), 1.41421356237310);
approx.deepEqual(sec(unit(complex('1+i'), 'rad')), complex(0.498337030555187, 0.591083841721045));
});
it('should throw an error if called with an invalid unit', function() {

View File

@ -53,6 +53,8 @@ describe('sech', function() {
assert(sech(unit(math.bignumber(90), 'deg')).isBigNumber);
approx.equal(sech(unit(math.bignumber(90), 'deg')).toNumber(), 0.39853681533839);
approx.deepEqual(sech(unit(complex('2 + i'), 'rad')), complex(0.15117629826558, -0.22697367539372));
});
it('should throw an error if called with an invalid unit', function() {

View File

@ -91,6 +91,8 @@ describe('sin', function() {
assert(sin(unit(math.bignumber(45), 'deg')).isBigNumber);
approx.equal(sin(unit(math.bignumber(45), 'deg')).toNumber(), 0.707106781186548);
approx.deepEqual(sin(unit(complex('1+i'), 'rad')), complex(1.298457581415977, 0.634963914784736));
});
it('should throw an error if called with an invalid unit', function() {

View File

@ -67,6 +67,8 @@ describe('sinh', function() {
assert(sinh(unit(math.bignumber(90), 'deg')).isBigNumber);
approx.equal(sinh(unit(math.bignumber(90), 'deg')).toNumber(), 2.3012989023073);
approx.deepEqual(sinh(unit(complex('2 + i'), 'rad')), complex(1.9596010414216, 3.1657785132162));
});
it('should throw an error if called with an invalid unit', function() {

View File

@ -76,6 +76,8 @@ describe('tan', function() {
assert(tan(unit(math.bignumber(60), 'deg')).isBigNumber);
approx.equal(tan(unit(math.bignumber(60), 'deg')).toNumber(), math.sqrt(3));
approx.deepEqual(tan(unit(complex('1+i'), 'rad')), complex(0.271752585319512, 1.083923327338695));
});
it('should throw an error if called with an invalid unit', function() {

View File

@ -63,6 +63,8 @@ describe('tanh', function() {
assert(tanh(unit(math.bignumber(90), 'deg')).isBigNumber);
approx.equal(tanh(unit(math.bignumber(90), 'deg')).toNumber(), 0.91715233566727);
approx.deepEqual(tanh(unit(complex('2 + i'), 'rad')), complex(1.0147936161466, 0.033812826079897));
});
it('should throw an error if called with an invalid unit', function() {

View File

@ -43,6 +43,12 @@ describe('Unit', function() {
assert.equal(unit1.units[0].unit.name, 'm');
});
it('should create a unit with Complex value', function () {
var unit1 = new Unit(math.complex(500, 600), 'cm');
assert.deepEqual(unit1.value, math.complex(5, 6));
assert.equal(unit1.units[0].unit.name, 'm');
});
it('should create square meter correctly', function() {
var unit1 = new Unit(0.000001, 'km2');
assert.equal(unit1.value, 1);
@ -160,6 +166,16 @@ describe('Unit', function() {
assert.equal(new Unit(100, 'cm').equals(new Unit(math.fraction(2), 'm')), false);
});
it('should test whether two Complex units are equal', function() {
assert.equal(new Unit(math.complex(3, 4), 'km').equals(new Unit(math.complex(3000, 4000), 'm')), true);
assert.equal(new Unit(math.complex(3, 4), 'km').equals(new Unit(math.complex(3000, 10), 'm')), false);
});
it('should test whether a Complex unit and a unit with a number are equal', function() {
assert.equal(new Unit(math.complex(3, 0), 'km').equals(new Unit(3000, 'm')), true);
assert.equal(new Unit(math.complex(3, 4), 'km').equals(new Unit(3000, 'm')), false);
});
});
describe('clone', function() {
@ -195,6 +211,14 @@ describe('Unit', function() {
assert(u1.value !== u2.value); // should be cloned
});
it('should clone a Complex unit', function() {
var u1 = new Unit(math.complex(1,3), 'cm');
var u2 = u1.clone();
assert(u1 !== u2);
assert.deepEqual(u1, u2);
assert(u1.value !== u2.value); // should be cloned
});
});
describe('toNumber', function() {
@ -223,7 +247,7 @@ describe('Unit', function() {
});
});
describe('toNumberic', function() {
describe('toNumeric', function() {
it ('should convert a unit to a numeric value', function () {
var u = new Unit(math.fraction(1,3), 'cm');
assert.deepEqual(u.toNumeric('mm'), math.fraction(10,3));
@ -273,6 +297,13 @@ describe('Unit', function() {
assert.equal(u2.fixPrefix, true);
});
it ('should convert a Complex unit', function() {
var u1 = new Unit(math.complex(300,400), 'kPa');
var u2 = u1.to('lbf/in^2');
approx.deepEqual(u2.value, math.complex(300000, 400000));
assert.deepEqual(u2.toString(), "(43.511321319062766 + 58.01509509208369i) lbf / in^2");
});
it ('should convert a unit to a fixed unit', function () {
var u1 = new Unit(5000, 'cm');
assert.equal(u1.value, 50);
@ -453,6 +484,10 @@ describe('Unit', function() {
it('should convert a unit with Fraction to string properly', function() {
assert.equal(new Unit(math.fraction(9/10), 'mm').toString(), '9/10 mm');
});
it('should convert a Complex unit to string properly', function() {
assert.equal(new Unit(math.complex(-1,-2), 'J / (mol K)').toString(), '(-1 - 2i) J / (mol K)');
});
});
describe('simplifyUnitListLazy', function() {
@ -545,9 +580,19 @@ describe('Unit', function() {
unit: 'cm',
fixPrefix: false
});
approx.deepEqual(new Unit(math.complex(2, 4), 'g').toJSON(),
{
mathjs: 'Unit',
value: math.complex(2, 4),
unit: 'g',
fixPrefix: false
});
var str = JSON.stringify(new Unit(math.fraction(0.375), 'cm'));
assert.deepEqual(str, '{"mathjs":"Unit","value":{"mathjs":"Fraction","n":3,"d":8},"unit":"cm","fixPrefix":false}');
var cmpx = JSON.stringify(new Unit(math.complex(2, 4), 'g'));
assert.equal(cmpx, '{"mathjs":"Unit","value":{"mathjs":"Complex","re":2,"im":4},"unit":"g","fixPrefix":false}');
});
it('fromJSON', function () {
@ -573,6 +618,14 @@ describe('Unit', function() {
fixPrefix: false
});
assert.deepEqual(u7, new Unit(math.fraction(0.375), 'cm'))
var u8 = Unit.fromJSON({
mathjs: 'Unit',
value: math.complex(2, 4),
unit: 'g',
fixPrefix: false
});
assert.deepEqual(u8, new Unit(math.complex(2,4), 'g'));
});
it('toJSON -> fromJSON should recover an "equal" unit', function() {
@ -612,6 +665,23 @@ describe('Unit', function() {
assert.equal(new Unit(math.fraction(4/5), 'm').format(), '4/5 m');
});
it('should format a Complex unit', function() {
assert.equal(new Unit(math.complex(-2, 4.5), 'mm').format(14), '(-2 + 4.5i) mm');
});
it('should format units with VA and VAR correctly', function() {
assert.equal(math.eval('4000 VAR + 3000 VA').format(), "(3 + 4i) kVA");
assert.equal(math.eval('3000 VA + 4000 VAR').format(), "(3 + 4i) kVA");
assert.equal(math.eval('4000 VAR').format(), "(4) kVAR");
assert.equal(math.eval('4000i VA').format(), "(4) kVAR");
assert.equal(math.eval('4000i VAR').format(), "(-4) kVA");
assert.equal(math.eval('abs(4000 VAR + 3000 VA)').format(), "5 kW");
assert.equal(math.eval('abs(3000 VA + 4000 VAR)').format(), "5 kW");
assert.equal(math.eval('abs(4000 VAR)').format(), "4 kW");
assert.equal(math.eval('abs(4000i VA)').format(), "4 kW");
assert.equal(math.eval('abs(4000i VAR)').format(), "4 kW");
});
it('should ignore properties in Object.prototype when finding the best prefix', function() {
Object.prototype.foo = 'bar';