comparing strings

27 views
Skip to first unread message

Tom Lenz

unread,
May 20, 2009, 11:46:25 PM5/20/09
to ra...@googlegroups.com
Over here
http://www.bennadel.com/blog/236-ColdFusion-String-Comparison-Compare-vs-Equals-vs-CompareTo-.htm
I read this:

This is why I hate coldfusion. It doesn't hold to any conventions about
how objects should be compared. For example, strings of different
lengths get evaluated completely differently. I know of no other
language that does this.

<cfscript>
a = '12345';
b = '12346';
// Should be false, and is false.
writeoutput('#a# eq #b# == #a eq b#<br />');

a = '2707200116272368271111';
b = '2707200116272368279465';
// Should be false, but isn't.
writeoutput('#a# eq #b# == #a eq b#<br />');
</cfscript>

And I thought, "Nah, that's just with adobe's". Wrong. Railo's output:

12345 eq 12346 == false
2707200116272368271111 eq 2707200116272368279465 == true


Tom Lenz

unread,
May 21, 2009, 8:51:45 AM5/21/09
to ra...@googlegroups.com
Someone suggested that maybe these strings are getting converted to
numbers and compared as numbers. Sure enough:

<cfscript>
a = 'xyz2707200116272368271111';
b = 'xyz2707200116272368279465';
// can't be converted to numbers


writeoutput('#a# eq #b# == #a eq b#<br />');
</cfscript>

gives:
xyz270720011627236821111 eq xyz270720011627236829465 == false

As an aside,

<cfswitch expression="#a#">
<cfcase value="270720011627236829465">
<cfoutput>270720011627236829465</cfoutput>
</cfcase>
<cfcase value="270720011627236821111">
<cfoutput>270720011627236821111</cfoutput>
</cfcase>
</cfswitch>


gives what you'd want with Railo:
270720011627236821111

with adobe cf:
Context validation error for the cfcase tag.
The cfswitch tag has a duplicate cfcase tag for value
2.7072001162723682E20.

Ryan Letulle

unread,
May 21, 2009, 10:29:29 AM5/21/09
to ra...@googlegroups.com
Hmmm.  This is some nasty stuff.  So have you determined that string comparisons beyond a certain length cannot be trusted.   

--
Ryan

Tom Lenz

unread,
May 21, 2009, 10:31:43 AM5/21/09
to ra...@googlegroups.com
Yeah, must be the reason for the Compare and CompareNoCase functions

Ryan Letulle

unread,
May 21, 2009, 10:36:28 AM5/21/09
to ra...@googlegroups.com
This is very nice to know.  I never noticed this before,  I guess since I rarely compare long strings.  This is the kind of thing that could set you back a few hours or days. :)

thx
--
Ryan

Peter Bell

unread,
May 21, 2009, 10:47:28 AM5/21/09
to ra...@googlegroups.com
Don't think so. It's simply an issue with precision of integers. I'm not much of a guru on the inner workings of any of the CF engines (sad to say), but I'm pretty sure all of them will by default treat a = 12345 OR a = '12345' as creation and assignment of an integer (or *possibly* BigInt). If you concatenate something to them, it'll probably treat them as strings, or if there are any non numeric characters, but you were simply running into an issue with comparing really large numbers. 

As for Compare and CompareNoCase, they're what you'd expect. In one abc == ABC and in the other abc !== ABC.

Best Wishes,
Peter

Ryan Letulle

unread,
May 21, 2009, 11:01:52 AM5/21/09
to ra...@googlegroups.com
So very large integers cannot be compared precisely but strings such uuid can?

--
Ryan

Andrew Penhorwood

unread,
May 21, 2009, 11:09:11 AM5/21/09
to Ryan Letulle

Ryan,


It appears that you are ok if the data between quotes is interpreted as a string instead of as a number.


so this would be a number "1234567890123456789" 

but "1234-5678901-23456789" would be a string.


Andrew Penhorwood

-- 

Best regards,

Andrew Penhorwood

and...@coldbits.com

www.coldbits.com

419-884-6042

Peter Bell

unread,
May 21, 2009, 11:18:49 AM5/21/09
to ra...@googlegroups.com
Right. Its a function of the Java type system, but I don't know offhand of any type system that can compare arbitrarily large numbers. Usually you have a few types like Int, BigInt, Decimal and BigDecimal and you need to know the limitations of the underlying system. It's the same if you try to compare floating point numbers and run into precision issues. I'd definitely recommend reading up on the Java type system. CFML allows us to ignore types most of the time, but that doesn't mean they don't exist, so you can still get caught out by them if you're not aware of what is going on under the hood. This is true in all computer languages (that Im aware of),

Best Wishes.
Peter

Tom Lenz

unread,
May 21, 2009, 11:41:44 AM5/21/09
to ra...@googlegroups.com
<cfset a = "270720011627236821111">
<cfset b = "270720011627236829465">

<cfoutput>#Compare(a,b)#<br></cfoutput>
returns:
-1

<cfset a = 270720011627236821111>
<cfset b = 270720011627236829465>

