Is this a bug? Equality test fails when comparing numbers with decimal places


#1

when

x = “12345.12345”
y = 12345.12345

ACF
(x eq y) is TRUE
(val(x) eq y) is TRUE
(x eq trim(y)) is TRUE
isNumeric(x) is TRUE

Lucee 5.1
(x eq y) is FALSE
(val(x) eq y) is TRUE
(x eq trim(y)) is TRUE
isNumeric(x) is TRUE


#2

It’s a compatibility difference, I’ll grant you that, but I’m not sure I’d call it a bug, per se. It’s been this way since Railo and, strictly speaking, a string shouldn’t evaluate true with a number.

EDIT: The decimal point here causes the string version of the decimal number to be cast as a string, whereas the decimal number by itself is cast as a numeric. Though Micha or someone else involved in the Java can correct me if I’m wrong here, I’m pretty sure that’s what happening in this case.

ACF goes out of their way to make numbers and strings equivalent, If you know you’ll be comparing a string representation of a decimal number with an actual decimal number in Lucee, then I’d go with the second version of your tests:

val(x) eq y

since this works in both Lucee and ACF, if portability is a concern.

HTH

– Denny


#3

FYI a bug and a testcase has been filed about this problem
https://luceeserver.atlassian.net/browse/LDEV-1419


#4

Thanks Denny. I understand the issue, and can resolve. However cf is type-less so implementation should take this into account, especially for compatibility. And consistency as whole numbers work OK.

And this could lead to some quite difficult run-time anomalies for code moved from ACF.

I posted a bug on the issue tracker and they are thinking about what to do with it. At minimum need to be a searchable issue for portability concerns.


#5

follow up

the comparison only failed if the the number’s length as a string was greater than 9

so

ie. 1234.56 eq “1234.56”

BUT

ie. 12345678.9 neq “12345678.9”

a fix has been made - see https://luceeserver.atlassian.net/browse/LDEV-1419

here is the diff…

if(Decision.isNumber(left)) {
if(left.length()>9) {
try{

  •        		return new BigDecimal(left).compareTo(new BigDecimal(right));
    
  •        		return new BigDecimal(left).compareTo(new BigDecimal(**Caster.toString(right)**));
           	}
    
  •        	catch(Throwable t) {ExceptionUtil.rethrowIfNecessary(t);}
    
  •        	catch(Exception e) {}
           }
      	return compare(Caster.toDoubleValue(left,Double.NaN),right); 
      }