Skip to content

[ABA-20] fix(vortex-array): reject fractional f64 values in integer casts#10

Open
abnobdoss wants to merge 2 commits into
developfrom
fix/aba-20-f64-to-i64-fractional-loss
Open

[ABA-20] fix(vortex-array): reject fractional f64 values in integer casts#10
abnobdoss wants to merge 2 commits into
developfrom
fix/aba-20-f64-to-i64-fractional-loss

Conversation

@abnobdoss
Copy link
Copy Markdown
Owner

Summary

  • Bug: Casting a f64 (or f32/f16) array with fractional values to an integer type silently truncated the fractional part instead of returning an error. For example, cast([1.5_f64] → i64) returned Ok([1]) instead of Err.
  • Root cause (array kernel): CastKernel::cast delegated to cast::<F, T>() which uses AsPrimitive::as_() — the Rust as operator — which silently truncates. The pre-flight guard values_fit_in checked only min/max range via PValue::cast, and PValue::cast used NumCast::from(1.5_f64) which returns Some(1), so fractional values slipped through.
  • Fix (array kernel): Before the per-element cast loop, call reject_fractional_values() when source.is_float() && target.is_int(). This materializes the validity mask and checks fract() != 0.0 on valid positions only, skipping null slots.
  • Fix (scalar layer): PValue::cast gains the same fractional check for float→int casts. This also makes the conformance test helper fits() return false for fractional values, keeping the conformance suite self-consistent without changing test data.

Linear

Closes ABA-20

Validation

  • Added issue_aba20_cast_f64_to_i64_rejects_fractional_values (inline #[cfg(test)]):
    • cast([1.5_f64] → i64)Err
    • cast([2.0_f64] → i64)Ok([2])
    • cast([Some(2.0_f64), None, Some(3.0)] → nullable i64)Ok([Some(2), None, Some(3)]) ✓ (null slots with potentially fractional underlying bits do not trigger false positives)
  • cargo test -p vortex-array: 2753 unit tests + 67 doc tests pass, 0 failures
  • NaN and ±Inf: already rejected by values_fit_in; the fractional check also catches them as a secondary layer (their fract() is NaN ≠ 0.0).

Note: Scalar callers of PValue::cast outside vortex-array (e.g. in vortex-datafusion, vortex-session) may previously have relied on silent truncation semantics. This fix makes scalar float→int cast strict; downstream callers should be reviewed if they perform such casts intentionally.


🤖 Generated with Claude Code

Abanoub Doss and others added 2 commits May 21, 2026 08:23
…s fractional values

Add a failing regression test `issue_aba20_cast_f64_to_i64_rejects_fractional_values`
that documents the bug: casting 1.5_f64 to i64 currently returns Ok(1) instead of Err.
Also rename the test module from `test` to `tests` per project conventions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Abanoub Doss <abanoub.doss@gmail.com>
In the array kernel (CastKernel for Primitive), add a validity-aware
per-element check before any float→int element-wise cast: iterate
valid positions only and return a Compute error if any has a non-zero
fractional part (detected via f64::fract() != 0.0).

In the scalar layer (PValue::cast), add the same fractional check when
the source is a float variant (F16/F32/F64) and the target ptype is an
integer. For F16, promote to f32 via ToPrimitive before calling fract().

Both fixes correctly handle NaN and ±Inf (their fract() returns NaN,
which compares unequal to 0.0, so they are rejected). In practice NaN
and ±Inf are already caught by the `values_fit_in` range guard, but
the fractional check provides a second, more precise layer.

The PValue::cast fix also causes the conformance test helper `fits()`
to return false for fractional min/max values, keeping the conformance
suite consistent without modifying any test data.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Abanoub Doss <abanoub.doss@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant