Can somebody explain to me why ColdFusion (tested on 2016,2018 and 2021) is doing a wrong double to long conversion? I know it can mess things up for fractional values, but in this example, it is clearly an integer value.
This is the code:
<cfoutput>
<cfset a = 69.35>
#getMetadata(a)# #a#</br>
<cfset b = a * 100>
#getMetadata(b)# #b#</br>
<cfset c = int(b)>
#getMetadata(c)# #c#</br>
</cfoutput>
And this is the output:
class coldfusion.runtime.CFDouble 69.35
class java.lang.Double 6935
class java.lang.Long 6934
It is "sort-of" fixable by doing this:
<cfset d = int(javacast("string", b))>
#getMetadata(d)# #d#</br>
Returning
class java.lang.Long 6935
But I'm not really satisfied by this "solution"... Thanks!
EDIT: Because ColdFusion is running on top of java, I guess this is responsible for it:
public static void main(String[] args)
{
double a = 69.35;
double b = a * 100;
System.out.println(b);
long c = (int)b;
System.out.println(c);
long d = Math.round(b);
System.out.println(d);
}
Output:
6934.999999999999
6934
6935
And most likely, ColdFusion is using int() and not round() to convert the double value to long... This is one of the "nice" side effects of a typeless programming language, which internally makes a mess of it. Makes me think of javascript ;-)
EDIT 2:
As Cameron pointed out, there is a difference between #b# and #b.ToString()#. The former is returning 6935, while the latter is returning 6934.999999999999. This is confusing in my opinion, but I'll keep it in the back of my head for in case I run into another strange problem with double/long values :-)
And to make it even a bit more confusion: int(ToString(b)) is returning 6935 while int(b.ToString()) is returning 6934...
<cfset a = 69.35>
#getMetadata(a)# #a#</br>
<cfset b = a * 100>
#getMetadata(b)# #b#</br>
#b.toString()# #ToString(b)#</br>
Is returning:
class java.lang.String 69.35
class java.lang.Double 6935
6934.999999999999 6935
So, don't assume that b.ToString() is the same as ToString(b) ...
As @SOS touches on in their comment (not sure why they did not make it an "answer"?), the issue is not the conversion. The issue is that ColdFusion is displaying 69.35 * 100
as equalling 6935
, which it isn't. And even ColdFusion doesn't really think it is.
As far as most computing languages are concerned, 69.35 * 100
is 6934.999999999999
(check on JS, Python, Ruby etc if you like), due to issues with the inherent inaccuracy of representing decimal fractional values in a system that stores stuff in binary. I've written about this before: Floating point arithmetic with decimals.
Internally ColdFusion is storing the result as 6934.999999999999
:
<cfset f = 69.35 * 100>
<cfoutput>#f.toString()#</cfoutput>
This yields:
6934.999999999999
So when you use int
to take the integer portion of 6934.999999999999
, you get 6934
. That part is actually doing the job correctly! ;-)