HIVE-11174: Hive does not treat floating point signed zeros as equal (-0.0 should equal 0.0 according to IEEE floating point spec) (Sergio Pena, reviewed by Xuefu Zhang)
Project: http://git-wip-us.apache.org/repos/asf/hive/repo Commit: http://git-wip-us.apache.org/repos/asf/hive/commit/af4aeab9 Tree: http://git-wip-us.apache.org/repos/asf/hive/tree/af4aeab9 Diff: http://git-wip-us.apache.org/repos/asf/hive/diff/af4aeab9 Branch: refs/heads/beeline-cli Commit: af4aeab9c0dffc5f8e42428bf8b835dccc8771ef Parents: 6e0d480 Author: Sergio Pena <sergio.p...@cloudera.com> Authored: Wed Jul 15 09:47:06 2015 -0500 Committer: Sergio Pena <sergio.p...@cloudera.com> Committed: Wed Jul 15 09:47:06 2015 -0500 ---------------------------------------------------------------------- .../objectinspector/ObjectInspectorUtils.java | 18 ++++++++++++++-- .../TestObjectInspectorUtils.java | 22 ++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hive/blob/af4aeab9/serde/src/java/org/apache/hadoop/hive/serde2/objectinspector/ObjectInspectorUtils.java ---------------------------------------------------------------------- diff --git a/serde/src/java/org/apache/hadoop/hive/serde2/objectinspector/ObjectInspectorUtils.java b/serde/src/java/org/apache/hadoop/hive/serde2/objectinspector/ObjectInspectorUtils.java index 041d218..6ef9f5d 100644 --- a/serde/src/java/org/apache/hadoop/hive/serde2/objectinspector/ObjectInspectorUtils.java +++ b/serde/src/java/org/apache/hadoop/hive/serde2/objectinspector/ObjectInspectorUtils.java @@ -722,12 +722,26 @@ public final class ObjectInspectorUtils { case FLOAT: { float v1 = ((FloatObjectInspector) poi1).get(o1); float v2 = ((FloatObjectInspector) poi2).get(o2); - return Float.compare(v1, v2); + + // The IEEE 754 floating point spec specifies that signed -0.0 and 0.0 should be treated as equal. + if (v1 == 0.0f && v2 == 0.0f) { + return 0; + } else { + // Float.compare() treats -0.0 and 0.0 as different + return Float.compare(v1, v2); + } } case DOUBLE: { double v1 = ((DoubleObjectInspector) poi1).get(o1); double v2 = ((DoubleObjectInspector) poi2).get(o2); - return Double.compare(v1, v2); + + // The IEEE 754 floating point spec specifies that signed -0.0 and 0.0 should be treated as equal. + if (v1 == 0.0d && v2 == 0.0d) { + return 0; + } else { + // Double.compare() treats -0.0 and 0.0 as different + return Double.compare(v1, v2); + } } case STRING: { if (poi1.preferWritable() || poi2.preferWritable()) { http://git-wip-us.apache.org/repos/asf/hive/blob/af4aeab9/serde/src/test/org/apache/hadoop/hive/serde2/objectinspector/TestObjectInspectorUtils.java ---------------------------------------------------------------------- diff --git a/serde/src/test/org/apache/hadoop/hive/serde2/objectinspector/TestObjectInspectorUtils.java b/serde/src/test/org/apache/hadoop/hive/serde2/objectinspector/TestObjectInspectorUtils.java index f3fd6fa..ade0ef7 100644 --- a/serde/src/test/org/apache/hadoop/hive/serde2/objectinspector/TestObjectInspectorUtils.java +++ b/serde/src/test/org/apache/hadoop/hive/serde2/objectinspector/TestObjectInspectorUtils.java @@ -34,6 +34,28 @@ import org.apache.hadoop.hive.serde2.thrift.test.IntString; */ public class TestObjectInspectorUtils extends TestCase { + public void testCompareFloatingNumberSignedZero() { + PrimitiveObjectInspector doubleOI = PrimitiveObjectInspectorFactory + .getPrimitiveJavaObjectInspector(PrimitiveObjectInspector.PrimitiveCategory.DOUBLE); + + Double d1 = Double.valueOf("0.0"); + Double d2 = Double.valueOf("-0.0"); + assertEquals(0, ObjectInspectorUtils.compare(d1, doubleOI, d2, doubleOI)); + assertEquals(0, ObjectInspectorUtils.compare(d2, doubleOI, d1, doubleOI)); + assertEquals(0, ObjectInspectorUtils.compare(d1, doubleOI, d1, doubleOI)); + assertEquals(0, ObjectInspectorUtils.compare(d2, doubleOI, d2, doubleOI)); + + PrimitiveObjectInspector floatOI = PrimitiveObjectInspectorFactory + .getPrimitiveJavaObjectInspector(PrimitiveObjectInspector.PrimitiveCategory.FLOAT); + + Float f1 = Float.valueOf("0.0"); + Float f2 = Float.valueOf("-0.0"); + assertEquals(0, ObjectInspectorUtils.compare(f1, floatOI, f2, floatOI)); + assertEquals(0, ObjectInspectorUtils.compare(f2, floatOI, f1, floatOI)); + assertEquals(0, ObjectInspectorUtils.compare(f1, floatOI, f1, floatOI)); + assertEquals(0, ObjectInspectorUtils.compare(f2, floatOI, f2, floatOI)); + } + public void testObjectInspectorUtils() throws Throwable { try { ObjectInspector oi1 = ObjectInspectorFactory