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



x = “12345.12345”
y = 12345.12345

(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


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.


– Denny


FYI a bug and a testcase has been filed about this problem


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.


follow up

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


ie. 1234.56 eq “1234.56”


ie. 12345678.9 neq “12345678.9”

a fix has been made - see

here is the diff…

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

  •        		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);