Large decimal number strings lose precision when converted to a number format
Description
Environment
Attachments
relates to
Activity
Pothys - MitrahSoft 5 October 2021 at 11:58Edited
Michael Offner 17 September 2021 at 14:19
your example has nothing to do with the json functions
I’m not sure what you mean by that. My first example demonstrates the issue with de-serialization - specifically the loss of type once 11 decimal places is reached. The second example demonstrates the native handling as you switch from 10 to 11 decimal places. This was a known issue and, as noted above, we can probably work around that with explicit casting to ensure the outbound payload is accurate.
Problem is the lost of information happen BEFORE the json function is even called, as you can see in my code example, it is already 20 and 74 in the dump of the struct. The information in this examples already get lost in the compiler, when the compiler creates the literal number
Take this example
when look at the generated java code from this
you can see the number already is ConstantsDouble._12
in the bytecode, so everything that follows does not matter anymore.
BTW
With the new version that now looks as follows
so this Caster.toDouble(11.9999999999999)
has no rounding anymore.
So in short all code following a literal number does not matter and does not reflect your issue.
Jon Clausen 17 September 2021 at 13:54
Thanks for the literal number clarification, when attempting to cast the big decimal.
As I said, we can change our code for the outbound, to workaround this limitation in the engine. Maintaining precision in the deserialization of JSON is now our blocker. Both of those stories have been rejected ( linked to this story ), however.
I will pull down the latest version of Lucee, since tryCF
doesn’t have that and see what differences I see. Expect a report back by the EOD or Monday AM at the latest.
Michael Offner 17 September 2021 at 13:43
Let me address this first “as an end-user and developer that I’m still not understanding in the push-back from you on this story“.
I really try to help here, as you can see in the Lucee “6.0“ branch, i have completely rewritten number handling in Lucee 6 (4 days of work). I also have made changes to Lucee 5.3 today, based on your input and this ticket is in QA now, waiting for your input. i spend a LOT of time trying to explain what is going on, by taking all assumption out by backing everything i say with examples.
I try to get as much info as possible out of you, because your description did not match your code so far, if you see that as negative, i’m sorry. My goal is to help and solve the issue for you, as i said before, we cannot apply the change from Lucee 6 to 5, so we need a more specific approach and for that i need to completely understand what is going wrong. Best always is a 1 to 1 example that shows the problem and reduce assumptions to a absolute minimum.
Your example ALWAYS (also the last one) have literal numbers (a literal number is a number defined literally in the code), we know we have a limitation there (and i have addressed that limitation in the latest build), but i’m sure your problem is NOT with literal numbers, because you loads this number from a datasource, as you clarified in the last comment.
Also your last example uses literal numbers again
queryAddRow( qTest, [ createUUID(), bigDecimal.init( 19.9999999999999 ), bigDecimal.init( 73.9999999999999 ) ] );
but it should be
queryAddRow( qTest, [ createUUID(), bigDecimal.init( "19.9999999999999" ), bigDecimal.init( "73.9999999999999" ) ] );
then it works as you expect
Your example creates a literal number (double) and then passes that number to BigDecimal, that makes the BigDecimal useless, because you loose already the precision BEFORE you pass it in to BigDecimal
With the new Lucee 5.3 build i changed 2 things:
literal numbers now get now not rounded at all as long they stay numbers (same rule still apply for to string conversion)
i changed the rounding rules for the json (and WDDX,XML) converter, so it allows more digits (#.###############)
But i still think there is the option for a change in your code, that will solve the issue, without a Lucee version update necessary.
Jon Clausen 17 September 2021 at 13:05
There is one thing that, as an end-user and developer that I’m still not understanding in the push-back from you on this story:
I fully understanding java casting and why the numbers are being rounded, at the current time, when the right-hand assignment contains 11 decimal places.
What I don’t understand is why a workaround in 5.3.x can’t be implemented so that, if the right hand assignment is a decimal, and is greater than 10 places, why Lucee can’t auto-cast that as a BigDecimal. You have mentioned that this might be a regression, but I highly doubt there are downstream users who want their precision decimals to be rounded.
Details
Details
Assignee
Reporter
Priority
Labels
Fix versions
New Issue warning screen
Before you create a new Issue, please post to the mailing list first https://dev.lucee.org
Once the issue has been verified, one of the Lucee team will ask you to file an issue
Converting a string containing a large decimal number (more than 15 digits) causes the number to be rounded and to lose all decimal places after the rounded digit.
In ACF, the decimal precision is preserved no matter how large (or small) the decimal value is.
in Lucee, adding a 14th character (15th if you count the decimal point) causes the value to round up, and all former precision is lost.
In summary, Lucee should respect the original casting / decimal precision when the variable was created in CFML or provided from an external source ( e.g. a JSON file ).
Example on TryCF: