Jason Roozee
05/05/2025, 3:54 PMceiling((val/4)*100)
should be returning 7001 not 7002
<cfset val = 280.04>
val/4: #(val/4)#
<br>
(val/4)*100: #((val/4)*100)#
<br>
ceiling((val/4)*100): #(ceiling((val/4)*100))#
<br>
ceiling((val/4)*100)*100:#(ceiling((val/4)*100)/100)#Matt Jones
05/05/2025, 4:11 PMJason Roozee
05/05/2025, 4:19 PMMatt Jones
05/05/2025, 4:21 PMMatt Jones
05/05/2025, 4:23 PMJason Roozee
05/05/2025, 4:24 PMJason Roozee
05/05/2025, 4:24 PMbdw429s
05/05/2025, 6:26 PMbdw429s
05/05/2025, 6:27 PMbdw429s
05/05/2025, 6:27 PMprecisionEvaluate() in ACF should give the expected response.dswitzer
05/05/2025, 9:53 PMbdw429s
05/05/2025, 10:04 PMfoo = 5
is still a java.lang.Integer behind the scenes. We only promote to a "larger" type such as double, long, or bigdecimal if it's needed, and our types are "contagious" just like other JVM languages such as Clojure, so the result of a math operation is the "larger" of the two types. This keeps most types pretty small. I don't know what Lucee's BigDecimal defaults were, but BoxLang also uses DECIMAL128 by default
> IEEE 754-2019 decimal128 format, 34 digits, and a rounding mode of HALF_EVEN.
which stores a lot less data than what you get out of the box to be more performant. If Lucee used BigDecimal's default settings, it would have been unlimited precision which is entirely unnecessary for most use cases.
I did tests on the ColdBox framework, and out of thousands of math operations on every page request (largely internal loops and counters), I think there was an average of 0 to 1 of them which actually used big decimal. The rest used basic int math. Lucee's approach of making EVERYTHING big decimal was killing ants with a hand-grenade IMO. And Lucee's fallback approach is still too heavy IMO as they use Doubles even for non-floating point numbers, or at least they did last time I looked.bdw429s
05/05/2025, 10:06 PMBK BK
05/07/2025, 3:57 PMLet x be 0.99999999999999999... (ad infinitum)
Then 10x = 9.99999999999999...
= 9 + 0.999999999999999...
= 9 + x
If 10x = 9 + x, then x must be 1.
Therefore 0.9999999999999... = 1.
Different digits on the left and on the right of the equality sign, but the same value.
I suppose the moral is: be careful how you mix floating-point arithmetic with integer arithmetic.bdw429s
05/07/2025, 5:33 PMBK BK
05/07/2025, 5:52 PMval = 280.04.
Then, in floating-point arithmetic, the value of val/4 is not necessarily 70.01. Instead, it is somewhere between 70.01 - e and 70.01 + e. Here e is a very small number that is a measure of the accuracy and granularity with which real numbers are stored and manipulated by the software or computer.
Variously called "machine epsilon (macheps)", "floating-point precision" or just "precision", e is a deviation from the true value, and so may carry a positive or negative sign. It is the developer's responsibility to be aware of this, irrespective of the underlying the software or computer.
For example, in floating-point arithmetic, ceiling((val/4)*100) may turn out to be
ceiling((70.01 - e)*100) , which is 7001 or ceiling((70.01 + e)*100) , which is 7002.Jason Roozee
05/07/2025, 5:56 PMbdw429s
05/07/2025, 6:01 PMbdw429s
05/07/2025, 6:01 PMbdw429s
05/07/2025, 6:03 PM0.333333333 repeating forever. This is because 1/3 cannot be stored exactly in decimal. So even though the value seems "small" there is no exact representation of it, so the value gets rounded at some point.bdw429s
05/07/2025, 6:06 PM0.1 looks very "small", but cannot be stored exactly in binary without an infinite repeating pattern, which is eventually rounded.
0011111110111001100110011001100110011001100110011001100110011010... etc
☝️ binary representation of the decimal 0.1bdw429s
05/07/2025, 6:07 PMbdw429s
05/07/2025, 6:07 PMbdw429s
05/07/2025, 6:14 PMnum = .1 + .2
writeoutput( num.toString() )
BTW. The output is
0.30000000000000004 // Adobe 2025
0.3 // BoxLangBK BK
05/08/2025, 8:18 AM