This is an automated email from the ASF dual-hosted git repository.

liurenjie1024 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git


The following commit(s) were added to refs/heads/main by this push:
     new c74a27ac fix: fix float compare order (#1416)
c74a27ac is described below

commit c74a27ac0d77314926240d325701107e5360f836
Author: ZENOTME <[email protected]>
AuthorDate: Mon Jun 9 17:11:46 2025 +0800

    fix: fix float compare order (#1416)
    
    ## Which issue does this PR close?
    
    Closes #1415
    
    ## What changes are included in this PR?
    
    
    ## Are these changes tested?
    
    
    
    Co-authored-by: ZENOTME <[email protected]>
---
 crates/iceberg/src/spec/values.rs | 104 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 101 insertions(+), 3 deletions(-)

diff --git a/crates/iceberg/src/spec/values.rs 
b/crates/iceberg/src/spec/values.rs
index 786fe961..b005f7ab 100644
--- a/crates/iceberg/src/spec/values.rs
+++ b/crates/iceberg/src/spec/values.rs
@@ -20,6 +20,7 @@
  */
 
 use std::any::Any;
+use std::cmp::Ordering;
 use std::collections::HashMap;
 use std::fmt::{Display, Formatter};
 use std::hash::Hash;
@@ -29,7 +30,7 @@ use std::str::FromStr;
 pub use _serde::RawLiteral;
 use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
 use num_bigint::BigInt;
-use ordered_float::OrderedFloat;
+use ordered_float::{Float, OrderedFloat};
 use rust_decimal::Decimal;
 use rust_decimal::prelude::ToPrimitive;
 use serde::de::{
@@ -214,6 +215,36 @@ impl<'de> Deserialize<'de> for Datum {
     }
 }
 
+// Compare following iceberg float ordering rules:
+//  -NaN < -Infinity < -value < -0 < 0 < value < Infinity < NaN
+fn iceberg_float_cmp<T: Float>(a: T, b: T) -> Option<Ordering> {
+    if a.is_nan() && b.is_nan() {
+        return match (a.is_sign_negative(), b.is_sign_negative()) {
+            (true, false) => Some(Ordering::Less),
+            (false, true) => Some(Ordering::Greater),
+            _ => Some(Ordering::Equal),
+        };
+    }
+
+    if a.is_nan() {
+        return Some(if a.is_sign_negative() {
+            Ordering::Less
+        } else {
+            Ordering::Greater
+        });
+    }
+
+    if b.is_nan() {
+        return Some(if b.is_sign_negative() {
+            Ordering::Greater
+        } else {
+            Ordering::Less
+        });
+    }
+
+    a.partial_cmp(&b)
+}
+
 impl PartialOrd for Datum {
     fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
         match (&self.literal, &other.literal, &self.r#type, &other.r#type) {
@@ -241,13 +272,13 @@ impl PartialOrd for Datum {
                 PrimitiveLiteral::Float(other_val),
                 PrimitiveType::Float,
                 PrimitiveType::Float,
-            ) => val.partial_cmp(other_val),
+            ) => iceberg_float_cmp(*val, *other_val),
             (
                 PrimitiveLiteral::Double(val),
                 PrimitiveLiteral::Double(other_val),
                 PrimitiveType::Double,
                 PrimitiveType::Double,
-            ) => val.partial_cmp(other_val),
+            ) => iceberg_float_cmp(*val, *other_val),
             (
                 PrimitiveLiteral::Int(val),
                 PrimitiveLiteral::Int(other_val),
@@ -3845,4 +3876,71 @@ mod tests {
 
         assert_eq!(result, expected);
     }
+
+    #[test]
+    fn test_iceberg_float_order() {
+        // Test float ordering
+        let float_values = vec![
+            Datum::float(f32::NAN),
+            Datum::float(-f32::NAN),
+            Datum::float(f32::MAX),
+            Datum::float(f32::MIN),
+            Datum::float(f32::INFINITY),
+            Datum::float(-f32::INFINITY),
+            Datum::float(1.0),
+            Datum::float(-1.0),
+            Datum::float(0.0),
+            Datum::float(-0.0),
+        ];
+
+        let mut float_sorted = float_values.clone();
+        float_sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
+
+        let float_expected = vec![
+            Datum::float(-f32::NAN),
+            Datum::float(-f32::INFINITY),
+            Datum::float(f32::MIN),
+            Datum::float(-1.0),
+            Datum::float(-0.0),
+            Datum::float(0.0),
+            Datum::float(1.0),
+            Datum::float(f32::MAX),
+            Datum::float(f32::INFINITY),
+            Datum::float(f32::NAN),
+        ];
+
+        assert_eq!(float_sorted, float_expected);
+
+        // Test double ordering
+        let double_values = vec![
+            Datum::double(f64::NAN),
+            Datum::double(-f64::NAN),
+            Datum::double(f64::INFINITY),
+            Datum::double(-f64::INFINITY),
+            Datum::double(f64::MAX),
+            Datum::double(f64::MIN),
+            Datum::double(1.0),
+            Datum::double(-1.0),
+            Datum::double(0.0),
+            Datum::double(-0.0),
+        ];
+
+        let mut double_sorted = double_values.clone();
+        double_sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
+
+        let double_expected = vec![
+            Datum::double(-f64::NAN),
+            Datum::double(-f64::INFINITY),
+            Datum::double(f64::MIN),
+            Datum::double(-1.0),
+            Datum::double(-0.0),
+            Datum::double(0.0),
+            Datum::double(1.0),
+            Datum::double(f64::MAX),
+            Datum::double(f64::INFINITY),
+            Datum::double(f64::NAN),
+        ];
+
+        assert_eq!(double_sorted, double_expected);
+    }
 }

Reply via email to