0

I am trying out mXparser in an android app and I almost have it working. But, if I parse the following expression "10/3" then it returns: 3.33333333335. Why this rounding in the end? and how do I tell mXparser to return 3.33333333333 instead?

I am writing the app using kotlin and has added mXparser through Maven.

Alternatively, do you know of a better/more used/more maintained math parser library for Android?

7heViking
  • 7,137
  • 11
  • 50
  • 94

2 Answers2

2

The reason is that computers calculate in base 2, not base 10. The number 10/3 has an infinite expansion in both base 2 and base 10 meaning it must be truncated. The decimal expansion of 10/3 is 3.333..., which when you cut it off simplifies to a bunch of 3's; while the binary expansion is 11.010101010101... and when you cut it off and convert back to decimal, it's totally believable that you could get the 5 at the end. I'm not sure you can get around that when using a computer since computers have to use binary and they also have to truncate the binary expansion.

Philip Egger
  • 326
  • 1
  • 11
  • Okay, that sound correct. However, there must be a solution as calculators of all kinds had been dealing with this problem for very long. Do you have any idea. Also, if I try it out on wolframalpha it returns the expected result: https://www.wolframalpha.com/input/?i=10%2F3 – 7heViking Jan 28 '20 at 12:00
  • I suspect that the way to get around that is to use higher machine precision, so that fewer bits are truncated from the end and thus the machine error will more likely be beyond the reach of the decimal truncation. – Philip Egger Jan 28 '20 at 12:27
  • Yes, there is a solution. Calculators simply make a rounding for the fixed precision. mXparser gives you the option to work on very big or very small. Calculators usually have fixed number of places. Wolfram is a different animal - this is a computer algebra system. Anyway - round the final result to the fixed number of places and you have the same as calculators are doing. – Leroy Kegan Feb 04 '20 at 23:06
1

Any system based around IEEE 754 double precision will give the same answer. That includes all major programming languages. This is a very frequent SO question. See for example Is floating point math broken?

The solution is to never use the default Double.toString() method for your output. Use and output with specific number of decimal places and the problem goes away.

A more complex solution is to use a ration representation of your numbers, so the result of 10/3 is stored internally as a rational number {numerator:10,denominator:3}. This works for basic arithmetic but can't work with function like cos(x) or sqrt(x). The Jep parsing evaluation library does have options to allow ration number. (disclaimer I'm one of the authors of Jep).

Salix alba
  • 7,536
  • 2
  • 32
  • 38
  • Just of curiosity: I don't see android listed on the java version page. Does Jep work on android and how well? – 7heViking Feb 03 '20 at 11:48
  • I've done a brief test app with android using it, which worked without problem. The library does not use any exotic code so should port easily to android but its not fully tested. – Salix alba Feb 03 '20 at 12:59
  • Okay, then just a quick answer: Why should I choose Jep instead of a free tool like mXparser? – 7heViking Feb 03 '20 at 14:29
  • This is probably not the best forum for discussing this I'm happy to answer in more details at rich@singsurf.org. In brief Jep is a more mature product, it more extensible which allows every part to be changed from the set of operators used to changing the evaluator used. – Salix alba Feb 03 '20 at 15:38
  • I am fairly sure that Jep's math library is poor compared to the mXparser's one. mXParser is very flexible, you can add your own functions, own arguments, user defined recursion and much more. Additionally mXparser has few hundreds of built-in math elements. – Leroy Kegan Feb 04 '20 at 23:04