<cfoutput>#Compare(a,b)#<br></cfoutput>
<cfoutput>#Compare("#a#","#b#")#<br></cfoutput>
returns:
0
0

Barney Boisvert

unread,
May 21, 2009, 11:51:15 AM5/21/09
to ra...@googlegroups.com
The third compare is doing a number-to-string comparison, but the
numbers are already truncated in precision, so converting them to
strings isn't going to help. Though I get -1 for all three
statements on ColdFusion Server 8,0,1,195765

cheers
barneyb
--
Barney Boisvert
bboi...@gmail.com
http://www.barneyb.com/

Ryan Letulle

unread,
May 21, 2009, 12:06:38 PM5/21/09
to ra...@googlegroups.com
Verrry nice to know because on occasion I have used the exact point in time as a unique id - i.e. YYYYMMDDHHMMSS

I don't think I will ever do that again.
 
--
Ryan

Peter Bell

unread,
May 21, 2009, 12:16:17 PM5/21/09
to ra...@googlegroups.com
Add hyphens. More readable and clearly a string :-)

DateFormat( Now() , "YYYY-MM-DD-HH-MM-SS")

Best Wishes,
Peter

Baz

unread,
May 21, 2009, 1:20:05 PM5/21/09
to ra...@googlegroups.com
Even if it is a precision issue shouldn't 2 identical numbers be treated or truncated identically?

Adam Haskell

unread,
May 21, 2009, 3:00:56 PM5/21/09
to ra...@googlegroups.com
Everything simple is a string, it's defacto since a string can hold everything. I imagine most of the engines store all CF level data in some sort of CFML Data wrapper so reality is nothing is stored as a int or as a string but really as an object but I think that goes beyond the discussion here. The important thing to note is that  CFML engines will convert a value at runtime to the "appropriate type".

Very large integers can be compared precisely. Very large numbers, which are not integers, may not be able to be compared precisely. This is more than a semantic distinction there is a difference. Realize that regardless of how a value is "stored" when the comparison happens it happens in Java so the number must be representable as a number in java in some type or another. Longs, the largest primative numeric type in Java as far as I recall, have the range of around +/- 1x10^19 (the range is actually smaller than that but this was easier to type). The original numbers set forth are larger than this which might be why there are recorded inconsistencies. I think Larger numbers can be cast into BigIntegers but that's not native and i am not sure how BigIntegers perform, can't say I've ever run into the need to know about it.



Adam H

Michael Offner-Streit

unread,
May 22, 2009, 3:45:42 AM5/22/09
to ra...@googlegroups.com
the problem is and yes it is a problem, in java numbers are restricted
in (byte) size.
Railo use internally double values for all number operations.
it is possible to use BigDecimal but this is very slow.

what is happening in your example, a cfml string comparsion always check
if the 2 operant are castable to numeric value.
if yes in make a number comparsion otherwise a string comparision:
example:
<cfoutput>#"01" EQ "1"#</cfoutput> return true, because both values cant
be translated to 1.

ok let us take your example
<cfscript>
a = '2707200116272368271111';
b = '2707200116272368279465';
writeoutput(a+0);
writeoutput('<br>');
writeoutput(a+0);
</cfscript>
the plus 0 translate the value to a number
the output is
2707200116272368000000
2707200116272368000000
and a comparsion of this 2 values gives true

the question is why are this values transalted to the same numeric value.
take the following example
<cfscript>
Double=createObject('java','java.lang.Double');
a = '2707200116272368271111';
b = '2707200116272368279465';
writeoutput(Double.toString(Double.parseDouble(a)));
writeoutput('<br>');
writeoutput(Double.toString(Double.parseDouble(b)));
</cfscript>
you see i use a native java method to translate the string to a number
and back to a string and the result is the same for both vaules.
the problem is already on java level

you can also see this problem also with smaller numbers
<cf_valueEquals left="#(27^(1/3))#" right="3">
output:2.99999999997

read more here
http://epramono.blogspot.com/2005/01/double-vs-bigdecimal.html

we already have this on our to do list, but it is not easy to solve

/micha













Tom Lenz schrieb:
--
Michael Offner-Streit
Technical Support
Railo Technologies GmbH
michael...@railo.ch
www.railo-technologies.com

Mailing List (english): http://groups.yahoo.com/group/railo_talk/
Mailing List (german): http://de.groups.yahoo.com/group/railo/
Linked in: http://www.linkedin.com/e/gis/71368/0CF7D323BBC1
Issue Tracker: http://jira.jboss.org/jira/browse/RAILO
Blog: http://www.railo-technologies.com/blog


Ronan Lucio

unread,
May 22, 2009, 8:39:11 AM5/22/09
to ra...@googlegroups.com
Michael,

Michael Offner-Streit escreveu:


> the problem is and yes it is a problem, in java numbers are restricted
> in (byte) size.
> Railo use internally double values for all number operations.
> it is possible to use BigDecimal but this is very slow.
>

What about using BigDecimal only for values greater than <Doble_Limit>?

Example: the same way you check it "01" should be compared either as a
string or as a number, you can check it can be compared either as a
double or as a bigdecimal.

Ronan

Reply all
Reply to author
Forward
0 new messages