miguelcorderopamphile opened a new issue, #11316:
URL: https://github.com/apache/arrow-rs/issues/11316

   ### Describe the bug
   
   `i256` only implements `ToPrimitive::to_f64`, so `ToPrimitive::to_f32` falls 
back to the default `to_f64() as f32`. When the exact value is within half an 
`f64` ULP of an `f32` midpoint, the intermediate rounding moves it across the 
midpoint and the result differs from a correctly rounded `f32`.
   
   Verified on `main` (Rust):
   
   | value | correctly rounded (`i128 as f32`) | `i256::to_f32()` |
   | --- | --- | --- |
   | `2^53 + 2^29 + 1` | `0x5a000001` | `0x5a000000` |
   | `-(2^53 + 2^29 + 1)` | `0xda000001` | `0xda000000` |
   | `2^54 + 2^30 + 1` | `0x5a800001` | `0x5a800000` |
   
   For `v = 9007199791611905`, the expected `f32` is `9007200328482816.0` and 
`to_f32()` returns `9007199254740992.0`.
   
   ### To Reproduce
   
   ```rust
   use arrow_buffer::i256;
   use num_traits::ToPrimitive;
   
   let v: i128 = (1 << 53) + (1 << 29) + 1;
   let value = i256::from_i128(v);
   assert_eq!(value.to_f32().unwrap().to_bits(), (v as f32).to_bits()); // fails
   ```
   
   ### Expected behavior
   
   For values in the `i128` range, `i256::to_f32` should match `i128 as f32` 
(correctly rounded), the same expectation that `to_f64` now satisfies after 
#11315.
   
   ### Additional context
   
   Found while validating #11315. Similar values exist across f32 exponents 
(the double-rounding window is around 2^-29, so they are rare in practice). 
There are no in-tree callers of `i256::to_f32`; `Decimal256 -> Float32` goes 
through `to_f64` plus scaling. Low impact, but a correctness gap in the public 
conversion.
   


-- 
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]

Reply via email to