我想知道当我将一个非常大的浮点值转换为整数时会发生什么。这是我写的一个例子:
fn main() {
let x = 82747650246702476024762_f32;//-1_i16;
let y = x as u8;
let z = x as i32;
println!("{} {} {}", x, y, z);
}
Run Code Online (Sandbox Code Playgroud)
输出是:
$ ./casts
82747650000000000000000 0 -2147483648
Run Code Online (Sandbox Code Playgroud)
显然浮点数不适合任何整数,但由于 Rust 如此强烈地宣传它是安全的,我会预料到某种错误。这些操作使用 llvmfptosi和fptoui指令,如果该值不适合它已转换为的类型,则会产生所谓的毒值。这可能会产生未定义的行为,这是非常糟糕的,尤其是在编写 Rust 代码时。
如何确保我的 float 到 int 类型转换不会导致 Rust 中的未定义行为?为什么 Rust 甚至允许这样做(因为它以创建安全代码而闻名)?
在 Rust 1.44 及更早版本中,如果您使用as将浮点数转换为整数类型,并且该浮点数不适合目标类型中的\xc2\xb9,则结果是未定义值\xc2\xb2,并且你可以用它做的大多数事情都会导致未定义的行为。
这个严重问题 ( #10184 ) 在 Rust 1.45 中得到了修复。自该版本以来,浮点到整数的强制转换改为饱和(也就是说,太大或太小的值被转换为T::MAX或T::MIN;NaN 转换为 0)。
在旧版本的 Rust 中,您可以使用该-Z saturating-float-casts标志启用新的安全行为。请注意,饱和强制转换可能会稍微慢一些,因为它们必须首先检查类型边界。如果您确实需要避免检查,标准库提供了to_int_unchecked. 由于当数字超出范围时行为未定义,因此您必须使用unsafe。
(某些整数到浮点的转换曾经存在类似的问题类似的问题,但通过使此类转换始终饱和来解决。此更改不被视为性能回归,并且无法选择旧行为。)
\n\xc2\xb9 这里的“Fit”表示 NaN,或者是一个无法用较小的类型来近似的大数值。8.7654321_f64仍然会被截断8为as u8强制转换截断——精度损失不会导致未定义的行为,只有超出范围才会导致。
\xc2\xb2 LLVM 中的“毒药”值,正如您在问题中正确指出的那样,但 Rust 本身不区分undef和毒药值。
| 归档时间: |
|
| 查看次数: |
729 次 |
| 最近记录: |