diff --git a/basex-core/src/main/java/org/basex/query/value/item/ANum.java b/basex-core/src/main/java/org/basex/query/value/item/ANum.java index e3a27c0218..b4be8b8821 100644 --- a/basex-core/src/main/java/org/basex/query/value/item/ANum.java +++ b/basex-core/src/main/java/org/basex/query/value/item/ANum.java @@ -83,6 +83,38 @@ public final boolean atomicEqual(final Item item) throws QueryException { */ protected abstract float flt(); + /** + * Converts an item to decimal, if it is untyped, or to double if decimal conversion cannot + * succeed. + * @param item item + * @param ii input info + * @return converted item (unchanged if not untyped, otherwise decimal or double) + * @throws QueryException query exception + */ + protected static Item untypedToDec(final Item item, final InputInfo ii) throws QueryException { + if(!item.type.isUntyped()) return item; + final byte[] token = item.string(ii); + for(final byte b : token) if(b == 'e' || b == 'E' || b == 'N') return Dbl.get(item.dbl(ii)); + return Dec.get(item.dec(ii)); + } + + /** + * Converts an item to float, if it is untyped, or to double if float conversion fails. + * @param item item + * @param ii input info + * @return converted item (unchanged if not untyped, otherwise float or double) + * @throws QueryException query exception + */ + protected static Item untypedToFlt(final Item item, final InputInfo ii) throws QueryException { + if(!item.type.isUntyped()) return item; + try { + return Flt.get(item.flt(ii)); + } catch(QueryException ex) { + Util.debug(ex); + return Dbl.get(item.dbl(ii)); + } + } + /** * Returns an absolute value. * @return absolute value diff --git a/basex-core/src/main/java/org/basex/query/value/item/Dbl.java b/basex-core/src/main/java/org/basex/query/value/item/Dbl.java index c8b53d5715..dab5d8856b 100644 --- a/basex-core/src/main/java/org/basex/query/value/item/Dbl.java +++ b/basex-core/src/main/java/org/basex/query/value/item/Dbl.java @@ -107,14 +107,17 @@ public Dbl round(final int prec, final RoundMode mode) { @Override public boolean equal(final Item item, final Collation coll, final InputInfo ii) throws QueryException { - return value == item.dbl(ii); + return !item.type.instanceOf(AtomType.DECIMAL) ? value == item.dbl(ii) : + Double.isFinite(value) ? dec(ii).compareTo(item.dec(ii)) == 0 : false; } @Override public int compare(final Item item, final Collation coll, final boolean transitive, final InputInfo ii) throws QueryException { - return transitive && item instanceof Dec ? -item.compare(this, coll, transitive, ii) : - compare(value, item.dbl(ii), transitive); + return !item.type.instanceOf(AtomType.DECIMAL) ? compare(value, item.dbl(ii), transitive) : + Double.isFinite(value) ? dec(ii).compareTo(item.dec(ii)) : + value == Double.NEGATIVE_INFINITY ? -1 : value == Double.POSITIVE_INFINITY ? 1 : + transitive ? -1 : NAN_DUMMY; } /** diff --git a/basex-core/src/main/java/org/basex/query/value/item/Dec.java b/basex-core/src/main/java/org/basex/query/value/item/Dec.java index 9e523fb622..22152a2559 100644 --- a/basex-core/src/main/java/org/basex/query/value/item/Dec.java +++ b/basex-core/src/main/java/org/basex/query/value/item/Dec.java @@ -163,23 +163,24 @@ static BigDecimal round(final BigDecimal value, final int prec, final RoundMode @Override public boolean equal(final Item item, final Collation coll, final InputInfo ii) throws QueryException { - final Type tp = item.type; - return tp.isUntyped() ? dbl() == item.dbl(ii) : - tp == AtomType.DOUBLE || tp == AtomType.FLOAT ? item.equal(this, coll, ii) : - value.compareTo(item.dec(ii)) == 0; + final Item it = untypedToDec(item, ii); + return !(it instanceof Dbl || it instanceof Flt) || Double.isFinite(it.dbl(ii)) ? + value.compareTo(it.dec(ii)) == 0 : + false; } @Override public int compare(final Item item, final Collation coll, final boolean transitive, final InputInfo ii) throws QueryException { - if(transitive) { - final double n = item.dbl(ii); - if(n == Double.NEGATIVE_INFINITY || Double.isNaN(n)) return 1; - if(n == Double.POSITIVE_INFINITY) return -1; - } else if(item instanceof Dbl || item instanceof Flt) { - return -item.compare(this, coll, transitive, ii); + final Item it = untypedToDec(item, ii); + if(it instanceof Dbl || it instanceof Flt) { + final double n = it.dbl(ii); + if(!Double.isFinite(n)) { + return n == Double.NEGATIVE_INFINITY ? 1 : n == Double.POSITIVE_INFINITY ? -1 : + transitive ? 1 : NAN_DUMMY; + } } - return value.compareTo(item.dec(ii)); + return value.compareTo(it.dec(ii)); } @Override diff --git a/basex-core/src/main/java/org/basex/query/value/item/Flt.java b/basex-core/src/main/java/org/basex/query/value/item/Flt.java index 470e3c1c59..be058ee34f 100644 --- a/basex-core/src/main/java/org/basex/query/value/item/Flt.java +++ b/basex-core/src/main/java/org/basex/query/value/item/Flt.java @@ -107,14 +107,22 @@ public Flt round(final int prec, final RoundMode mode) { @Override public boolean equal(final Item item, final Collation coll, final InputInfo ii) throws QueryException { - return item.type == AtomType.DOUBLE ? item.equal(this, coll, ii) : value == item.flt(ii); + final Item it = untypedToFlt(item, ii); + return it instanceof Flt flt ? value == flt.value : + it instanceof Dbl ? it.equal(this, coll, ii) : + Float.isFinite(value) ? dec(ii).compareTo(it.dec(ii)) == 0 : false; } @Override public int compare(final Item item, final Collation coll, final boolean transitive, final InputInfo ii) throws QueryException { - return item instanceof Dbl || transitive && item instanceof Dec - ? -item.compare(this, coll, transitive, ii) : compare(value, item.flt(ii), transitive); + final Item it = untypedToFlt(item, ii); + return it instanceof Flt flt ? compare(value, flt.value, transitive) : + it instanceof Dbl ? -it.compare(this, coll, transitive, ii) : + Float.isFinite(value) ? dec(ii).compareTo(it.dec(ii)) : + value == Float.NEGATIVE_INFINITY ? -1 : + value == Float.POSITIVE_INFINITY ? 1 : + transitive ? -1 : NAN_DUMMY; } /** diff --git a/basex-core/src/main/java/org/basex/query/value/item/Itr.java b/basex-core/src/main/java/org/basex/query/value/item/Itr.java index b745f6f56e..d2447de4ce 100644 --- a/basex-core/src/main/java/org/basex/query/value/item/Itr.java +++ b/basex-core/src/main/java/org/basex/query/value/item/Itr.java @@ -151,16 +151,14 @@ public int toInt() { public boolean equal(final Item item, final Collation coll, final InputInfo ii) throws QueryException { return item instanceof final Itr itr ? value == itr.value : - item instanceof Dec ? item.equal(this, coll, ii) : - value == item.dbl(ii); + untypedToDec(item, ii).equal(this, coll, ii); } @Override public int compare(final Item item, final Collation coll, final boolean transitive, final InputInfo ii) throws QueryException { return item instanceof final Itr itr ? Long.compare(value, itr.value) : - item instanceof Dec ? -item.compare(this, coll, transitive, ii) : - Dbl.compare(dbl(ii), item.dbl(ii), transitive); + -untypedToDec(item, ii).compare(this, coll, transitive, ii); } @Override diff --git a/basex-core/src/main/java/org/basex/query/value/item/Uln.java b/basex-core/src/main/java/org/basex/query/value/item/Uln.java index d4bc54d2fd..5495db78e1 100644 --- a/basex-core/src/main/java/org/basex/query/value/item/Uln.java +++ b/basex-core/src/main/java/org/basex/query/value/item/Uln.java @@ -88,19 +88,17 @@ public ANum round(final int prec, final RoundMode mode) { @Override public boolean equal(final Item item, final Collation coll, final InputInfo ii) throws QueryException { - return item.type == AtomType.UNSIGNED_LONG ? value.equals(((Uln) item).value) : - item.type == AtomType.DOUBLE || item.type == AtomType.FLOAT || item.type == AtomType.DECIMAL ? - item.equal(this, coll, ii) : - value.compareTo(BigInteger.valueOf(item.itr(ii))) == 0; + return item instanceof final Uln uln ? value.equals(uln.value) : + item instanceof Itr ? value.equals(BigInteger.valueOf(item.itr(ii))) : + untypedToDec(item, ii).equal(this, coll, ii); } @Override public int compare(final Item item, final Collation coll, final boolean transitive, final InputInfo ii) throws QueryException { - return item.type == AtomType.UNSIGNED_LONG ? value.compareTo(((Uln) item).value) : - item.type == AtomType.DOUBLE || item.type == AtomType.FLOAT || item.type == AtomType.DECIMAL ? - -item.compare(this, coll, transitive, ii) : - value.compareTo(BigInteger.valueOf(item.itr(ii))); + return item instanceof final Uln uln ? value.compareTo(uln.value) : + item instanceof Itr ? value.compareTo(BigInteger.valueOf(item.itr(ii))) : + -untypedToDec(item, ii).compare(this, coll, transitive, ii); } @Override diff --git a/basex-core/src/test/java/org/basex/query/ast/RewritingsTest.java b/basex-core/src/test/java/org/basex/query/ast/RewritingsTest.java index cbcd058c57..adbbd84c32 100644 --- a/basex-core/src/test/java/org/basex/query/ast/RewritingsTest.java +++ b/basex-core/src/test/java/org/basex/query/ast/RewritingsTest.java @@ -171,9 +171,11 @@ public final class RewritingsTest extends SandboxTest { check("5[text() <= -800000000]", "", exists(cmpr)); check("5[text() > 8000000000000000000]", "", exists(cmpr)); check("5[text() < -8000000000000000000]", "", exists(cmpr)); - check("exists(1234567890.12345678[. = 1234567890.1234567])", true, empty(cmpr)); + check("exists(1234567890.12345678[. = 1234567890.1234567])", false, empty(cmpr)); + check("exists(1234567890.12345678e0[. = 1234567890.1234567e0])", true, empty(cmpr)); - check("exists(123456789012345678 [. = 123456789012345679])", true, empty(cmpr)); + check("exists(123456789012345678 [. = 123456789012345679])", false, empty(cmpr)); + check("exists(123456789012345678e0 [. = 123456789012345679e0])", true, empty(cmpr)); check("5[xs:integer(.) > 8000000000000000000]", "", empty(cmpr)); check("5[xs:integer(.) < -8000000000000000000]", "", empty(cmpr)); check("(1, 1234567890.12345678)[. = 1234567890.1234567]", "", empty(cmpr)); @@ -885,9 +887,13 @@ public final class RewritingsTest extends SandboxTest { "2\n3\n4\n5\n6\n7", empty(Cast.class)); check("for $n in (10000000000000000, 1)[. != 0] return number($n) = 10000000000000001", - "true\nfalse", exists(NUMBER)); + "false\nfalse", exists(NUMBER)); + check("for $n in (10000000000000000, 1)[. != 0] return number($n) = " + + "xs:double(10000000000000001)", "true\nfalse", exists(NUMBER)); check("for $n in (10000000000000000, 1)[. != 0] return xs:double($n) = 10000000000000001", - "true\nfalse", exists(Cast.class)); + "false\nfalse", exists(Cast.class)); + check("for $n in (10000000000000000, 1)[. != 0] return xs:double($n) = " + + "xs:double(10000000000000001)", "true\nfalse", exists(Cast.class)); check("number() + number(<_>2)", 3, count(NUMBER, 1)); check("xs:double() + xs:double(<_>2)", 3, count(Cast.class, 1)); diff --git a/basex-core/src/test/java/org/basex/query/simple/SimpleTest.java b/basex-core/src/test/java/org/basex/query/simple/SimpleTest.java index ca1628baee..9db7c66618 100644 --- a/basex-core/src/test/java/org/basex/query/simple/SimpleTest.java +++ b/basex-core/src/test/java/org/basex/query/simple/SimpleTest.java @@ -53,10 +53,10 @@ public final class SimpleTest extends QueryTest { { "Compare 5", booleans(false), "1234567890.12345678 = 1234567890.1234567" }, { "Compare 6", booleans(false), "123456789012345678 = 123456789012345679" }, // GH-2112, GH-2115 - { "Compare 7", booleans(false), "xs:decimal(1.13) gt xs:double(1.13)" }, - { "Compare 8", booleans(false), "xs:decimal(1.13) gt xs:float(1.13)" }, - { "Compare 9", booleans(true), "xs:decimal(1.13) le xs:double(1.13)" }, - { "Compare 10", booleans(true), "xs:decimal(1.13) le xs:float(1.13)" }, + { "Compare 7", booleans(true), "xs:decimal(1.13) gt xs:double(1.13)" }, + { "Compare 8", booleans(true), "xs:decimal(1.13) gt xs:float(1.13)" }, + { "Compare 9", booleans(false), "xs:decimal(1.13) le xs:double(1.13)" }, + { "Compare 10", booleans(false), "xs:decimal(1.13) le xs:float(1.13)" }, // GH-2113, GH-2114 { "Compare 11", booleans(false), "xs:float (1.13) ge xs:double(1.13)" }, { "Compare 12", booleans(true), "xs:float (1.13) le xs:double(1.13)" },