ParserNG should use `BigDecimal` instead of `double`
Test code
class MathTest {
@Test
fun testMathExpression() {
println(MathExpression("239081204214*1247981247912749").solve())
}
}
Expect
298368859587470504923124286
Result
298368859587470500000000000
The parserng works by default in doubles. What you see is max precision double can get:
jshell> double a = 239081204214d
a ==> 2.39081204214E11
jshell> double b=1247981247912749d
b ==> 1.247981247912749E15
jshell> a*b
$3 ==> 2.983688595874705E26
What you see would be achieved moving whole parserng to bigdecimal:
jshell> BigInteger ba = new BigInteger("239081204214");
ba ==> 239081204214
jshell> BigInteger bb = new BigInteger("1247981247912749");
bb ==> 1247981247912749
jshell> BigInteger bc =ba.multiply(bb)
bc ==> 298368859587470504923124286
and big decimal
jshell> BigDecimal ba = new BigDecimal("239081204214");
ba ==> 239081204214
jshell> BigDecimal bb = new BigDecimal("1247981247912749");
bb ==> 1247981247912749
jshell> ba.multiply(bb)
$3 ==> 298368859587470504923124286
Where the cost performance will be notable, I would vote for moveing parserng from double to BigInteger. Still it is very huge step.
I would probably recommend to change subject of this issue: "parserng shoud use bigdecimal instead of doubles" , but still, I think its not going to be solved anytime soon.
btw, future 0.1.9 (pom is not yet bumped) have sum and gsum rewritten to biginteger:
java -jar target/parser-ng-0.1.8.jar "gsum(239081204214,1247981247912749)"
298368859587470504923124286
(prod is still in double):
java -jar target/parser-ng-0.1.8.jar "prod(239081204214,1247981247912749)"
2.983688595874705E26
So gsum/summ can help you to workaroudn this problem.. somehow...
I hope to draft readme.md changes for 0.1.9 during this week, so @gbenroscience could release.
The parserng works by default in doubles. What you see is max precission double can get:
jshell> double a = 239081204214d a ==> 2.39081204214E11 jshell> double b=1247981247912749d b ==> 1.247981247912749E15 jshell> a*b $3 ==> 2.983688595874705E26What you see would be achieved moving whole parserng to bigdecimal:
jshell> BigInteger ba = new BigInteger("239081204214"); ba ==> 239081204214 jshell> BigInteger bb = new BigInteger("1247981247912749"); bb ==> 1247981247912749 jshell> BigInteger bc =ba.multiply(bb) bc ==> 298368859587470504923124286Where the cost performance will be notable, I would vote for moveing parserng from double to BigInteger. Still it is very huge step.
https://github.com/ezylang/EvalEx-big-math
How about delegating BigDecimal operations to other extension libraries? (e.g. EvalEx <-> EvalEx-big-math)
https://github.com/ezylang/EvalEx-big-math
How about delegating
BigDecimaloperations to other extension libraries? (e.g.EvalEx <-> EvalEx-big-math)
Well there is plenty of math libraries, each with its pros and cons. Some ar fast, some ar not, some have some functins, some dont, some are double, some are bigdecimal.... I like pareserng for its strightforward approach and easy extendability. To have math library(parserng) calling another math library (evalex-bigmath) would be very weird step.
Thanx for fixing me to BigDecimal. My typo. Had BigDecimal in mind.
ezylang/EvalEx-big-math How about delegating
BigDecimaloperations to other extension libraries? (e.g.EvalEx <-> EvalEx-big-math)Well there is plenty of math libraries, each with its pros and cons. Some ar fast, some ar not, some have some functins, some dont, some are double, some are bigdecimal.... I like pareserng for its strightforward approach and easy extendability. To have math library(parserng) calling another math library (evalex-bigmath) would be very weird step.
What I'm saying is that there are cases like EvalEx-big-math. I'm not saying that ParserNG should include EvalEx-big-math.
Hello @JellyBrick , thanks for using ParserNG!
Thanks @judovana for responding.
@JellyBrick , BigDecimal computations would definitely slow down the parser and this is why we use double precision instead!
However, we can define a limited BigMathExpression class that handles no functions, just algebraic expressions.
This would bring limited support of your functionality to ParserNG.
Many important classes are based on MathExpression and we don't want something like this to break something higher up in the chain.
With time, then we can contribute functions that efficiently and accurately compute the trig functions, the log functions etc in BigDecimal format.
Once this is achieved, we can then allow BigMathExpression support functions also.
What do you think, @judovana and @JellyBrick ?
Actually, there is a class PolynomialExpression that does this already, buried somewhere in the heart of ParserNG. It is used mainly by numerical methods for integral calculus and some other functionality, I think, in the parser.
If you are cool with it, we can base this functionality on it and move ahead.
Can you provide examples of PolynomialExpression please?
The BigMathExpression is interesting idea. Maybe MathExpression can have as parameter factory method, which will be responsible for sting->number convertions? like T toNumber(String) which in MathExpression will return Double, and otherwise BigDecimal. The mian issue here is the Double x double. In all cases this will get rid of primitives, whcih you do not want I guess. Still having BigDecimal at elast semi optional, sounds exceptionally god.
Before actuallys tarting anything, would be nice to have performance comparsion double x Double x BigDecimal. Maybe the difference will bs super trivial.
PolynomialExpression
So sorry. I took a look at PolynomialExpression and its not what I had in mind that it does. Its quite old code but it contains a lot of things that can be reused in an hypothetical BigMathExpression class.
Before actually starting anything, would be nice to have performance comparison double x Double x BigDecimal. Maybe the difference will be super trivial.
Did some research online though, it seems the general consensus is that BigDecimal would be much slower versus primitives. One such article is this
I have bigger concerns about double x Double. Which is killing the idea of generic MathExpression. Still worthy to investigate in future. I personally would like to see whole ParserNG on BigDecimal. But that would be tremendous work with sporadic result. generic MathExpression would be incredible solution. It would allow also predictable default length of fractional part of number.
Considering the fact that I pray God that a time would come when I would have enough time on my hands to do a speed optimized refactor of ParserNG, moving all of ParserNG to BigDecimal is definitely not attractive to me. But I do not mind having robust BigDecimal support via inheritance(extension...e.g BigMathExpression, preferable) or via setting modes(e.g. DOUBLE or BIGDECIMAL) on the MathExpression class(not so attractive).
I have bigger concerns about
doublexDouble.
Double would benchmark slower than double also; that is the popular opinion since Double is an object. But you could run some tests to convince us of this.
Yup. Sure. Crossing fingers for you, and agreeing on double x Double.
Hi @judovana and @JellyBrick, here is PR #32