jiggzson / nerdamer

a symbolic math expression evaluator for javascript
http://www.nerdamer.com
MIT License
517 stars 82 forks source link

InvalidVariableNameError on fractions with very large numbers #489

Closed nicola closed 5 years ago

nicola commented 5 years ago

Hello, I am trying to have the following:

nerdamer('a = 2^(-80)').evaluate().solveFor('a').toString()

same for this:

nerdamer('a = 1/2^(80)').solveFor('a').toString()

with error:

InvalidVariableNameError:  is not a valid variable name

However, this seems to hang my browser which is pretty unfortunate, since Math.pow(2, 80) works pretty quickly. This must be because it's trying to put the number into a fraction. How do I go around having this issue?

Thank you!

nicola commented 5 years ago

you can see the issue here: https://observablehq.com/d/25c3c65a9bd71f61

jiggzson commented 5 years ago

@nicola, the ideal solution to this issue would be to convert the Jenkins-Traub algorithm to no longer use JS numbers. Unfortunately this takes a little time so the work around for the time being is to use round to limit the rounding errors and to establish a good base to work from. I am howerver a little perplexed that your browser hangs since fraction conversion is fairly fast. Usually less than 20 iterations.

One way to fix this issue would be to no longer round and let the rounding error propagate which should have a negligible impact on almost all solutions except for integrate. Not including this rounding forces me to throw out way too many good results because of the uncertainty it creates.

Just as in #463, you could change these lines in Algebra.js from

var img = round( zeroi[i], decp+8 ),
      real = round( zeror[i], decp );

to

var img = zeroi[i],
      real = zeror[i];

this might be an acceptable solution in your case until I can make the proper conversion if you're not really using integrate and maybe 'partfrac`. It might still be an acceptable solution if you are depending on whether your integration includes partial fractions.

Let me know if this at least somewhat partially addresses your issue.

Thanks.

nicola commented 5 years ago

@jiggzson can you give me a one liner on how to make this one work? I am not sure how I would do the change you are proposing

nerdamer('a = 1/2^(80)').solveFor('a').toString()
nicola commented 5 years ago

a simple trick for me is:

nerdamer('a = 1/2^(80)').toString().split('=')[1]

but I would like to avoid that

nicola commented 5 years ago

also, I am not interested in turning symbols in fractions, if there is a way to turn it off, I think it would help a lot

jiggzson commented 5 years ago

Use this branch and let me know if this issue goes away https://github.com/jiggzson/nerdamer/tree/Jenkins-Traub-conversion.

also, I am not interested in turning symbols in fractions, if there is a way to turn it off, I think it would help a lot

You can't really turn it off since that's how it works internally but you could use the text method instead of toString and set PARSE2NUMBER to true. In your case for example.

nerdamer.set('PARSE2NUMBER', true);
//only symbols have the text method and since solveFor returns an array, you have to 
//first select which result
var e = nerdamer('a = 1/2^(80)').solveFor('a')[0].text();
console.log(e);
nicola commented 5 years ago

I was thinking:

Why does this work:

nerdamer('a = 1/2^(80)').toString().split('=')[1]

and this not?

nerdamer('a = 1/2^(80)').solveFor('a').toString()

will try what you requested soon

nicola commented 5 years ago

The fork works: https://observablehq.com/d/9b89ba7da26dbb36