Skip to content

Commit bb77ff4

Browse files
authored
Merge pull request #4433 from evolvedbinary/hotfix/numeric-operations
2 parents e63ca9f + a8e72a0 commit bb77ff4

16 files changed

+924
-39
lines changed

exist-core/src/main/java/org/exist/xquery/ValueComparison.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ protected Sequence genericCompare(Sequence contextSequence, Item contextItem) th
7676
final AtomicValue rv = rs.itemAt(0).atomize();
7777
final Collator collator = getCollator(contextSequence);
7878
return BooleanValue.valueOf(compareAtomic(collator, lv, rv, StringTruncationOperator.NONE, relation));
79-
}
79+
}
8080
throw new XPathException(this, ErrorCodes.XPTY0004, "Type error: sequence with more than one item is not allowed here");
8181
}
8282

exist-core/src/main/java/org/exist/xquery/value/DecimalValue.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,8 @@ public boolean isPositive() {
283283
} else if (other instanceof DoubleValue) {
284284
comparison = () -> value.compareTo(BigDecimal.valueOf(((DoubleValue)other).value));
285285
} else if (other instanceof FloatValue) {
286-
comparison = () -> value.compareTo(BigDecimal.valueOf(((FloatValue)other).value));
286+
final BigDecimal otherPromoted = new BigDecimal(Float.toString(((FloatValue)other).value));
287+
comparison = () -> value.compareTo(otherPromoted);
287288
} else {
288289
return null;
289290
}
@@ -361,10 +362,8 @@ public NumericValue round(final IntegerValue precision) throws XPathException {
361362
return round(precision, DecimalValue.DEFAULT_ROUNDING_MODE);
362363
}
363364

