This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/master by this push:
new efa2a7a JENA-1674: Don't sign extend Float.floatToIntBits.
new d5545fe Merge pull request #535 from afs/tdb2-xsd_float
efa2a7a is described below
commit efa2a7ac19ec148812f29634225a79f40e82f864
Author: Andy Seaborne <[email protected]>
AuthorDate: Wed Feb 20 21:01:59 2019 +0000
JENA-1674: Don't sign extend Float.floatToIntBits.
Add TestFloatNode for value-based testing of FloatNode.
Use canonical NaN for packing Double.NaN.
---
.../apache/jena/tdb2/store/value/DoubleNode62.java | 39 +++++++++++------
.../apache/jena/tdb2/store/value/FloatNode.java | 7 +++-
.../java/org/apache/jena/tdb2/store/TS_Store.java | 2 +
.../jena/tdb2/store/value/TestDoubleNode62.java | 43 +++++++------------
.../jena/tdb2/store/value/TestFloatNode.java | 49 ++++++++++++++++++++++
.../jena/tdb2/store/value/TestNodeIdInline.java | 18 ++++++++
6 files changed, 115 insertions(+), 43 deletions(-)
diff --git
a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DoubleNode62.java
b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DoubleNode62.java
index ac3d68e..8ae4929 100644
---
a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DoubleNode62.java
+++
b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DoubleNode62.java
@@ -26,37 +26,49 @@ import org.apache.jena.atlas.lib.BitsLong;
* Uses java's 64 bit long format (which is IEEE754 binary64) except that 2
bits are taken
* from the exponent. This keeps the precision but reduces the range.
* <p>
- * <b>Java
- * (<a
href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">IEEE
- * 754 binary64</a>)</b>
+ * <b>
+ * <a
href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">IEEE
754 binary64</a>
+ * </b>
*
* <pre>
- * bit 63 : sign bit
+ * bit 63 : sign bit
* bits 52-62 : exponent, 11 bits, the power of 2, bias -1023.
* bits 0-51 : mantissa (significand) 52 bits (the leading one is not stored).
*
* Exponents are 11 bits, with values -1022 to +1023 held as 1 to 2046 (11
bits, bias -1023)
+ * Exponents 0x000 and 0x7ff have a special meaning:
* 0x000 is signed zero.
- * 0x7FF is +/- infinity.
+ * 0x7FF is +/- infinity when the mantissa is zero
+ * 0x7FF is NaN if the the mantissa is not zero
+ * The canonical NaN is 0x7FF8000000000000L, i.e. mantissa 0x8000...
+ * The different NaN values.
* </pre>
*
- * for a maximum value of 1.797693e+308 = (2-2^-52)*2^1023 and smallest
denormlized of
+ * The different NaN bit patterns are not distinguishable in Java
+ * by floating point operations, only by {@link Double#doubleToRawLongBits}.
+ *
+ * The maximum value is 1.797693e+308 = (2-2^-52)*2^1023 and smallest
denormalized of
* (1-2^-52)*2^-1022 = 2.225...e-308.
* <p>
* <b>DoubleNode62</b>
* <p>
* In a 62 bit double:
- *
* <pre>
- * bit 63 : pointer bit.
- * bit 62 : double type bit.
- * bit 61 : sign bit
+ * <i>NodeId</i>
+ * bit 63 : pointer or value bit.
+ * bit 62 : double type bit
+ *
+ * <i>Double62</i>
+ * bit 61 : sign bit
* bits 52-60 : exponent, 9 bits, the power of 2, bias -255
* bits 0-51 : mantissa (significand) 52 bits (the leading one is not stored).
*
* Exponents are 9 bits, with values -254 to 255, held as 1 to 512 (9 bits,
bias -255)
+ * Exponents 0x000 and 0x1ff have a special meaning:
* 0x000 is signed zero.
- * 0x1FF is +/- infinity.
+ * 0x1FF is +/- infinity if the mantissa is zero
+ * 0x1FF is NaN if the the mantissa is not zero
+ * The canonical NaN is 0x1FF8000000000000L, i.e. mantissa 0x8000...
* </pre>
*
* for a maximum value of (2-2^-52)*2^255 = 1.157921e+77 and smallest
denormlized of
@@ -66,7 +78,7 @@ import org.apache.jena.atlas.lib.BitsLong;
* <p>
* "No encoding" is 0xFF00_0000_0000_0000L which would otherwise be the
smallest (most negative) denormalized value:
* -3.5336941295567687E72
- * <p>All unencodeable numbers will endup in the node table in full lexical
form.
+ * <p>All unencodeable numbers will end up in the node table in full lexical
form.
*/
public class DoubleNode62 {
/**
@@ -80,7 +92,8 @@ public class DoubleNode62 {
* The top two bits are zero if packing was possible.
*/
public static long pack(double v) {
- long x = Double.doubleToRawLongBits(v);
+ // Not "raw" , so NaNs end up as the same bit pattern when packed.
+ long x = Double.doubleToLongBits(v);
long sign = BitsLong.unpack(x, 63, 64);
long exp11 = BitsLong.unpack(x, 52, 63);
long exp9 = encode11to9(exp11);
diff --git
a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/FloatNode.java
b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/FloatNode.java
index 2bf9d86..2bdd3c7 100644
---
a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/FloatNode.java
+++
b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/FloatNode.java
@@ -19,10 +19,15 @@
package org.apache.jena.tdb2.store.value;
public class FloatNode {
+ // Floats,being 32 bits are always encodable.
+ //public static long NO_ENCODING = 0xFF00_0000_0000_0000L;
+
// 32 bits of value; collapses NaNs to a single value.
public static long pack(float v) {
- return Float.floatToIntBits(v);
+ // Not "raw" , so NaNs end up as the same bit pattern when packed.
+ int x = Float.floatToIntBits(v);
+ return Integer.toUnsignedLong(x);
}
public static float unpack(long v) {
diff --git
a/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/TS_Store.java
b/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/TS_Store.java
index f4ee83d..40e323d 100644
--- a/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/TS_Store.java
+++ b/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/TS_Store.java
@@ -20,6 +20,7 @@ package org.apache.jena.tdb2.store;
import org.apache.jena.dboe.base.block.FileMode;
import org.apache.jena.tdb2.store.value.TestDoubleNode62;
+import org.apache.jena.tdb2.store.value.TestFloatNode;
import org.apache.jena.tdb2.store.value.TestNodeIdInline;
import org.apache.jena.tdb2.sys.SystemTDB;
import org.apache.jena.tdb2.sys.TestOps;
@@ -33,6 +34,7 @@ import org.junit.runners.Suite ;
TestNodeId.class
, TestNodeIdInline.class
, TestDoubleNode62.class
+ , TestFloatNode.class
, TestTripleTable.class
, TestGraphTDB.class
, TestGraphNamedTDB.class
diff --git
a/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestDoubleNode62.java
b/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestDoubleNode62.java
index a2a6b0e..651acda 100644
---
a/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestDoubleNode62.java
+++
b/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestDoubleNode62.java
@@ -25,6 +25,7 @@ import org.junit.Test;
import static org.junit.Assert.*;
public class TestDoubleNode62 {
+ // See also TestNodeIdInline.nodeId_double_*
@Test public void double_01() { testRoundTripDouble(1d); }
@Test public void double_02() { testRoundTripDouble(-1d); }
@Test public void double_03() { testRoundTripDouble(-1111111111e50d); }
@@ -49,14 +50,18 @@ public class TestDoubleNode62 {
@Test public void double_22() { testRoundTripDouble(Double.NaN); }
@Test public void double_23() { testNoEncoding(Double.MAX_VALUE); }
@Test public void double_24() { testNoEncoding(Double.MIN_NORMAL); }
- @Test public void double_25() { testNoEncoding(Double.MIN_VALUE); }
+ // Despite being out of the normal range of DoubleNode62,
+ // this does encode and round trip even though out of range.
+ // Its encoding is long value 1.
+ @Test public void double_25() { testRoundTripDouble(Double.MIN_VALUE); }
@Test public void double_30() {
testRoundTripDouble(DoubleNode62.POSITIVE_INFINITY); }
@Test public void double_31() {
testRoundTripDouble(DoubleNode62.NEGATIVE_INFINITY); }
@Test public void double_32() { testRoundTripDouble(DoubleNode62.NaN); }
- @Test public void double_33() { testNoEncoding(DoubleNode62.MAX_VALUE); }
- @Test public void double_34() { testNoEncoding(DoubleNode62.MIN_NORMAL); }
- @Test public void double_35() { testNoEncoding(DoubleNode62.MIN_VALUE); }
+
+ @Test public void double_33() {
testRoundTripDouble(DoubleNode62.MAX_VALUE); }
+ @Test public void double_34() {
testRoundTripDouble(DoubleNode62.MIN_NORMAL); }
+ @Test public void double_35() {
testRoundTripDouble(DoubleNode62.MIN_VALUE); }
@Test public void double_40() { sameValue(DoubleNode62.POSITIVE_INFINITY,
Double.POSITIVE_INFINITY); }
@Test public void double_41() { sameValue(DoubleNode62.NEGATIVE_INFINITY,
Double.NEGATIVE_INFINITY); }
@@ -70,13 +75,11 @@ public class TestDoubleNode62 {
@Test public void double_55() { testConst(DoubleNode62.MIN_VALUE_BITS,
0x01L); }
private void sameValue(double d1, double d2) {
- // Not d1 == d2 - NaN != NaN
+ // Not d1 == d2 because NaN != NaN
assertEquals(Double.valueOf(d1), Double.valueOf(d2));
}
private static void testConst(long x, long expected) {
- //print(expected);
- //print(x);
assertEquals(expected, x);
double d = DoubleNode62.unpack(x);
long z = DoubleNode62.pack(d);
@@ -84,33 +87,15 @@ public class TestDoubleNode62 {
}
private void testNoEncoding(double d) {
- testRoundTripDouble(d, false);
+ long x = DoubleNode62.pack(d);
+ assertEquals("Expected no encoding", x, DoubleNode62.NO_ENCODING);
}
private static void testRoundTripDouble(double d) {
- testRoundTripDouble(d, true);
- }
-
- private static void testRoundTripDouble(double d, boolean valid) {
- //System.out.printf("Double: %.2e\n", d);
- long x0 = Double.doubleToRawLongBits(d);
- //print(x0);
long x = DoubleNode62.pack(d);
- //print(x);
- if ( x == DoubleNode62.NO_ENCODING ) {
- if ( valid )
- fail("Expect no encoding");
-
- //System.out.println("No encoding");
- //System.out.println();
- return;
- }
-
+ assertNotEquals("Expected encoding", x, DoubleNode62.NO_ENCODING);
double d2 = DoubleNode62.unpack(x);
-
- Double double1 = d ;
- Double double2 = d2 ;
- assertEquals(double1, double2);
+ assertEquals(d, d2, 0);
}
private static void print(long x) {
diff --git
a/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestFloatNode.java
b/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestFloatNode.java
new file mode 100644
index 0000000..a8a95d7
--- /dev/null
+++
b/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestFloatNode.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.tdb2.store.value;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class TestFloatNode {
+ // Floats can always be encoded.
+ // See also TestNodeIdInline.nodeId_float_*
+ @Test public void float_01() { testRoundTripFloat(1f); }
+ @Test public void float_02() { testRoundTripFloat(-1f); }
+ @Test public void float_03() { testRoundTripFloat(-1111111111e20f); }
+ @Test public void float_04() { testRoundTripFloat(1111111111e20f); }
+
+ @Test public void float_10() {
testRoundTripFloat(Float.POSITIVE_INFINITY); }
+ @Test public void float_11() {
testRoundTripFloat(Float.NEGATIVE_INFINITY); }
+ @Test public void float_12() { testRoundTripFloat(Float.NaN); }
+ @Test public void float_13() { testRoundTripFloat(Float.MAX_VALUE); }
+ @Test public void float_14() { testRoundTripFloat(Float.MIN_NORMAL); }
+ @Test public void float_15() { testRoundTripFloat(Float.MIN_VALUE); }
+
+ private static void testRoundTripFloat(float f) {
+ long x0 = Float.floatToRawIntBits(f);
+ long x = FloatNode.pack(f);
+ // No high part.
+ assertTrue( (x & 0xFFFFFFFF00000000L) == 0 );
+ float f2 = FloatNode.unpack(x);
+ assertEquals(f, f2, 0);
+ }
+}
diff --git
a/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestNodeIdInline.java
b/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestNodeIdInline.java
index 519d635..96c3bf8 100644
---
a/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestNodeIdInline.java
+++
b/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestNodeIdInline.java
@@ -257,6 +257,24 @@ public class TestNodeIdInline
@Test public void nodeId_float_5()
{ test("'1.1E9'^^xsd:float") ; }
+ @Test public void nodeId_float_6()
+ { test("'-1'^^xsd:float", "'-1.0'^^xsd:float") ; }
+
+ @Test public void nodeId_float_7()
+ { test("'-1.0'^^xsd:float") ; }
+
+ @Test public void nodeId_float_8()
+ { test("'-0.0'^^xsd:float") ; }
+
+ @Test public void nodeId_float_9()
+ { test("'INF'^^xsd:float") ; }
+
+ @Test public void nodeId_float_10()
+ { test("'-INF'^^xsd:float") ; }
+
+ @Test public void nodeId_float_11()
+ { test("'NaN'^^xsd:float") ; }
+
private void test(String x) { test(x, x) ; }
private void test(String x, String expected) {