This is an automated email from the ASF dual-hosted git repository. andy pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/jena.git
commit 16ec4d84d77196c2fd5ae75825df43beeeb6e913 Author: Andy Seaborne <[email protected]> AuthorDate: Tue Dec 30 19:00:01 2025 +0000 Rename NodeValue constants for certain xsd:double cases --- .../org/apache/jena/sparql/expr/NodeValue.java | 28 +++++++++++---- .../sparql/expr/nodevalue/NodeValueDouble.java | 2 +- .../jena/sparql/expr/nodevalue/NodeValueFloat.java | 2 +- .../jena/sparql/expr/nodevalue/NodeValueOps.java | 2 +- .../jena/sparql/expr/nodevalue/XSDFuncOp.java | 40 ++++++++++++++++++++-- .../org/apache/jena/sparql/function/CastXSD.java | 9 +++-- .../org/apache/jena/sparql/expr/LibTestExpr.java | 4 +-- .../jena/sparql/expr/TestExpressionsMath.java | 16 ++++----- .../jena/sparql/expr/TestLeviathanFunctions.java | 2 +- 9 files changed, 80 insertions(+), 25 deletions(-) diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java index 26fc926e66..e127b4aaf0 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java @@ -106,19 +106,35 @@ public abstract class NodeValue extends ExprNode public static final NodeValue TRUE = NodeValue.makeNode("true", XSDboolean); public static final NodeValue FALSE = NodeValue.makeNode("false", XSDboolean); + public static final NodeValue nvEmptyString = NodeValue.makeString(""); + public static final NodeValue nvZERO = NodeValue.makeNode(NodeConst.nodeZero); - public static final NodeValue nvNegZERO = NodeValue.makeNode("-0.0e0", XSDdouble); public static final NodeValue nvONE = NodeValue.makeNode(NodeConst.nodeOne); public static final NodeValue nvTEN = NodeValue.makeNode(NodeConst.nodeTen); public static final NodeValue nvDecimalZERO = NodeValue.makeNode("0.0", XSDdecimal); public static final NodeValue nvDecimalONE = NodeValue.makeNode("1.0", XSDdecimal); - public static final NodeValue nvNaN = NodeValue.makeNode("NaN", XSDdouble); - public static final NodeValue nvINF = NodeValue.makeNode("INF", XSDdouble); - public static final NodeValue nvNegINF = NodeValue.makeNode("-INF",XSDdouble); + public static final NodeValue nvDoubleNegZERO = NodeValue.makeNode("-0.0e0", XSDdouble); + public static final NodeValue nvDoubleNaN = NodeValue.makeNode("NaN", XSDdouble); + public static final NodeValue nvDoubleINF = NodeValue.makeNode("INF", XSDdouble); + public static final NodeValue nvDoubleNegINF = NodeValue.makeNode("-INF",XSDdouble); - public static final NodeValue nvEmptyString = NodeValue.makeString(""); + /** @deprecated Use {@link #nvDoubleNegZERO} */ + @Deprecated + public static final NodeValue nvNegZERO = nvDoubleNegZERO; + + /** @deprecated Use {@link #nvDoubleNaN} */ + @Deprecated + public static final NodeValue nvNaN = nvDoubleNaN; + + /** @deprecated Use {@link #nvDoubleINF} */ + @Deprecated + public static final NodeValue nvINF = nvDoubleINF; + + /** @deprecated Use {@link #nvDoubleNegINF} */ + @Deprecated + public static final NodeValue nvNegINF = nvDoubleNegINF; public static final String xsdNamespace = XSD+"#"; @@ -605,7 +621,7 @@ public abstract class NodeValue extends ExprNode // Java equals, not "same value" or "same term" if ( other == null ) return false; if ( this == other ) return true; - // This is the equality condition Jena uses - lang tags are different by case. + // This is the equality condition Jena uses if ( ! ( other instanceof NodeValue nv) ) return false; return asNode().equals(nv.asNode()); diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueDouble.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueDouble.java index 0351f913d7..5e404a7141 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueDouble.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueDouble.java @@ -31,7 +31,7 @@ import org.apache.jena.sparql.util.XSDNumUtils; public class NodeValueDouble extends NodeValue { - double value = Double.NaN; + private final double value; public NodeValueDouble(double d) { super(); value = d; } public NodeValueDouble(double d, Node n) { super(n); value = d; } diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueFloat.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueFloat.java index 20cfc14dea..0b32c89a86 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueFloat.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueFloat.java @@ -26,7 +26,7 @@ import org.apache.jena.sparql.util.XSDNumUtils; public class NodeValueFloat extends NodeValue { - float value = Float.NaN; + private final float value; public NodeValueFloat(float f) { super(); value = f; } public NodeValueFloat(float f, Node n) { super(n); value = f; } diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueOps.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueOps.java index b11cbc79ad..5b397efb6f 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueOps.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueOps.java @@ -40,7 +40,7 @@ import org.apache.jena.sparql.util.NodeUtils; * Operations relating to {@link NodeValue NodeValues}. * <ul> * <li>The code parts of arithmetic operations on {@link NodeValue}s. - * <li>Library code such as Argument testing + * <li>Library code such as expression string argument testing * </ul> * <p> * This class is not considered to be part of the ARQ API. diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/XSDFuncOp.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/XSDFuncOp.java index 6bfc904fe1..6fd848817d 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/XSDFuncOp.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/XSDFuncOp.java @@ -397,14 +397,50 @@ public class XSDFuncOp dec = v.getDecimal().setScale(0, RoundingMode.HALF_UP); return NodeValue.makeDecimal(dec); case OP_FLOAT: - return NodeValue.makeFloat(Math.round(v.getFloat())); + return NodeValue.makeFloat(roundFloat(v.getFloat())); case OP_DOUBLE: - return NodeValue.makeDouble(Math.round(v.getDouble())); + return NodeValue.makeDouble(roundDouble(v.getDouble())); default: throw new ARQInternalErrorException("Unrecognized numeric operation : " + v); } } + private static double roundDouble(double d) { + if ( Double.isNaN(d) ) + return Double.NaN; + if ( d == Double.POSITIVE_INFINITY ) + return d; + if ( d == Double.NEGATIVE_INFINITY ) + return d; + if ( d == -0.0e0 ) + return d; + // Math.round returns a java long + long resultLong = Math.round(d); + if ( resultLong == 0 && d < 0 ) + // Return -0 for round negative to 0. + return -0.0e0d; + // Cast to double by the return. + return resultLong; + } + + private static float roundFloat(float f) { + if ( Float.isNaN(f) ) + return Float.NaN; + if ( f == Float.POSITIVE_INFINITY ) + return f; + if ( f == Float.NEGATIVE_INFINITY ) + return f; + if ( f == -0.0e0f ) + return f; + // Math.round returns a java long + long resultLong = Math.round(f); + if ( resultLong == 0 && f < 0 ) + // Return -0 for round negative to 0. + return -0.0e0f; + // Math.round returns a java long, which is cast to float by the return. + return resultLong; + } + // The following function 'roundXpath3' implements the definition for "fn:round" in F&O v3. // This is different to the "fn:round" in F&O v2. // SPARQL 1.1 references F&O v2. diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/function/CastXSD.java b/jena-arq/src/main/java/org/apache/jena/sparql/function/CastXSD.java index ae43940b2c..07362c4142 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/function/CastXSD.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/function/CastXSD.java @@ -18,8 +18,8 @@ package org.apache.jena.sparql.function; -import static org.apache.jena.sparql.expr.NodeValue.nvNaN; -import static org.apache.jena.sparql.expr.NodeValue.nvNegZERO; +import static org.apache.jena.sparql.expr.NodeValue.nvDoubleNaN; +import static org.apache.jena.sparql.expr.NodeValue.nvDoubleNegZERO; import static org.apache.jena.sparql.expr.NodeValue.nvZERO; import static org.apache.jena.sparql.expr.nodevalue.XSDFuncOp.*; import java.math.BigDecimal; @@ -273,7 +273,10 @@ public class CastXSD { if ( nv.isBoolean() ) return nv; if ( nv.isNumber() ) { - if ( NodeValue.sameValueAs(nv, nvZERO) || NodeValue.sameValueAs(nv, nvNaN) || NodeValue.sameValueAs(nv, nvNegZERO) ) + if ( NodeValue.sameValueAs(nv, nvZERO) ) + return NodeValue.FALSE; + // sameValueAs Covers xsd:float + if ( NodeValue.sameValueAs(nv, nvDoubleNaN) || NodeValue.sameValueAs(nv, nvDoubleNegZERO) ) return NodeValue.FALSE; return NodeValue.TRUE; } diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/LibTestExpr.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/LibTestExpr.java index b56dec1871..44e455442b 100644 --- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/LibTestExpr.java +++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/LibTestExpr.java @@ -94,8 +94,8 @@ public class LibTestExpr { assertTrue(sameValueSameDatatype(expected, actual), ()->"Expected = " + expected + " : Actual = " + actual); } - public static void testIsNaN(String exprStr) { - testSameObject(exprStr, NodeValue.nvNaN); + public static void testDoubleIsNaN(String exprStr) { + testSameObject(exprStr, NodeValue.nvDoubleNaN); } public static void testSameObject(String exprStr, NodeValue expected) { diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExpressionsMath.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExpressionsMath.java index 13e8aa18e7..d8392350f9 100644 --- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExpressionsMath.java +++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExpressionsMath.java @@ -20,7 +20,7 @@ package org.apache.jena.sparql.expr; import static org.apache.jena.sparql.expr.LibTestExpr.test; import static org.apache.jena.sparql.expr.LibTestExpr.testDouble; -import static org.apache.jena.sparql.expr.LibTestExpr.testIsNaN; +import static org.apache.jena.sparql.expr.LibTestExpr.testDoubleIsNaN; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Test; @@ -41,7 +41,7 @@ public class TestExpressionsMath @Test public void exp_04() { test("math:exp(1e0/0)", "'INF'^^xsd:double"); } @Test public void exp_05() { test("math:exp('INF'^^xsd:double)", "'INF'^^xsd:double"); } @Test public void exp_06() { test("math:exp('-INF'^^xsd:double)", "'0.0e0'^^xsd:double"); } - @Test public void exp_07() { testIsNaN("math:exp('NaN'^^xsd:double)"); } + @Test public void exp_07() { testDoubleIsNaN("math:exp('NaN'^^xsd:double)"); } @Test public void exp10_01() { test("math:exp10(2)", "100"); } @Test public void exp10_02() { testDouble("math:exp10(-1)", 0.1, 0.00001); } @@ -55,7 +55,7 @@ public class TestExpressionsMath @Test public void log_04() { test("math:log(0)", "'-INF'^^xsd:double"); } @Test public void log_05() { test("math:exp('INF'^^xsd:double)", "'INF'^^xsd:double"); } @Test public void log_06() { test("math:exp('-INF'^^xsd:double)", "'0.0e0'^^xsd:double"); } - @Test public void log_07() { testIsNaN("math:exp('NaN'^^xsd:double)"); } + @Test public void log_07() { testDoubleIsNaN("math:exp('NaN'^^xsd:double)"); } @Test public void pow_01() { test("math:pow(2,2)", "4"); } @Test public void pow_02() { testDouble("math:pow(2,-2)", 0.25, 0.00001); } @@ -67,18 +67,18 @@ public class TestExpressionsMath @Test public void pow_13() { test("math:pow('INF'^^xsd:double,0)", "'1.0e0'^^xsd:double"); } @Test public void pow_14() { test("math:pow('-INF'^^xsd:double, 0)", "'1.0e0'^^xsd:double"); } - @Test public void pow_15() { testIsNaN("math:pow('NaN'^^xsd:double, 1)"); } - @Test public void pow_16() { testIsNaN("math:pow(1, 'NaN'^^xsd:double)"); } + @Test public void pow_15() { testDoubleIsNaN("math:pow('NaN'^^xsd:double, 1)"); } + @Test public void pow_16() { testDoubleIsNaN("math:pow(1, 'NaN'^^xsd:double)"); } @Test public void sqrt_01() { test("math:sqrt(1)", "'1.0e0'^^xsd:double"); } @Test public void sqrt_02() { testDouble("math:sqrt(2)", Math.sqrt(2), 0.000001); } - @Test public void sqrt_03() { testIsNaN("math:sqrt(-2)"); } + @Test public void sqrt_03() { testDoubleIsNaN("math:sqrt(-2)"); } @Test public void sqrt_04() { assertThrows(ARQException.class, ()->test("math:sqrt('TWO')", "'dummy'")); } @Test public void sqrt_10() { test("math:sqrt('INF'^^xsd:double)", "'INF'^^xsd:double"); } - @Test public void sqrt_11() { testIsNaN("math:sqrt('-INF'^^xsd:double)"); } - @Test public void sqrt_12() { testIsNaN("math:sqrt('NaN'^^xsd:double)"); } + @Test public void sqrt_11() { testDoubleIsNaN("math:sqrt('-INF'^^xsd:double)"); } + @Test public void sqrt_12() { testDoubleIsNaN("math:sqrt('NaN'^^xsd:double)"); } // 4.8.7 math:sqrt // 4.8.8 math:sin diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestLeviathanFunctions.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestLeviathanFunctions.java index 55e06dc527..bf10c8c831 100644 --- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestLeviathanFunctions.java +++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestLeviathanFunctions.java @@ -135,7 +135,7 @@ public class TestLeviathanFunctions { public void log_03() { NodeValue actual = LibTestExpr.eval("lfn:log(-1)"); // Test the object, not the value. - assertTrue(NodeValue.nvNaN.equals(actual)); + assertTrue(NodeValue.nvDoubleNaN.equals(actual)); } @Test
