From ed27558efe99095eec326e1a4cd560cc71b0b707 Mon Sep 17 00:00:00 2001 From: Nic Crane Date: Thu, 9 Jul 2026 14:34:51 +0100 Subject: [PATCH 1/3] Add float16 logic --- r/src/array_to_vector.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/r/src/array_to_vector.cpp b/r/src/array_to_vector.cpp index dc02c711d1eb..8b617e6709d6 100644 --- a/r/src/array_to_vector.cpp +++ b/r/src/array_to_vector.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -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(p_values[i]); + if constexpr (std::is_same_v) { + p_data[i] = arrow::util::Float16::FromBits(p_values[i]).ToDouble(); + } else { + p_data[i] = static_cast(p_values[i]); + } return Status::OK(); }; auto null_one = [&](R_xlen_t i) { From c39308d19b34df94140283b7f72628488c6d2219 Mon Sep 17 00:00:00 2001 From: Nic Crane Date: Thu, 9 Jul 2026 15:22:40 +0000 Subject: [PATCH 2/3] add float16 into tests --- r/src/r_to_arrow.cpp | 5 +++-- r/tests/testthat/test-chunked-array.R | 2 +- r/tests/testthat/test-dplyr-funcs-type.R | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/r/src/r_to_arrow.cpp b/r/src/r_to_arrow.cpp index cbe404aba962..9a26a2c3df7a 100644 --- a/r/src/r_to_arrow.cpp +++ b/r/src/r_to_arrow.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "./r_task_group.h" @@ -390,12 +391,12 @@ struct RConvert { return static_cast(from); } - // ---- convert to half float: not implemented + // ---- convert to half float template static enable_if_t::value, Result> Convert(Type*, From from) { - return Status::Invalid("Cannot convert to Half Float"); + return arrow::util::Float16(static_cast(from)).bits(); } }; diff --git a/r/tests/testthat/test-chunked-array.R b/r/tests/testthat/test-chunked-array.R index bcadaa889f90..74bc3f61d2a4 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) { diff --git a/r/tests/testthat/test-dplyr-funcs-type.R b/r/tests/testthat/test-dplyr-funcs-type.R index e2adf1de3ef2..81e6f74ddba6 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, From 9d0c3798f80ed7eea340ec15c783d5c18ab379b2 Mon Sep 17 00:00:00 2001 From: Nic Crane Date: Tue, 18 Aug 2026 13:32:22 +0100 Subject: [PATCH 3/3] Add extra tests --- r/tests/testthat/test-chunked-array.R | 12 ++++++++++++ r/tests/testthat/test-dplyr-funcs-type.R | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/r/tests/testthat/test-chunked-array.R b/r/tests/testthat/test-chunked-array.R index 74bc3f61d2a4..e5fcfefe9045 100644 --- a/r/tests/testthat/test-chunked-array.R +++ b/r/tests/testthat/test-chunked-array.R @@ -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 81e6f74ddba6..928a0e3d2412 100644 --- a/r/tests/testthat/test-dplyr-funcs-type.R +++ b/r/tests/testthat/test-dplyr-funcs-type.R @@ -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) +})