364-
/* (non-Javadoc)
365-
* @see org.exist.xquery.value.NumericValue#minus(org.exist.xquery.value.NumericValue)
366-
*/
367-
public ComputableValue minus(ComputableValue other) throws XPathException {
365+
@Override
366+
public ComputableValue minus(final ComputableValue other) throws XPathException {
368367
switch (other.getType()) {
369368
case Type.DECIMAL:
370369
return new DecimalValue(value.subtract(((DecimalValue) other).value));
@@ -375,10 +374,8 @@ public ComputableValue minus(ComputableValue other) throws XPathException {
375374
}
376375
}
377376

378-
/* (non-Javadoc)
379-
* @see org.exist.xquery.value.NumericValue#plus(org.exist.xquery.value.NumericValue)
380-
*/
381-
public ComputableValue plus(ComputableValue other) throws XPathException {
377+
@Override
378+
public ComputableValue plus(final ComputableValue other) throws XPathException {
382379
switch (other.getType()) {
383380
case Type.DECIMAL:
384381
return new DecimalValue(value.add(((DecimalValue) other).value));

exist-core/src/main/java/org/exist/xquery/value/FloatValue.java

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ public boolean isPositive() {
137137
if (other instanceof IntegerValue) {
138138
comparison = () -> BigDecimal.valueOf(value).compareTo(new BigDecimal(((IntegerValue)other).value));
139139
} else if (other instanceof DecimalValue) {
140-
comparison = () -> BigDecimal.valueOf(value).compareTo(((DecimalValue)other).value);
140+
final BigDecimal promoted = new BigDecimal(Float.toString(value));
141+
comparison = () -> promoted.compareTo(((DecimalValue)other).value);
141142
} else if (other instanceof DoubleValue) {
142143
comparison = () -> BigDecimal.valueOf(value).compareTo(BigDecimal.valueOf(((DoubleValue)other).value));
143144
} else if (other instanceof FloatValue) {
@@ -276,35 +277,38 @@ public NumericValue round(IntegerValue precision) throws XPathException {
276277
return round(precision, DecimalValue.DEFAULT_ROUNDING_MODE);
277278
}
278279

279-
/* (non-Javadoc)
280-
* @see org.exist.xquery.value.NumericValue#minus(org.exist.xquery.value.NumericValue)
281-
*/
282-
public ComputableValue minus(ComputableValue other) throws XPathException {
280+
@Override
281+
public ComputableValue minus(final ComputableValue other) throws XPathException {
283282
if (Type.subTypeOf(other.getType(), Type.FLOAT)) {
284283
return new FloatValue(value - ((FloatValue) other).value);
284+
} else if (other.getType() == Type.DOUBLE) {
285+
// type promotion - see https://www.w3.org/TR/xpath-31/#promotion
286+
return ((DoubleValue) convertTo(Type.DOUBLE)).minus(other);
285287
} else {
286288
return minus((ComputableValue) other.convertTo(getType()));
287289
}
288290
}
289291

290-
/* (non-Javadoc)
291-
* @see org.exist.xquery.value.NumericValue#plus(org.exist.xquery.value.NumericValue)
292-
*/
293-
public ComputableValue plus(ComputableValue other) throws XPathException {
292+
@Override
293+
public ComputableValue plus(final ComputableValue other) throws XPathException {
294294
if (Type.subTypeOf(other.getType(), Type.FLOAT)) {
295295
return new FloatValue(value + ((FloatValue) other).value);
296+
} else if (other.getType() == Type.DOUBLE) {
297+
// type promotion - see https://www.w3.org/TR/xpath-31/#promotion
298+
return ((DoubleValue) convertTo(Type.DOUBLE)).plus(other);
296299
} else {
297300
return plus((ComputableValue) other.convertTo(getType()));
298301
}
299302
}
300303

301-
/* (non-Javadoc)
302-
* @see org.exist.xquery.value.NumericValue#mult(org.exist.xquery.value.NumericValue)
303-
*/
304-
public ComputableValue mult(ComputableValue other) throws XPathException {
304+
@Override
305+
public ComputableValue mult(final ComputableValue other) throws XPathException {
305306
switch (other.getType()) {
306307
case Type.FLOAT:
307308
return new FloatValue(value * ((FloatValue) other).value);
309+
case Type.DOUBLE:
310+
// type promotion - see https://www.w3.org/TR/xpath-31/#promotion
311+
return ((DoubleValue) convertTo(Type.DOUBLE)).mult(other);
308312
case Type.DAY_TIME_DURATION:
309313
case Type.YEAR_MONTH_DURATION:
310314
return other.mult(this);
@@ -358,26 +362,26 @@ public ComputableValue div(ComputableValue other) throws XPathException {
358362
}
359363
}
360364

361-
public IntegerValue idiv(NumericValue other) throws XPathException {
362-
final ComputableValue result = div(other);
363-
return new IntegerValue(((IntegerValue) result.convertTo(Type.INTEGER)).getLong());
364-
/*
365-
if (Type.subTypeOf(other.getType(), Type.FLOAT)) {
366-
float result = value / ((FloatValue) other).value;
367-
if (result == Float.NaN || result == Float.POSITIVE_INFINITY || result == Float.NEGATIVE_INFINITY)
368-
throw new XPathException("illegal arguments to idiv");
369-
return new IntegerValue(new BigDecimal(result).toBigInteger(), Type.INTEGER);
370-
}
371-
throw new XPathException("idiv called with incompatible argument type: " + getType() + " vs " + other.getType());
372-
*/
365+
@Override
366+
public IntegerValue idiv(final NumericValue other) throws XPathException {
367+
if (other.getType() == Type.DOUBLE) {
368+
// type promotion - see https://www.w3.org/TR/xpath-31/#promotion
369+
return ((DoubleValue) convertTo(Type.DOUBLE)).idiv(other);
370+
} else if (other.getType() == Type.DECIMAL) {
371+
return idiv((FloatValue) other.convertTo(Type.FLOAT));
372+
} else {
373+
final ComputableValue result = div(other);
374+
return new IntegerValue(((IntegerValue) result.convertTo(Type.INTEGER)).getLong());
375+
}
373376
}
374377

375-
/* (non-Javadoc)
376-
* @see org.exist.xquery.value.NumericValue#mod(org.exist.xquery.value.NumericValue)
377-
*/
378-
public NumericValue mod(NumericValue other) throws XPathException {
378+
@Override
379+
public NumericValue mod(final NumericValue other) throws XPathException {
379380
if (Type.subTypeOf(other.getType(), Type.FLOAT)) {
380381
return new FloatValue(value % ((FloatValue) other).value);
382+
} else if (other.getType() == Type.DOUBLE) {
383+
// type promotion - see https://www.w3.org/TR/xpath-31/#promotion
384+
return ((DoubleValue) convertTo(Type.DOUBLE)).mod(other);
381385
} else {
382386
return mod((NumericValue) other.convertTo(getType()));
383387
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* eXist-db Open Source Native XML Database
3+
* Copyright (C) 2001 The eXist-db Authors
4+
*
5+
6+
* http://www.exist-db.org
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; either
11+
* version 2.1 of the License, or (at your option) any later version.
12+
*
13+
* This library is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
* Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public
19+
* License along with this library; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
package xquery.numericOp;
23+
24+
import org.exist.test.runner.XSuite;
25+
import org.junit.runner.RunWith;
26+
27+
@RunWith(XSuite.class)
28+
@XSuite.XSuiteFiles({
29+
"src/test/xquery/numericOp"
30+
})
31+
public class NumericOpTests {
32+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
(:
2+
: eXist-db Open Source Native XML Database
3+
: Copyright (C) 2001 The eXist-db Authors
4+
:
5+
6+
: http://www.exist-db.org
7+
:
8+
: This library is free software; you can redistribute it and/or
9+
: modify it under the terms of the GNU Lesser General Public
10+
: License as published by the Free Software Foundation; either
11+
: version 2.1 of the License, or (at your option) any later version.
12+
:
13+
: This library is distributed in the hope that it will be useful,
14+
: but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
: Lesser General Public License for more details.
17+
:
18+
: You should have received a copy of the GNU Lesser General Public
19+
: License along with this library; if not, write to the Free Software
20+
: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
:)
22+
xquery version "3.1";
23+
24+
(:~
25+
: Tests for the op:numeric-add operator.
26+
:)
27+
module namespace ona = "http://exist-db.org/test/op-numeric-add";
28+
29+
declare namespace test = "http://exist-db.org/xquery/xqsuite";
30+
31+
declare
32+
%test:args("1.13", "1.13")
33+
%test:assertEquals("2.2599999952316283")
34+
function ona:numeric-add-float-double($f as xs:float, $d as xs:double) {
35+
$f + $d
36+
};
37+
38+
declare
39+
%test:args("1.13", "1.13")
40+
%test:assertEquals("2.2599999952316283")
41+
function ona:numeric-add-double-float($d as xs:double, $f as xs:float) {
42+
$d + $f
43+
};
44+
45+
declare
46+
%test:args("1.13", "1.13")
47+
%test:assertEquals("2.26")
48+
function ona:numeric-add-double-decimal($d as xs:double, $dec as xs:decimal) {
49+
$d + $dec
50+
};
51+
52+
declare
53+
%test:args("1.13", "1.13")
54+
%test:assertEquals("2.26")
55+
function ona:numeric-add-decimal-double($dec as xs:decimal, $d as xs:double) {
56+
$dec + $d
57+
};
58+
59+
declare
60+
%test:args("1.13", "1.13")
61+
%test:assertEquals("2.26")
62+
function ona:numeric-add-decimal-float($dec as xs:decimal, $f as xs:float) {
63+
$dec + $f
64+
};
65+
66+
declare
67+
%test:args("1.13", "1.13")
68+
%test:assertEquals("2.26")
69+
function ona:numeric-add-float-decimal($f as xs:float, $dec as xs:decimal) {
70+
$f + $dec
71+
};
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
(:
2+
: eXist-db Open Source Native XML Database
3+
: Copyright (C) 2001 The eXist-db Authors
4+
:
5+
6+
: http://www.exist-db.org
7+
:
8+
: This library is free software; you can redistribute it and/or
9+
: modify it under the terms of the GNU Lesser General Public
10+
: License as published by the Free Software Foundation; either
11+
: version 2.1 of the License, or (at your option) any later version.
12+
:
13+
: This library is distributed in the hope that it will be useful,
14+
: but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
: Lesser General Public License for more details.
17+
:
18+
: You should have received a copy of the GNU Lesser General Public
19+
: License along with this library; if not, write to the Free Software
20+
: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
:)
22+
xquery version "3.1";
23+
24+
(:~
25+
: Tests for the op:numeric-divide operator.
26+
:)
27+
module namespace ond = "http://exist-db.org/test/op-numeric-divide";
28+
29+
declare namespace test = "http://exist-db.org/xquery/xqsuite";
30+
31+
declare
32+
%test:args("1.13", "1.13")
33+
%test:assertEquals("0.9999999957802023")
34+
function ond:numeric-divide-float-double($f as xs:float, $d as xs:double) {
35+
$f div $d
36+
};
37+
38+
declare
39+
%test:args("1.13", "1.13")
40+
%test:assertEquals("1.0000000042197978")
41+
function ond:numeric-divide-double-float($d as xs:double, $f as xs:float) {
42+
$d div $f
43+
};
44+
45+
declare
46+
%test:args("1.13", "1.13")
47+
%test:assertEquals("1")
48+
function ond:numeric-divide-double-decimal($d as xs:double, $dec as xs:decimal) {
49+
$d div $dec
50+
};
51+
52+
declare
53+
%test:args("1.13", "1.13")
54+
%test:assertEquals("1")
55+
function ond:numeric-divide-decimal-double($dec as xs:decimal, $d as xs:double) {
56+
$dec div $d
57+
};
58+
59+
declare
60+
%test:args("1.13", "1.13")
61+
%test:assertEquals("1")
62+
function ond:numeric-divide-decimal-float($dec as xs:decimal, $f as xs:float) {
63+
$dec div $f
64+
};
65+
66+
declare
67+
%test:args("1.13", "1.13")
68+
%test:assertEquals("1")
69+
function ond:numeric-divide-float-decimal($f as xs:float, $dec as xs:decimal) {
70+
$f div $dec
71+
};
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
(:
2+
: eXist-db Open Source Native XML Database
3+
: Copyright (C) 2001 The eXist-db Authors
4+
:
5+
6+
: http://www.exist-db.org
7+
:
8+
: This library is free software; you can redistribute it and/or
9+
: modify it under the terms of the GNU Lesser General Public
10+
: License as published by the Free Software Foundation; either
11+
: version 2.1 of the License, or (at your option) any later version.
12+
:
13+
: This library is distributed in the hope that it will be useful,
14+
: but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
: Lesser General Public License for more details.
17+
:
18+
: You should have received a copy of the GNU Lesser General Public
19+
: License along with this library; if not, write to the Free Software
20+
: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
:)
22+
xquery version "3.1";
23+
24+
(:~
25+
: Tests for the op:numeric-equal operator.
26+
:)
27+
module namespace one = "http://exist-db.org/test/op-numeric-equal";
28+
29+
declare namespace test = "http://exist-db.org/xquery/xqsuite";
30+
31+
declare
32+
%test:args("1.13", "1.13")
33+
%test:assertFalse
34+
function one:numeric-equal-float-double($f as xs:float, $d as xs:double) {
35+
$f eq $d
36+
};
37+
38+
declare
39+
%test:args("1.13", "1.13")
40+
%test:assertFalse
41+
function one:numeric-equal-double-float($d as xs:double, $f as xs:float) {
42+
$d eq $f
43+
};
44+
45+
declare
46+
%test:args("1.13", "1.13")
47+
%test:assertTrue
48+
function one:numeric-equal-double-decimal($d as xs:double, $dec as xs:decimal) {
49+
$d eq $dec
50+
};
51+
52+
declare
53+
%test:args("1.13", "1.13")
54+
%test:assertTrue
55+
function one:numeric-equal-decimal-double($dec as xs:decimal, $d as xs:double) {
56+
$dec eq $d
57+
};
58+
59+
declare
60+
%test:args("1.13", "1.13")
61+
%test:assertTrue
62+
function one:numeric-equal-decimal-float($dec as xs:decimal, $f as xs:float) {
63+
$dec eq $f
64+
};
65+
66+
declare
67+
%test:args("1.13", "1.13")
68+
%test:assertTrue
69+
function one:numeric-equal-float-decimal($f as xs:float, $dec as xs:decimal) {
70+
$f eq $dec
71+
};

0 commit comments

Comments
 (0)