UNPKG

nerdamer

Version:

javascript light-weight symbolic math expression evaluator

1,564 lines (1,495 loc) 99.4 kB
/* 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)'