josdejong / mathjs

An extensive math library for JavaScript and Node.js
https://mathjs.org
Apache License 2.0
14.44k stars 1.24k forks source link

Issue with "Convert a number with >15 significant digits to BigNumber" #482

Closed sonnyk22 closed 9 years ago

sonnyk22 commented 9 years ago

I am using the code below:

mathjs.config({ number: 'bignumber', precision: 64 }); var expression = 'cos(5)+0.28366218546'; var result = mathjs.eval(expression);

MathJS returns this exception:

Cannot implicitly convert a number with >15 significant digits to BigNumber (value: 0.28366218546322625). Use function bignumber(x) to convert to BigNumber.

How can I overcome this?

josdejong commented 9 years ago

The error does not occur with the code example you give, I don't know how you got this error message thrown. Anyway, it happens when you have a number with more than 15 digits, which needs to be converted to BigNumber, like:

// use math.js with default config
math.eval('cos(5) + bignumber(2)'); // throws error

The left part of the addition is a number 0.28366218546322625, right part is a BigNumber 2.

Because the left part is rounded to ~15 digits and has a know limited precision, math.js forces you to be explicit about this conversion from a rounded low precision to high precision, else you can accidentally think that you calculation was executed fully at high precision.

The error message tries to tell you what to do:

Cannot implicitly convert a number with >15 significant digits to BigNumber (value: 0.28366218546322625). Use function bignumber(x) to convert to BigNumber.

So:

math.eval('bignumber(cos(5)) + bignumber(2)'); // ok

EDIT: it would be best of course to prevent mixing low precision, rounded numbers with high precision bignumbers, and do everything at high precision. That's what the error tries to warn you for.

sonnyk22 commented 9 years ago

Thanks for the feedback. Is there a MathJS configuration that it will force to calculate the expression of 'cos(5)+0.28366218546' without me applying the JS string parsing/concatenation to make it 'bignumber(cos(5)) + bignumber(0.28366218546)'?

josdejong commented 9 years ago

If you do the following (your original code example!), there will be no errors. All values will be parsed as BigNumbers by the parser, no conversions from number to BigNumber.

math.config({ number: 'bignumber', precision: 64 });
var expression = 'cos(5)+0.28366218546';
var result = math.eval(expression);
sonnyk22 commented 9 years ago

I agree its very strange; its exactly the same code that I am using, but its throwing an error.

Also, let me show you the Config() returned object for my mathjs.config(): Object {epsilon: 1e-14, matrix: "matrix", number: "bignumber", precision: 64, predictable: false}

Could any of the above properties cause the error to be thrown?

josdejong commented 9 years ago

Hmm. Are you using the latest version of math.js?

sonnyk22 commented 9 years ago

I am using a fairly new version:

Also, I am using the MathJS lib in a SPA application that I am developing in AngularJS 1.3.5 which is almost a year old. I am not sure if this "could" have anything to do with this issue; I doubt it, but anything could be the root cause for this on my side. I am planning on upgrading to AngularJS version 1.4.7 tomorrow; not sure if this will resolve it.

josdejong commented 9 years ago

hm, how can we pinpoint this error? Could you manage to create a minimal jsbin/jsfiddle where this error occurs?

I created a small angular.js fiddle which outputs an evaluation with mathjs, that works fine: http://jsfiddle.net/dx9801gc/2/.

Just for completeness: what browser and operating system are you using?

EDIT: updated the jsfiddle url, it was not pointing to the latest version.

sonnyk22 commented 9 years ago

Thank you.

After commenting the mathjs.config({ number: 'bignumber', precision: 64 }) line from my code, everything started working great.

josdejong commented 9 years ago

you mean if you're not using BigNumbers then everything works fine? Well, if that works for you it's ok of course, if you don't need high precision calculations at all. I suppose though that you wanted to use bignumbers for a reason?

Snorvarg commented 7 years ago

Hi, I have made a modified version of the jsfiddle, showing a similar/same problem I have: http://jsfiddle.net/dx9801gc/3/

In short:

var variables = {"a": "899", "b": "7"};
var expression = 'a/b+a/2';
math.eval(expression, variables);

This code throws an exception "Unexpected type of argument in function divide (expected: Array or Matrix, actual: BigNumber, index: 1)"

If I change the expression into var expression = 'a/b'; it works.

What is wrong?

josdejong commented 7 years ago

That's an interesting case @Snorvarg , the underlying issue is that math.js doesn't know how to divide a string and a BigNumber. As a workaround you could first convert your variables a and b to a number or BigNumber and then put them in math.eval.

I've created a separate topic for this issue: #789