What happens when casting a big float to a int?

If you use as to cast a floating-point number to an integer type, and the floating-point number does not fit¹ in the destination type, the result is an undefined value², and most things that you can do with it cause undefined behavior.

This is certainly unfortunate! This is issue #10184 on GitHub and it is one of only a few ways you can still invoke undefined behavior in safe Rust. In fact, it's the oldest soundness bug in Rust.

Today, if you run Rust with the -Z saturating-float-casts flag, float-to-integer casts saturate instead (that is, values that are too large or small are converted to T::MAX or T::MIN, respectively; NaN is converted to 0). Enabling this flag is likely to make most floating-point casts slower since they have to check the type bounds first, so it has not yet been enabled by default. However, in the future, expect that safe-but-slower saturating will become the behavior of as and there will be a new API for manually using the fast-but-unsafe conversion.

(There used to be a similar issue for certain integer-to-float casts, but it was resolved by making such casts always saturating. This change was not considered a performance regression and there is no way to opt in to the old behavior.)

Also read

  • Can casting in safe Rust ever lead to a runtime error? especially the answer from DK.

¹ "Fit" here means either NaN, or a number of such large magnitude that it cannot be approximated by the smaller type. 8.7654321_f64 will still be truncated to 8 by an as u8 cast, even though the value cannot be represented exactly by the destination type -- loss of precision does not cause undefined behavior, only being out of range does.

² A "poison" value in LLVM, as you correctly note in the question, but Rust itself does not distinguish between undef and poison values.

Tags:

Rust