Floating point 将字节转换为浮点是安全的,还是会产生未定义的行为?

Floating point 将字节转换为浮点是安全的,还是会产生未定义的行为?,floating-point,rust,undefined-behavior,Floating Point,Rust,Undefined Behavior,是否有字节序列在转换为f32或f64时,会在Rust中产生未定义的行为?我将非有限值(如NaN、Infinity等)计算为有效的浮点值 注释提示从原始字节转换浮点可能存在一些问题。提供了一个很好的列表,列出了发生未定义行为的情况。其中,与该问题最密切相关的是: 基元类型中的值无效,即使在专用字段/局部变量中也是如此: 悬挂/空引用或框 布尔值中除false(0)或true(1)以外的值 类型定义中未包含的枚举中的判别式 字符中的一个值,它是代理项或高于char::MAX的值 str中的非UTF

是否有字节序列在转换为
f32
f64
时,会在Rust中产生未定义的行为?我将非有限值(如NaN、Infinity等)计算为有效的浮点值

注释提示从原始字节转换浮点可能存在一些问题。

提供了一个很好的列表,列出了发生未定义行为的情况。其中,与该问题最密切相关的是:

基元类型中的值无效,即使在专用字段/局部变量中也是如此:

  • 悬挂/空引用或框
  • 布尔值中除false(0)或true(1)以外的值
  • 类型定义中未包含的枚举中的判别式
  • 字符中的一个值,它是代理项或高于char::MAX的值
  • str中的非UTF-8字节序列
不过,浮点类型并未列出。这是因为根据IEEE 754-2008二进制32和二进制64浮点类型,任何位序列(32位用于f32;64位用于f64)都是浮点值的有效状态。它们可能不正常(其他类为零、次正常、无限或不是数字),但仍然有效

然而,最终,应该始终有
transmute
。特别是,
字节顺序
板条箱提供了一种从字节流中读取数字的安全直观的方法

use byteorder::{ByteOrder, LittleEndian}; // or NativeEndian

let bytes = [0x00u8, 0x00, 0x80, 0x7F];
let number = LittleEndian::read_f32(&bytes);
println!("{}", number);


好的,实际上有一种非常特殊的边缘情况,将位转换为浮点会导致信号NaN,在某些CPU架构和配置中,这将触发低级异常。有关详细信息,请参见中的讨论。目前已知,具体化信令NAN并不是未定义的行为,如果启用了浮点异常(默认情况下并非如此),则不太可能出现问题

Rust library团队已经做出的决定是,转化为浮动是安全的,即使没有任何掩蔽。文档中详细描述了以下原因:

目前,这与所有平台上的
transmute::(v)
相同。事实证明,这是难以置信的便携性,原因有两个:

  • 浮点和整数在所有支持的平台上具有相同的endianness
  • IEEE-754非常精确地指定了浮点的位布局
然而,有一个警告:在2008版IEEE-754之前,没有实际指定如何解释NaN信令位。大多数平台(尤其是x86和ARM)选择了2008年最终标准化的解释,但有些平台没有(尤其是MIPS)。因此,MIPS上的所有信令NAN在x86上都是安静的NAN,反之亦然

这种实现不试图跨平台保留信令,而是倾向于保留确切的位。这意味着,即使此方法的结果通过网络从x86机器发送到MIPS机器,NAN中编码的任何有效负载都将被保留

如果此方法的结果仅由生成它们的相同体系结构操纵,那么就没有可移植性问题

如果输入不是NaN,那么就没有可移植性问题

如果您不关心信号性(很可能),那么就没有可移植性问题


一些解析/编码库可能仍在将各种NaN转换为绝对安静的NaN,因为这一问题在Rust的历史上有一段时间是不确定的。

可能是信号NaN。