sunchao commented on code in PR #6595:
URL: https://github.com/apache/datafusion-comet/pull/6595#discussion_r4193614955


##########
native/spark-expr/src/conversion_funcs/string.rs:
##########
@@ -254,7 +255,44 @@ where
         } else {
             s
         };
-    // Rust's parse logic already handles scientific notations so we just rely 
on it
+    let unsigned = pruned_float_str
+        .strip_prefix(['+', '-'])
+        .unwrap_or(pruned_float_str);
+    if unsigned.starts_with("0x") || unsigned.starts_with("0X") {
+        // lexical 1.0.6's fast path cannot mix radix 16 with a binary 
exponent. Expand
+        // only the significand, preserving exact bits and rounding at the 
target width.
+        // Remove after https://github.com/Alexhuszagh/rust-lexical/issues/87 
is fixed.
+        let (mantissa, exponent) = unsigned[2..].split_once(['p', 'P'])?;
+        let mut binary = String::new();
+        if pruned_float_str.starts_with('-') {
+            binary.push('-');
+        }
+        for digit in mantissa.bytes() {
+            if digit == b'.' {
+                binary.push('.');
+            } else {
+                let digit = char::from(digit).to_digit(16)?;
+                for bit in (0..4).rev() {
+                    binary.push(char::from(b'0' + ((digit >> bit) & 1) as u8));
+                }
+            }
+        }
+        binary.push('p');
+        binary.push_str(exponent);
+        const BINARY: u128 = NumberFormatBuilder::new()
+            .mantissa_radix(2)
+            .exponent_base(std::num::NonZeroU8::new(2))
+            .exponent_radix(std::num::NonZeroU8::new(10))
+            .required_exponent_notation(true)
+            .no_special(true)
+            .build_strict();
+        return F::from_lexical_with_options::<BINARY>(

Review Comment:
   [P2] Preserve zero significands when hexadecimal exponents are large. With 
`spark.sql.variant.pushVariantIntoScan=false`, store `parse_json('"0x0p1100"')` 
in a Parquet Variant column `v`, then select `try_variant_get(v, '$', 
'double')`. Spark returns `0.0`, but the new parser returns infinity. Strict 
extraction also accepts that incorrect value, and `-0x0p1100` becomes negative 
infinity instead of negative zero. These previously correct fallback queries 
now silently change results. Handle validated zero significands before exponent 
scaling, preserving the sign, and add FLOAT/DOUBLE regressions.
   
   Evidence: A release-mode reproduction using the exact head’s unchanged 
`parse_string_to_float` and pinned `lexical-parse-float` 1.0.6 returned DOUBLE 
bits `7ff0000000000000` for `0x0p1100` and `fff0000000000000` for `-0x0p1100`. 
Direct `VariantGet.variantGet` calls on Spark 4.1.3 and 4.2.0 returned bits 
`0000000000000000` and `8000000000000000` in both strict and TRY modes. An 
exact-head native `VariantGet::evaluate_array` probe with `0x0p157` targeting 
FLOAT additionally panicked at `lexical-parse-float/src/binary.rs:40` in the 
debug build. The release parser returned FLOAT infinity for that input.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to