Copy link to clipboard
Copied
Hi all,
There's a good one, which may have an obvious answer (and that's the reason I first decided to ask it here before filing a bug).
<cfset t1 = ToString("00237000000075384887")>
<cfset t2 = ToString("00237000000075384892")>
<cfif t1 EQ t2><cfoutput>#t1# equal to #t2#</cfoutput><cfelse><cfoutput>#t1# different to #t2#</cfoutput></cfif>
The result of the above is rather surprising. Somewhat this sort of comparison thinks the numbers are equal. Also, even if both numbers are converted to strings, ColdFusion still thinks they are equal.
If using Compare(t1,t2) however, ColdFusion starts comparing the strings as us, humans and distinguishes the difference between them
Now if there's any known limitation to comparing long numbers etc. or the fact that middle of each of them is filled with zeros affects it all, be welcome to point it out to me.
Simon
Do some google on "floating point precision".
As CF is loosely typed, it has to make some guesses when it comes to doing operations in which type is significant. The EQ operator is an example of this: if CF can cast the operands to numerics, it will, which is what it's doing here. And when it casts those strings to numerics, both are 2.37000000075E+017, so they equal.
If you want to compare two strings explicitly as strings, then you need to use compare(), as you ahve already surmised.
There are no
...Copy link to clipboard
Copied
Do some google on "floating point precision".
As CF is loosely typed, it has to make some guesses when it comes to doing operations in which type is significant. The EQ operator is an example of this: if CF can cast the operands to numerics, it will, which is what it's doing here. And when it casts those strings to numerics, both are 2.37000000075E+017, so they equal.
If you want to compare two strings explicitly as strings, then you need to use compare(), as you ahve already surmised.
There are no surprises in anything you're seeing though.
--
Adam
Copy link to clipboard
Copied
You can use PrecisionEvaluate() to have CF store those numbers as BigDecimal instead of Double. You'll likely then see the behavior you expect.
Jason
Copy link to clipboard
Copied
Thanks guys!
@12Robots: tried PrecisionEvaluate(), though results were the same.
@Adam Cameron: Thanks for the explanation. Thought there's something there I've missed. Well, learned something new today
Copy link to clipboard
Copied
I would have expected precisionEvaluate() to work, but I can't coerce it into being helpful here. But one can cut to the chase and just use BigDecimals:
<cfset t1 = createObject("java", "java.math.BigDecimal").init("00237000000075384887")>
<cfset t2 = createObject("java", "java.math.BigDecimal").init("00237000000075384892")>
<cfoutput>#t1.compareTo(t2)#<br /></cfoutput>
That works fine.
--
Adam
Copy link to clipboard
Copied
In this case, I think Adam is right that compare() is the right way to go.
As an aside precisionEvaluate() is a way of gettling Long numbers to be treated as accurate decimals instead of frustrating floating-point Doubles. But I believe precisionEvaluate() needs to occur at the time of comparison.
This code works for me in this situation. Though when testing with numbers that are closer in value I was getting inconsistent results, so it seems that some rounding is still occuring.
<cfset t1 = ToString("00237000000075384848")>
<cfset t2 = ToString("00237000000075384887")>
<cfif precisionEvaluate(t1) EQ precisionEvaluate(t2)><cfoutput>#t1# equal to #t2#</cfoutput><cfelse><cfoutput>#t1# different to #t2#</cfoutput></cfif>
Bottom line, if you want to compare them as strings, use compare(). If you want to be able to use EQ, mix some alpha characters in there
jason