2

I have a simple loop:

<cfoutput>
    <cfloop from="0.01" to="0.06" index="i" step="0.01">
        <p>i=#i#</p>
    </cfloop>
</cfoutput>

Output is:

i=0.01
i=0.02
i=0.03
i=0.04
i=0.05

The expected value 0.06 does not appear! If I add or decrease the value of the "To" by 0.01 then the loop works properly.

I have created an example of the issue here on TryCF. Click the "Run Code" button to generate the output.

Any ideas?

Miguel-F
  • 13,450
  • 6
  • 38
  • 63
  • 3
    I've got an idea... show your code. – Evik James Oct 12 '15 at 13:51
  • 2
    @Marco - Since CF typically uses [java.lang.Double](http://docs.oracle.com/javase/7/docs/api/java/lang/Double.html) to represent numbers, you are running into the [typical floating point math issues](http://stackoverflow.com/questions/2002821/why-does-this-subtraction-not-equal-zero). The last value of the index is actually `0.060000000000000005`. The reason it does not display is because that value is greater than the loop max, ie `0.06`. You may be better off sticking with integer's for loops (if possible). – Leigh Oct 12 '15 at 16:59

2 Answers2

4

My guess is that the issue here is how ColdFusion deals with numbers. It is converting your strings "0.01" and "0.06" into numbers and probably loosing precision at some point. Remember ColdFusion is loosely typed.

ColdFusion does not use explicit types for variables, while Java is strongly typed. However, ColdFusion data does use underlying Java types to represent data.

From Java and ColdFusion data type conversions

I have modified the ColdFusion example on TryCF in an attempt to show my point. I used javacast() to explicitly define the numbers as floats. Try the new code here.

<cfloop from="#javacast('float','0.01')#" 
        to="#javacast('float','0.06')#" 
        index="i" 
        step="#javacast('float','0.01')#">
    i=#i#<br>
</cfloop>

This now outputs the expected six times.

i=0.00999999977648
i=0.019999999553
i=0.0299999993294
i=0.0399999991059
i=0.0499999988824
i=0.0599999986589

You could then add the NumberFormat() function when outputting these values to get the output you want. Not sure of the precision that you need here. You could just use Duncan's example as well.

<cfloop from="#javacast('float','0.01')#" 
        to="#javacast('float','0.06')#" 
        index="i" 
        step="#javacast('float','0.01')#">
    i=#NumberFormat(i,"9.99")#<br>
</cfloop>

Outputs:

i=0.01
i=0.02
i=0.03
i=0.04
i=0.05
i=0.06
Miguel-F
  • 13,450
  • 6
  • 38
  • 63
  • I think Miguell is on the right track here - doubtless a double/float issue in Java. – Mark A Kruger Oct 12 '15 at 17:28
  • I went through the same exact issue today some day). I posted my on gist/trycf/slack. I added JS and noticed it displayed full decimal value & didn't round. I also noticed all CFML engines on TryCF returned the same results. – James Moberg Oct 13 '15 at 01:00
  • 1
    @Miguel-F - Yes, it is definitely due to using approximate types. Seems like that is always going be an issue with *some* combination of fractional numbers, so sticking with integers might be a better option. – Leigh Oct 14 '15 at 12:49
  • @Leigh agreed, I was just trying to point out what was happening here. Hey, a bit OT but, have you joined the CFML Slack channel? If not, there has been some really good CFML conversations happening on it. Even with the Adobe team directly. Kinda cool if you are interested. – Miguel-F Oct 14 '15 at 12:56
  • @Miguel-F - Gotcha. No, I have not joined it yet (been working on a lot non-CF stuff lately). Thanks. I will check it out. – Leigh Oct 14 '15 at 12:59
  • @Leigh - you must be invited to join. They have setup an invitation platform here - http://cfml-slack.herokuapp.com/ And Adam Cameron blogged about it a bit here - http://blog.adamcameron.me/2015/06/cfml-slack.html – Miguel-F Oct 14 '15 at 13:04
  • @Miguel-F - Cool. Thanks for the heads up. – Leigh Oct 14 '15 at 13:17
1

Sounds like a bug. You can always do this, it seems to work:

<cfloop from="1" to="6" index="i" step="1">
    i=#i/100#<br>
</cfloop>
duncan
  • 31,401
  • 13
  • 78
  • 99