nerdamer
Version:
javascript light-weight symbolic math expression evaluator
1,564 lines (1,495 loc) • 99.4 kB
JavaScript
/* global expect */
'use strict';
var nerdamer = require('../nerdamer.core.js');
var utils = require('./support/utils');
var _ = utils.toFixed;
var run = utils.run;
var core = nerdamer.getCore();
var round = core.Utils.round;
var block = core.Utils.block;
//, x=2.1, y=3.3, z=1, a=7.42
var values = {
x: 2.1,
y: 3.3,
z: 1,
a: 7.42
};
describe('Nerdamer core', function () {
it('should perform simple arithmetic', function () {
// given
var testCases = [
{
given: '((((((1+1))))))',
expected: '2',
expectedValue: '2'
},
{
given: '((((((1+1))+4)))+3)',
expected: '9',
expectedValue: '9'
},
{
given: '1+1',
expected: '2',
expectedValue: '2'
},
{
given: '4^2',
expected: '16',
expectedValue: '16'
},
{
given: '2*-4',
expected: '-8',
expectedValue: '-8'
},
{
given: '2+(3/4)',
expected: '11/4',
expectedValue: '2.75'
},
{
given: '2/3+2/3',
expected: '4/3',
expectedValue: '1.3333333333333333'
},
{
given: '6.5*2',
expected: '13',
expectedValue: '13'
},
{
given: '(11.85)^(1/2)',
expected: '(1/2)*sqrt(237)*sqrt(5)^(-1)',
expectedValue: '3.4423828956117015'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate().text('decimals');
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
expect(round(value), 14).toEqual(round(testCases[i].expectedValue) ,14);
}
});
it('should handle minus sign properly', function () {
// given
var cases = [
{
given: '0-4',
expected: '-4'
},
{
given: '-(4)',
expected: '-4'
},
{
given: '3*-(4)',
expected: '-12'
},
{
given: '-3*-(4)',
expected: '12'
},
{
given: '-(3*-(4))',
expected: '12'
},
{
given: '-(-3*-(4))',
expected: '-12'
},
{
given: '-(3)-3',
expected: '-6'
},
{
given: '3^-1^-1',
expected: '1/3'
},
{
given: '-1',
expected: '-1'
},
{
given: '--1',
expected: '1'
},
{
given: '8-1',
expected: '7'
},
{
given: '(-1)',
expected: '-1'
},
{
given: '-(1)-1',
expected: '-2'
},
{
given: '-(-1-1)',
expected: '2'
},
{
given: '-(-1-+1)^2',
expected: '-4'
},
{
given: '-(-1-1+1)',
expected: '1'
},
{
given: '-(1)--(1-1--1)',
expected: '0'
},
{
given: '-(-(1))-(--1)',
expected: '0'
},
{
given: '5^-3',
expected: '1/125'
},
{
given: '5^---3',
expected: '1/125'
},
{
given: '5^-(1--2)',
expected: '1/125'
},
{
given: '5^-(++1+--+2)',
expected: '1/125'
},
{
given: '(5^-(++1+--+2))^-2',
expected: '15625'
},
{
given: '(5^-3^2)',
expected: '1/1953125'
},
{
given: '(5^-3^-2)',
expected: '5^(-1/9)'
},
{
given: '-(5^-3^-2)^-3',
expected: '-5^(1/3)'
},
{
given: '-(--5*--7)',
expected: '-35'
},
{
given: '(-1)^(3/4)',
expected: '(-1)^(3/4)'
}
];
for (var k in cases) {
// when
var parsed = nerdamer(cases[k].given);
// then
expect(parsed.toString()).toEqual(cases[k].expected);
}
});
it('should perform simple calculations with variables', function () {
// given
var testCases = [
{
given: 'x+x',
expected: '2*x',
expectedValue: '4.2'
}, {
given: 'x+1',
expected: '1+x',
expectedValue: '3.1'
}, {
given: 'x+y',
expected: 'x+y',
expectedValue: '5.4'
}, {
given: '-9-x+y-11',
expected: '-20-x+y',
expectedValue: '-18.8'
}, {
given: '(x+1)+(1+x)',
expected: '2+2*x',
expectedValue: '6.2'
}, {
given: '9+(x+1)-(1+x)',
expected: '9',
expectedValue: '9'
}, {
given: '0-x-2*x+6',
expected: '-3*x+6',
expectedValue: '-0.3'
}, {
given: '(x+y)+(a+x)',
expected: '2*x+a+y',
expectedValue: '14.92'
}, {
given: '7*(x+y)+2*(a+x)',
expected: '2*a+7*y+9*x',
expectedValue: '56.84'
}, {
given: 'x^y+x^y',
expected: '2*x^y',
expectedValue: '23.13948390048293'
}, {
given: 'x*x',
expected: 'x^2',
expectedValue: '4.41'
}, {
given: '-x*x',
expected: '-x^2',
expectedValue: '-4.41'
}, {
given: '-x*-x',
expected: 'x^2',
expectedValue: '4.41'
}, {
given: 'x-y',
expected: '-y+x',
expectedValue: '-1.2'
}, {
given: 'x-x',
expected: '0',
expectedValue: '0'
}, {
given: 'x*2',
expected: '2*x',
expectedValue: '4.2'
}, {
given: 'x*y',
expected: 'x*y',
expectedValue: '6.93'
}, {
given: 'x^x',
expected: 'x^x',
expectedValue: '4.749638091742242'
}, {
given: 'x^(x)',
expected: 'x^x',
expectedValue: '4.749638091742242'
}, {
given: 'y^y^3',
expected: 'y^y^3',
expectedValue: '4303635263255155700'
},
{
given: '(x-1)^2+(x-1)^2',
expected: '2*(-1+x)^2',
expectedValue: '2.4200000000000004'
},
{
given: '(-5(x/2-5)/4)^0',
expected: '1',
expectedValue: '1'
},
{
given: '((1+x)^(-2))+((1+x)^(-1))+((1+x)^(-1))+(1)',
expected: '(1+x)^(-2)+2*(1+x)^(-1)+1',
expectedValue: '1.74921956295526'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate(values).text('decimals');
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
expect(round(value), 14).toEqual(round(testCases[i].expectedValue) ,14);
}
});
it('should handle errors', function () {
var formulas = [
'0/0',
'0^0',
'-Infinity+Infinity',
'Infinity/Infinity',
'Infinity^Infinity',
'1^Infinity',
'Infinity^0',
'(-Infinity)^0',
'Infinity*0'
];
for(var i=0; i<formulas.length; i++)
expect(function (){ nerdamer(formulas[i]) }).toThrowError();
});
it('should set postfix operators correctly', function () {
var core = nerdamer.getCore();
var _ = core.PARSER;
var Symbol = core.Symbol;
nerdamer.setOperator({
precedence: 4,
operator: '°',
postfix: true,
operation: function(x){
return _.divide(_.multiply(x, new Symbol('pi')), new Symbol(180));
}
});
expect(nerdamer('x+1°+π+x').toString()).toEqual('(181/180)*pi+2*x');
});
it('should correctly calculate Infinity', function () {
// given
var testCases = [
{
given: '0^Infinity',
expected: '0'
},
{
given: 'Infinity*Infinity',
expected: 'Infinity'
},
{
given: '-Infinity*Infinity',
expected: '-Infinity'
},
{
given: '-Infinity*-Infinity',
expected: 'Infinity'
},
{
given: '-a*-Infinity',
expected: 'Infinity*a'
},
{
given: '-a-Infinity',
expected: '-Infinity'
},
{
given: '-a*Infinity',
expected: '-Infinity*a'
},
{
given: '-a^Infinity',
expected: '-a^Infinity'
},
{
given: '-2^Infinity',
expected: '-Infinity'
},
{
given: '-2^-Infinity',
expected: '0'
},
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
}
});
it('should calculate fib correctly', function () {
// given
var testCases = [
{
given: 'fib(0)',
expected: '0'
},
{
given: 'fib(14)',
expected: '377'
},
{
given: 'fib(-14)',
expected: '-377'
},
{
given: 'fib(15)',
expected: '610'
},
{
given: 'fib(-15)',
expected: '610'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given).evaluate();
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
}
});
it('should calculate sinc correctly', function () {
// given
var testCases = [
{
given: 'sinc(x)',
expected: 'sinc(x)',
eval: false
},
{
given: 'sinc(0)',
expected: '1',
eval: true
},
{
given: 'sinc(9)',
expected: '23287849/508568891',
eval: true
},
{
given: 'sinc(x-a)-sin(x-a)/(x-a)',
expected: '0',
eval: true
}
];
for (var i = 0; i < testCases.length; ++i) {
var testCase = testCases[i];
// when
var parsed = testCase.eval ? nerdamer(testCase.given).evaluate() : nerdamer(testCase.given);
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
}
});
it('should expand terms', function () {
// given
var testCases = [
{
given: 'expand((9*y*x+1)^3)',
expected: '1+243*x^2*y^2+27*x*y+729*x^3*y^3',
expectedValue: '254478.51475300005'
},
{
given: 'expand(x*(x+1))',
expected: 'x+x^2',
expectedValue: '6.51'
},
{
given: 'expand(x*(x+1)^5)',
expected: '10*x^3+10*x^4+5*x^2+5*x^5+x+x^6',
expectedValue: '601.212171'
},
{
given: 'expand((x*y)^x+(x*y)^2)',
expected: '(x*y)^x+x^2*y^2',
expectedValue: '106.3076174497575'
},
{
given: 'expand((3*x+4*y)^4)',
expected: '256*y^4+432*x^3*y+768*x*y^3+81*x^4+864*x^2*y^2',
expectedValue: '144590.0625'
},
{
given: 'expand((9*y*x+1)^2)',
expected: '1+18*x*y+81*x^2*y^2',
expectedValue: '4015.7568999999994'
},
{
given: 'expand((x+5)*(x-3)-x^2)',
expected: '-15+2*x',
expectedValue: '-10.8'
},
{
given: 'expand(((x^3+x)^x*(x^2+x)^x+1)*x)',
expected: '(x+x^2)^x*(x+x^3)^x*x+x',
expectedValue: '17667.12052556627'
},
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate(values).text('decimals');
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
expect(round(value, 12)).toEqual(round(testCases[i].expectedValue, 12)) ;
}
});
it('should expand correctly', function() {
expect(nerdamer('expand((a^2*b*c)^(-1))').toString()).toEqual('a^(-2)*b^(-1)*c^(-1)');
expect(nerdamer('expand(((a^2*b)(x+1))^2)').toString()).toEqual('2*a^4*b^2*x+a^4*b^2+a^4*b^2*x^2');
expect(nerdamer('expand(5*x/(c+d)^2)').toString()).toEqual('5*(2*c*d+c^2+d^2)^(-1)*x');
expect(nerdamer('expand((a+b)*(c+d))').toString()).toEqual('a*c+a*d+b*c+b*d');
expect(nerdamer('expand(5*(a+b)*(c+d))').toString()).toEqual('5*a*c+5*a*d+5*b*c+5*b*d');
expect(nerdamer('expand(4*parens(x+1)^2)').toString()).toEqual('4+4*x^2+8*x');
expect(nerdamer('expand(4*(a*b)*(c*b))').toString()).toEqual('4*a*b^2*c');
expect(nerdamer('expand(4*(a*b)*(c*b)+1)').toString()).toEqual('1+4*a*b^2*c');
expect(nerdamer('expand(3*(a+b)*(g+i)*(x*k))').toString()).toEqual('3*a*g*k*x+3*a*i*k*x+3*b*g*k*x+3*b*i*k*x');
expect(nerdamer('expand(2*x*(x+1)^3)').toString()).toEqual('2*x+2*x^4+6*x^2+6*x^3');
expect(nerdamer('expand((2*(a*b)*(x+1)^3)^2)').toString()).toEqual('24*a^2*b^2*x+24*a^2*b^2*x^5+4*a^2*b^2+4*a^2*b^2*x^6+60*a^2*b^2*x^2+60*a^2*b^2*x^4+80*a^2*b^2*x^3');
expect(nerdamer('expand((2*(a*b)*(x+1)^3)^2+1)').toString()).toEqual('1+24*a^2*b^2*x+24*a^2*b^2*x^5+4*a^2*b^2+4*a^2*b^2*x^6+60*a^2*b^2*x^2+60*a^2*b^2*x^4+80*a^2*b^2*x^3');
expect(nerdamer('expand((d/(x+1)+1)^2)').toString()).toEqual('(1+2*x+x^2)^(-1)*d^2+1+2*(1+x)^(-1)*d');
expect(nerdamer('expand(2*cos((d/(x+1)+1)^2)^2)').toString()).toEqual('2*cos((1+2*x+x^2)^(-1)*d^2+1+2*(1+x)^(-1)*d)^2');
});
it('should handle imaginary log arguments', function () {
// given
var testCases = [
{
given: 'log(5*i)',
expected: '1.5707963267948966*i+1.6094379124341003'
},
{
given: 'log(8+5*i)',
expected: '0.5585993153435624*i+2.2443181848660699'
},
{
given: 'log(123-2*i)',
expected: '-0.01625872980512958*i+4.8123165343435139'
},
{
given: 'log(123-2*i+a)',
expected: 'log(-2*i+123+a)'
},
/*
{
given: 'log(123-2*i+a)',
expected: '-atan2(123+a,-2)*i+1.5707963267948966*i+log(sqrt((123+a)^2+4))'
},
{
given: 'log(x+2*i)',
expected: '-atan2(x,2)*i+1.5707963267948966*i+log(sqrt(4+x^2))'
}
*/
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate().text('decimals', 17);
// then
expect(value).toEqual(testCases[i].expected);
}
});
it('should convert from polar to rectangular', function () {
// given
var testCases = [
{
given: 'rectform(sqrt(34)*e^(i*atan(3/5)))',
expected: '3*i+5'
},
//PENDING:
//(-1)^(1/4)*sqrt(2)
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate().text('decimals');
// then
expect(value).toEqual(testCases[i].expected);
}
});
it('should convert from rectangular to polar', function () {
// given
var testCases = [
{
given: 'polarform(3*i+5)',
expected: 'e^(atan(3/5)*i)*sqrt(34)'
},
{
given: 'polarform(i-1)',
expected: '(i*sqrt(2)^(-1)+sqrt(2)^(-1))*sqrt(2)'
},
{
given: 'polarform(i+1)',
expected: 'e^(atan(1)*i)*sqrt(2)'
},
{
given: 'polarform(a*i+b*1)',
expected: 'e^(atan(a*b^(-1))*i)*sqrt(a^2+b^2)'
},
{
given: 'polarform(3)',
expected: '3'
},
{
given: 'polarform(i)',
expected: 'i'
},
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.toString();
// then
expect(value).toEqual(testCases[i].expected);
}
});
it('should compute powers', function () {
// given
var testCases = [
{
given: '0^(1/2)',
expected: '0',
expectedValue: '0'
},
{
given: '2^(1/2)',
expected: 'sqrt(2)',
expectedValue: '1.4142135623730951'
},
{
given: '3/4/-5/7',
expected: '-3/140',
expectedValue: '-0.02142857142857143'
},
{
given: '(2/5)^(1/2)',
expected: 'sqrt(2)*sqrt(5)^(-1)',
expectedValue: '0.6324555320336757'
},
{
given: '2^(1/2)+sqrt(2)',
expected: '2*sqrt(2)',
expectedValue: '2.8284271247461903'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate(values).text('decimals');
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
expect(round(value), 14).toEqual(round(testCases[i].expectedValue) ,14);
}
});
it('should handle large exponents', function() {
expect(nerdamer("((0.06/3650))^(365)").toString()).toEqual('1410126170338158616048224728371571380367482072097134683678107761'+
'52508851857709566371341862240808591002757985609412198322971415396168976254349069'+
'9072942506404339112922628405843/22958690276909851695578696288325771692413979062611'+
'991343897836236337139161946070457727457304403772796893304635803331160164612018173513'+
'31134891165302696107379996154818718135122744754040421370203240041207474864695474953483'+
'0902803016857824896441156744745927014013655670039876606817604403974679132586661890547851'+
'679296531769750182377028054935351721036749094036432130424970214049875323757624442119121774'+
'055322139084444881193088085062373618050647934648517067336395372063877340185058649456212635239'+
'066781525382959311599987961299501210179615619443916881386730704082805297329446411862362398493471'+
'826680176950800344487654991092708947796616392537184126525313140738179830882678244141981560034679553'+
'975783364407913480224860273677558689624530555494789243375386735721249700734052057353034685422151396642'+
'918026922556798918041766876185384884777704756416389503981017717926985777672007862927270802670740330468020'+
'802233942408161027975787463864142754167881620056649731281986417206144622511945116440478852141832742043753412'+
'722079707428689254358366463206869962206219178342509475906640460010907598207195708896768921596249362559252745779'+
'251530796907715219008462775395896084216357246887696419435087591409683227539062500000000000000000000000000000000000'+
'000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'+
'000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'+
'000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'+
'000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'+
'000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'+
'00000000000000000000000000000000000000000000000000000000000000000000000000000000'
);
expect(nerdamer("1000*(1+(0.06/365))^(365*3)").evaluate().text()).toEqual('1197.199652936753887236');
});
it('should compute factorials', function () {
// given
var testCases = [
{
given: '(1+x^2)!',
expected: 'factorial(1+x^2)',
expectedValue: '245.1516183677083'
},
{
given: '10!',
expected: 'factorial(10)',
expectedValue: '3628800'
},
{
given: 'x!',
expected: 'factorial(x)',
expectedValue: '2.197620278392476'
},
{
given: 'x!*x!',
expected: 'factorial(x)^2',
expectedValue: '4.829534888001823'
},
{
given: '3*(1+x!*x!)',
expected: '3*(1+factorial(x)^2)',
expectedValue: '17.488604664005468'
},
{
given: '3*(1+x!*x!)!',
expected: '3*factorial(1+factorial(x)^2)',
expectedValue: '1573.2041488172601'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate(values).text('decimals');
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
expect(round(value), 14).toEqual(round(testCases[i].expectedValue) ,14);
}
});
it('should compute symbolic factorials', function () {
// given
var testCases = [
{
given: '(-1/2)!',
expected: 'sqrt(pi)'
},
{
given: '(-7/2)!',
expected: '(-8/15)*sqrt(pi)'
},
{
given: '(-9/2)!',
expected: '(16/105)*sqrt(pi)'
},
{
given: '(9/2)!',
expected: '(945/32)*sqrt(pi)'
},
{
given: '(7/2)!',
expected: '(105/16)*sqrt(pi)'
},
{
given: '(1/2)!',
expected: '(1/2)*sqrt(pi)'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
}
});
it('should handle square roots', function () {
// given
var testCases = [
{
given: 'sqrt(1+x)^(4*x)',
expected: '(1+x)^(2*x)',
expectedValue: '115.80281433592612'
},
{
given: 'sqrt(2*sqrt(5))',
expected: '5^(1/4)*sqrt(2)',
expectedValue: '2.114742526881128'
},
{
given: 'sqrt(2)*sqrt(2)',
expected: '2',
expectedValue: '2'
},
{
given: 'sqrt(1/2)',
expected: 'sqrt(2)^(-1)',
expectedValue: '0.7071067811865475'
},
{
given: 'sqrt(2)^2',
expected: '2',
expectedValue: '2'
},
{
given: '6*sqrt(2)^4',
expected: '24',
expectedValue: '24'
},
{
given: 'sqrt(x^2)*sqrt(x^4)',
expected: 'abs(x)*x^2',
expectedValue: '9.261'
},
{
given: 'sqrt((5/2)*x^10)',
expected: 'abs(x)*sqrt(2)^(-1)*sqrt(5)*x^4',
expectedValue: '64.5753067708567'
},
{
given: '(sqrt((5/2)*x^10))*-sqrt(2)',
expected: '-abs(x)*sqrt(5)*x^4',
expectedValue: '-91.3232746297487'
},
{
given: 'sqrt(9)',
expected: '3',
expectedValue: '3'
},
{
given: 'sqrt(-9)',
expected: '3*i',
expectedValue: '3*i'
},
{
given: 'sqrt(a/x)',
expected: 'sqrt(a)*sqrt(x)^(-1)',
expectedValue: '1.879716290649558'
},
{
given: 'sqrt(-x)',
expected: 'sqrt(-x)',
expectedValue: '1.4491376746189437*i'
},
{
given: 'sqrt(-x)*sqrt(-x)',
expected: '-x',
expectedValue: '-2.1'
},
{
given: 'sqrt(-x)*sqrt(-x)+4*x',
expected: '3*x',
expectedValue: '6.3'
},
{
given: 'sqrt((1/2*x)^(1/2))',
expected: '2^(-1/4)*x^(1/4)',
expectedValue: '1.0122722344290394'
},
{
given: 'sqrt(4*sqrt(2)^(-1)*x^(1/2))',
expected: '2^(3/4)*x^(1/4)',
expectedValue: '2.0245444688580787'
},
{
given: 'sqrt(4+x)',
expected: 'sqrt(4+x)',
expectedValue: '2.4698178070456938'
},
{
given: '(1/2)*x^(1/2)+sqrt(x)',
expected: '(3/2)*sqrt(x)',
expectedValue: '2.173706511928416'
},
{
given: 'sqrt((4+x)^2)',
expected: 'abs(4+x)',
expectedValue: '6.1'
},
{
given: '2*sqrt(3/4)',
expected: 'sqrt(3)',
expectedValue: '1.7320508075688772'
},
{
given: 'sqrt(2)*sqrt(8)',
expected: '4',
expectedValue: '4'
},
{
given: 'sqrt(242)',
expected: '11*sqrt(2)',
expectedValue: '15.556349186104047'
},
{
given: 'sqrt(4)^-1',
expected: '1/2',
expectedValue: '0.5'
},
{
given: 'sqrt(4*x^2)',
expected: '2*abs(x)',
expectedValue: '4.2'
},
{
given: '74689676.31109099*sqrt(5578547747455547)',
expected: '(824947474856/11045)*sqrt(5578547747455547)',
expectedValue: '5578547747455547'
},
{
given: 'sqrt(2/x)',
expected: 'sqrt(2)*sqrt(x)^(-1)',
expectedValue: '0.9759000729485331'
},
{
given: 'sqrt(3^x)',
expected: 'sqrt(3^x)',
expectedValue: '3.169401925649'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate(values).text('decimals');
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
expect(round(value, 12)).toEqual(round(testCases[i].expectedValue ,12));
}
});
it('should simplify square roots', function() {
expect(nerdamer('sqrt(128/49)').toString()).toEqual('(8/7)*sqrt(2)');
expect(nerdamer('sqrt(2)-2/(sqrt(2))').toString()).toEqual('0');
expect(nerdamer('expand((sqrt(7)+3sqrt(2))(sqrt(7)-3sqrt(2)))').toString()).toEqual('-11');
expect(nerdamer('3sqrt(2)*2sqrt(6)').toString()).toEqual('12*sqrt(3)');
});
it('should handle square roots of negative values', function() {
expect(nerdamer('sqrt(-x)').evaluate().text()).toEqual('sqrt(-x)');
expect(nerdamer('sqrt(-0.5*x)').evaluate().text()).toEqual('0.7071067811865475*sqrt(-x)');
expect(nerdamer('sqrt(-4)').evaluate().text()).toEqual('2*i');
expect(nerdamer('sqrt(-pi)').evaluate().text()).toEqual('1.7724538509055163*i');
});
it('should expand square roots', function () {
// given
var testCases = [
{
given: '(sqrt(7)+3sqrt(2))*(sqrt(7)-3sqrt(2))',
expected: '-11'
},
{
given: 'sqrt(33)*sqrt(11)',
expected: '11*sqrt(3)'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given).expand();
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
}
});
it('should correctly test for squareness', function() {
expect(nerdamer('16x^2*y^2').symbol.isSquare()).toBe(true);
expect(nerdamer('16x^2*y^2-1').symbol.isSquare()).toBe(false);
expect(nerdamer('9').symbol.isSquare()).toBe(true);
expect(nerdamer('(5+x)^6').symbol.isSquare()).toBe(true);
expect(nerdamer('(x+y)^2').symbol.isSquare()).toBe(true);
expect(nerdamer('9^(1/4)').symbol.isSquare()).toBe(false);
expect(nerdamer('x^(1/2)').symbol.isSquare()).toBe(false);
});
it('should correctly test for cubeness', function() {
expect(nerdamer('64x^3*y^3').symbol.isCube()).toBe(true);
expect(nerdamer('64x^3*y^3-1').symbol.isCube()).toBe(false);
expect(nerdamer('7').symbol.isCube()).toBe(false);
expect(nerdamer('27').symbol.isCube()).toBe(true);
expect(nerdamer('(5+x)^6').symbol.isCube()).toBe(true);
expect(nerdamer('(x+y)^2').symbol.isCube()).toBe(false);
expect(nerdamer('9^(1/4)').symbol.isCube()).toBe(false);
expect(nerdamer('x^(1/2)').symbol.isCube()).toBe(false);
expect(nerdamer('216*z^6').symbol.isCube()).toBe(true);
});
it('should support the imaginary number i', function () {
// given
var testCases = [
{
given: 'i*i',
expected: '-1',
expectedValue: '-1'
},
{
given: 'i*8*i',
expected: '-8',
expectedValue: '-8'
},
{
given: 'i^(2/3)',
expected: '-1',
expectedValue: '-1'
},
{
given: '(256*i)^(1/8)',
expected: '2*(-1)^(1/16)',
expectedValue: '0.39018064403225655*i+1.9615705608064609'
},
{
given: 'i/i',
expected: '1',
expectedValue: '1'
},
{
given: '(1/i)*i',
expected: '1',
expectedValue: '1'
},
{
given: 'i^(-1)',
expected: '-i',
expectedValue: '-i'
},
{
given: 'i^(2)',
expected: '-1',
expectedValue: '-1'
},
{
given: 'i^(-2)',
expected: '-1',
expectedValue: '-1'
},
{
given: 'i^(-1)',
expected: '-i',
expectedValue: '-i'
},
// Euler's identity
{
given: 'e^(i*pi)+e^(2*i*pi)',
expected: '0',
expectedValue: '0'
},
{
given: 'exp(i + x pi)',
expected: 'e^(i+pi*x)',
expectedValue: '396.1203590827245535+616.9209071285088*i'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate(values).text('decimals', 17);
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
expect(value).toEqual(testCases[i].expectedValue);
}
});
it('should handle powers with results using i', function () {
// given
var testCases = [
{
given: '(-2/3*x)^x',
expected: '(-x)^x*2^x*3^(-x)',
//TODO: Evaluates to NaN somewhere
expectedValue: '2.0270706004935852*(-1)^2.1'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate(values).text('decimals');
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
expect(value).toEqual(testCases[i].expectedValue);
}
});
it('should compute logarithms correctly', function () {
// given
var testCases = [
{
given: 'log(e)',
expected: '1',
expectedValue: '1'
},
{
given: 'log(e^e)',
expected: 'e',
expectedValue: '2.718281828459045'
},
{
given: 'log(1/e^e)',
expected: '-e',
expectedValue: '-2.718281828459045'
},
{
given: 'log(1/sqrt(2))',
expected: '(-1/2)*log(2)',
expectedValue: '-0.34657359027997'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate().text('decimals');
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
expect(round(value, 14)).toEqual(round(testCases[i].expectedValue), 14);
}
});
it('should check for equality', function () {
var a, b, c, d, e, f, g;
a = nerdamer("2sqrt(5)");
b = nerdamer("2sqrt(5)");
c = nerdamer("sqrt(13)");
d = nerdamer("sqrt(21)");
e = nerdamer("sqrt(20)");
f = nerdamer("sqrt(5) + sqrt(3)");
g = nerdamer("sqrt(5) + sqrt(7)");
expect(a.lt(g)).toBe(true);
expect(a.lt(f)).toBe(false);
expect(a.gt(c)).toBe(true);
expect(a.gt(d)).toBe(false);
expect(a.gt(e)).toBe(false);
expect(a.lt(e)).toBe(false);
expect(a.eq(e)).toBe(true);
expect(b.gte(a)).toBe(true);
expect(c.gte(a)).toBe(false);
expect(e.lte(d)).toBe(true);
expect(f.lte(g)).toBe(true);
});
/** Based on commit cf8c0f8. */
it('should not cause infinite recursion', function () {
// given
var formula = '1/(1+x)+(1+x)';
// when
var parsed = nerdamer(formula);
var result = parsed.evaluate().toString();
// then
expect(result).toBe('(1+x)^(-1)+1+x');
});
it('should support ceil and floor', function () {
// given
var testCases = [
{
given: 'floor(204)',
expected: '204'
},
{
given: 'floor(10.893)',
expected: '10'
},
{
given: 'floor(-10.3)',
expected: '-11'
},
{
given: 'ceil(204)',
expected: '204'
},
{
given: 'ceil(10.893)',
expected: '11'
},
{
given: 'ceil(-10.9)',
expected: '-10'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate().text('decimals');
// then
expect(value).toEqual(testCases[i].expected);
}
});
it('should round', function () {
// given
var testCases = [
{
given: 'round(204)',
expected: '204'
},
{
given: 'round(10.893)',
expected: '11'
},
{
given: 'round(10.893, 1)',
expected: '10.9'
},
{
given: 'round(-10.3)',
expected: '-10'
},
{
given: 'round(204)',
expected: '204'
},
{
given: 'round(10.1)',
expected: '10'
},
{
given: 'round(1.23423534e-12,-2)',
expected: '0.00000000000123'
},
{
given: 'round(1.23423534e12,-2)',
expected: '1230000000000'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate().text('decimals');
// then
expect(value).toEqual(testCases[i].expected);
}
});
it('should support trunc()', function () {
// given
var testCases = [
{
given: 'trunc(0)',
expected: '0'
},
{
given: 'trunc(10.234)',
expected: '10'
},
{
given: 'trunc(-9.99)',
expected: '-9'
},
{
given: 'trunc(0.99)',
expected: '0'
},
{
given: 'trunc(-0.7555)',
expected: '0'
},
{
given: 'trunc(8.9 * -4.9)',
expected: '-43'
},
{
given: 'trunc(8.9) * trunc(-4.9)',
expected: '-32'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate().text('decimals');
// then
expect(value).toEqual(testCases[i].expected);
}
});
it('should support continued fractions', function () {
// given
var testCases = [
{
given: 'continued_fraction(2.145474, 11)',
expected: '[1,2,[6,1,6,1,16,8,2,1,3,2]]'
},
{
given: 'continued_fraction(-6/7)',
expected: '[-1,0,[1,6]]'
},
{
given: 'continued_fraction(sqrt(2), 5)',
expected: '[1,1,[2,2,2,2,2]]'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
// then
expect(parsed.toString()).toEqual(testCases[i].expected);
}
});
/** #35 #76: Support multiple minus signs and brackets */
it('should support prefix operator with parantheses', function () {
// given
var testCases = [
{
given: '(a+x)--(x+a)',
expected: '2*a+2*x'
},
{
given: '(3)---(3)',
expected: '0'
},
{
given: '-(1)--(1-1--1)',
expected: '0'
},
{
given: '-(-(1))-(--1)',
expected: '0'
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var parsed = nerdamer(testCases[i].given);
var value = parsed.evaluate().text('decimals');
// then
expect(value).toEqual(testCases[i].expected);
}
});
//#78
it('should substitute variables', function () {
// given
var testCases = [
{
given: '2*(x+1)^2',
sub: 'x+1',
sub_with: 'u',
expected: '2*u^2'
},
{
given: '2*(x+1+a)^2',
sub: 'x+1',
sub_with: 'u',
expected: '2*(1+a+x)^2'
},
{
given: '2*(x+1)^(x+1)',
sub: 'x+1',
sub_with: 'u',
expected: '2*u^u'
},
{
given: '2*(x+1)^2',
sub: '(x+1)^2',
sub_with: 'u^x',
expected: '2*u^x'
},
{
given: '2*(x+1)^2',
sub: 'x+1',
sub_with: 'u^x',
expected: '2*u^(2*x)'
},
{
given: '(2*(x+1)^2+a)^2',
sub: '(x+1)^2',
sub_with: 'u^x',
expected: '(2*u^x+a)^2'
},
{
given: '(x^x+y)^(x^x-t)',
sub: 'x^x',
sub_with: '4',
expected: '(4+y)^(-t+4)'
},
{
given: '(cos(x)+cos(x)^2)',
sub: 'cos(x)',
sub_with: '4',
expected: '20'
},
{
given: '(cos(x)+cos(x)^2)',
sub: '(cos(x)+cos(x)^2)',
sub_with: '4',
expected: '4'
},
{
given: '(cos(x)+cos(x^6)^2)',
sub: '(cos(x)+cos(x)^2)',
sub_with: '4',
expected: 'cos(x)+cos(x^6)^2'
},
{
given: '(cos(x)+cos(x^6)^2)',
sub: 'cos(x)',
sub_with: '4',
expected: '4+cos(x^6)^2'
},
{
given: '(cos(x)+cos(x^6)^2)',
sub: '2',
sub_with: '4',
expected: 'error'
}
];
for (var i = 0; i < testCases.length; ++i) {
var testCase = testCases[i];
var parsed;
// when
try {
parsed = nerdamer(testCase.given).sub(testCase.sub, testCase.sub_with).toString();
}
catch(e){
parsed = 'error';
}
// then
expect(parsed).toEqual(testCases[i].expected);
}
});
it('should ignore constants and special values', function() {
var core = nerdamer.getCore();
expect(nerdamer('e').variables()).toEqual([]);
expect(nerdamer('pi').variables()).toEqual([]);
expect(nerdamer(core.Settings.IMAGINARY).variables()).toEqual([]);
});
/** #44: a+b - (a+b) not evaluated as 0 */
it('should perform subtraction of terms', function () {
// given
var formula = 'a+b - (a+b)';
// when
var result = nerdamer(formula).toString();
// then
expect(result).toBe('0');
});
/** #46: (x^(1/2)*x^(1/3))-x^(5/6) should be 0 */
it('should result in 0', function () {
// given
var formula = '(x^(1/2)*x^(1/3))-x^(5/6)';
// when
var result = nerdamer(formula).toString();
// then
expect(result).toBe('0');
});
/** #47: (a^2)/(a*b) should be a/b */
it('should simplify correctly', function () {
// given
var formula = '(a^2)/(a*b)';
// when
var result = nerdamer(formula).toString();
// then
// TODO jiggzson: Result is correct but a/b would be simpler
expect(result).toBe('a*b^(-1)');
});
/** #56: x/sqrt(x) = x^(3/2) */
it('should calculate x/sqrt(x) correctly', function () {
// given
var formula = 'x/sqrt(x)';
// when
var result = nerdamer(formula).toString();
// then
expect(result).toBe('x^(1/2)');
});
/** #60: sin(x) looks like sin(abs(x)) */
it('should respect the sign of argument for sin(x)', function () {
// given
var halfSqrt2 = '0.7071067811865475'; // sqrt(2)/2
var halfSqrt3 = '0.8660254037844385'; // sqrt(3)/2
var testCases = [
{
given: '-pi',
expected: '0'
},
{
given: '-3/4*pi',
expected: '-' + halfSqrt2
},
{
given: '-2/3*pi',
expected: '-' + halfSqrt3
},
{
given: '-1/2*pi',
expected: '-1'
},
{
given: '-1/6*pi',
expected: '-0.5'
},
{
given: '0',
expected: '0'
},
{
given: '1/4*pi',
expected: halfSqrt2
},
{
given: '1/2*pi',
expected: '1'
},
{
given: '3/4*pi',
expected: halfSqrt2
},
{
given: 'pi',
expected: '0'
},
{
given: '3/2*pi',
expected: '-1'
},
{
given: '2*pi',
expected: '0'
},
{
given: '2.25 * pi',
expected: halfSqrt2
}
];
for (var i = 0; i < testCases.length; ++i) {
// when
var result = nerdamer('sin(' + testCases[i].given + ')').evaluate().text('decimals');
// then
expect(round(result, 14)).toEqual(round(testCases[i].expected),14);
}
});
it('should compute complex numbers', function() {
var testCases = [
//SYMBOLIC
{
given: 'cos(3*i+a)',
expected: 'cos(3*i+a)'
},
{
given: 'sin(3*i+a)',
expected: 'sin(3*i+a)'