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

thisisnic pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new be3f4208eb GH-50378: [R] Reading a parquet with a Float16 column 
yields incorrect value (#50451)
be3f4208eb is described below

commit be3f4208eb07e72495ce444f806d94601f07a62a
Author: Nic Crane <[email protected]>
AuthorDate: Thu Sep 3 15:16:45 2026 +0100

    GH-50378: [R] Reading a parquet with a Float16 column yields incorrect 
value (#50451)
    
    ### Rationale for this change
    
    Wrong values reading Parquet files with float16s in them as we were 
returning the raw bytes not the float value
    
    ### What changes are included in this PR?
    
    Return the float value. Also enabling float16 in a lot of our tests.
    
    ### Are these changes tested?
    
    Aye
    
    ### Are there any user-facing changes?
    
    Nah
    * GitHub Issue: #50378
    
    Authored-by: Nic Crane <[email protected]>
    Signed-off-by: Nic Crane <[email protected]>
---
 r/src/array_to_vector.cpp                |  7 ++++++-
 r/src/r_to_arrow.cpp                     |  5 +++--
 r/tests/testthat/test-chunked-array.R    | 14 +++++++++++++-
 r/tests/testthat/test-dplyr-funcs-type.R | 13 ++++++++++++-
 4 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/r/src/array_to_vector.cpp b/r/src/array_to_vector.cpp
index dc02c711d1..8b617e6709 100644
--- a/r/src/array_to_vector.cpp
+++ b/r/src/array_to_vector.cpp
@@ -23,6 +23,7 @@
 #include <arrow/table.h>
 #include <arrow/util/bitmap_reader.h>
 #include <arrow/util/bitmap_writer.h>
+#include <arrow/util/float16.h>
 #include <arrow/util/int_util.h>
 
 #include <type_traits>
@@ -224,7 +225,11 @@ class Converter_Double : public Converter {
     }
     auto p_data = REAL(data) + start;
     auto ingest_one = [&](R_xlen_t i) {
-      p_data[i] = static_cast<value_type>(p_values[i]);
+      if constexpr (std::is_same_v<Type, HalfFloatType>) {
+        p_data[i] = arrow::util::Float16::FromBits(p_values[i]).ToDouble();
+      } else {
+        p_data[i] = static_cast<value_type>(p_values[i]);
+      }
       return Status::OK();
     };
     auto null_one = [&](R_xlen_t i) {
diff --git a/r/src/r_to_arrow.cpp b/r/src/r_to_arrow.cpp
index cbe404aba9..9a26a2c3df 100644
--- a/r/src/r_to_arrow.cpp
+++ b/r/src/r_to_arrow.cpp
@@ -29,6 +29,7 @@
 #include <arrow/util/bitmap_writer.h>
 #include <arrow/util/checked_cast.h>
 #include <arrow/util/converter.h>
+#include <arrow/util/float16.h>
 #include <arrow/util/logging.h>
 
 #include "./r_task_group.h"
@@ -390,12 +391,12 @@ struct RConvert {
     return static_cast<float>(from);
   }
 
-  // ---- convert to half float: not implemented
+  // ---- convert to half float
   template <typename Type, typename From>
   static enable_if_t<std::is_same<Type, const HalfFloatType>::value,
                      Result<typename Type::c_type>>
   Convert(Type*, From from) {
-    return Status::Invalid("Cannot convert to Half Float");
+    return arrow::util::Float16(static_cast<double>(from)).bits();
   }
 };
 
diff --git a/r/tests/testthat/test-chunked-array.R 
b/r/tests/testthat/test-chunked-array.R
index bcadaa889f..e5fcfefe90 100644
--- a/r/tests/testthat/test-chunked-array.R
+++ b/r/tests/testthat/test-chunked-array.R
@@ -17,7 +17,7 @@
 
 int_types <- c(int8(), int16(), int32(), int64())
 uint_types <- c(uint8(), uint16(), uint32(), uint64())
-float_types <- c(float32(), float64()) # float16() not really supported in C++ 
yet
+float_types <- c(float16(), float32(), float64())
 all_numeric_types <- c(int_types, uint_types, float_types)
 
 expect_chunked_roundtrip <- function(x, type) {
@@ -549,3 +549,15 @@ test_that("as_chunked_array() works for Array", {
     chunked_array(Array$create(1:6, type = float64()))
   )
 })
+
+test_that("float16 values roundtrip to R correctly", {
+  # Values exactly representable in half-float, so the roundtrip is exact.
+  # Regression test for GH-50378 (values were previously decoded as raw uint16 
bits)
+  x <- c(1, 2, 3.5, NA, -0.25, 1024, Inf)
+  a <- chunked_array(x[1:4], x[5:7], type = float16())
+  expect_type_equal(a$type, float16())
+  expect_identical(a$num_chunks, 2L)
+  expect_as_vector(a, x)
+  expect_as_vector(a$chunk(1), x[5:7])
+  expect_as_vector(a$Slice(1), x[-1])
+})
diff --git a/r/tests/testthat/test-dplyr-funcs-type.R 
b/r/tests/testthat/test-dplyr-funcs-type.R
index e2adf1de3e..928a0e3d24 100644
--- a/r/tests/testthat/test-dplyr-funcs-type.R
+++ b/r/tests/testthat/test-dplyr-funcs-type.R
@@ -31,7 +31,7 @@ test_that("explicit type conversions with cast()", {
 
   int_types <- c(int8(), int16(), int32(), int64())
   uint_types <- c(uint8(), uint16(), uint32(), uint64())
-  float_types <- c(float32(), float64())
+  float_types <- c(float16(), float32(), float64())
 
   types <- c(
     int_types,
@@ -1064,3 +1064,14 @@ test_that("format() for unsupported types returns the 
input as string", {
       collect()
   )
 })
+
+test_that("cast to float16 roundtrips values correctly", {
+  # Values exactly representable in half-float, so the roundtrip is exact.
+  # Regression test for GH-50378 (values were previously decoded as raw uint16 
bits)
+  df <- tibble::tibble(x = c(1, 2, 3.5, -0.25, 1024, NA))
+  result <- df |>
+    arrow_table() |>
+    mutate(x = cast(x, float16())) |>
+    collect()
+  expect_identical(result$x, df$x)
+})

Reply via email to