#hex #float #floating-point #auxiliary #hexf #hexf64 #hexf32

hexf-impl

Rust的十六进制浮点数支持(辅助crate;也见hexf)

1个不稳定版本

使用旧的Rust 2015

0.1.0 2017年4月15日

#13#辅助

34 每月下载量

CC0 许可证

2KB

hexf

Hexf on crates.io Hexf on docs.rs

为Rust 1.43或更高版本提供十六进制浮点数支持。(对于早期版本,请尝试 0.1.0

use hexf::hexf64;

assert_eq!(hexf64!("0x1.999999999999ap-4"), 0.1f64);

字面量是显式类型化的,并且应与以下模式匹配 SIGN "0x" INTEGRAL "." FRACTIONAL "p" EXPSIGN EXPDIGITS,其中

  • 所有拉丁字母均不区分大小写匹配;

  • SIGNEXPSIGN+- 或空;

  • INTEGRALFRACTIONAL 是一个或多个十六进制数字,可选地由或以恰好一个下划线(_)分隔或结束(但不能以它开始);

  • INTEGRALFRACTIONAL 中至少应有一个存在(允许 1.0.01.,不允许 1);

  • EXPDIGITS 是十进制数字,可选地由或以或以恰好一个下划线(_)分隔或开始或结束。

放置无效的字面量是编译时错误。

// hexf32! failed: invalid hexadecimal float literal
let invalid = hexf32!("42");

放置无法在目标类型中精确表示的字面量也是编译时错误。

// hexf32! failed: cannot exactly represent float in target type
let inexact = hexf32!("0x1.99999bp-4");

// hexf32! failed: cannot exactly represent float in target type
let inexact_subnormal = hexf32!("0x1.8p-149");

// hexf64! failed: cannot exactly represent float in target type
let overflow = hexf64!("0x1.0p1024");

// hexf64! failed: cannot exactly represent float in target type
let underflow = hexf64!("0x1.0p-1075");

该库(以及独立的 hexf-parse 库)提供了 parse_hexf32parse_hexf64 函数,这些函数允许解析失败(通过 ParseHexfError 类型报告)。如果第二个参数为 true,则这些函数将允许存在交错下划线;这是为了保持一致性,因为 Rust 允许在数字字面量中使用下划线,但在标准库中不允许(例如,"3_4".parse::<i32>() 是一个错误)。

它是如何工作的?

该库高度依赖于最近的 Rust 编译器能够正确打印和读取浮点数。因此,该库的实际实现是通过将解析的十六进制浮点数打印回正确的十进制数字来完成的,编译器将此提取出来以生成精确的位模式。

等等,那么十六进制浮点数有什么用呢?答案是,它们是 ISO C99 为了避免实现陷阱“发明”的。理想情况下,应该可以枚举足够多的分数位数以获得正确的舍入位模式,但许多实现并没有这样做(相当可以理解,因为实际上相当困难)。因此,标准做出了一项妥协:在符合标准的实现中,十进制浮点数应解析为非常接近但不是精确的舍入数。

尾数部分被解释为(十进制或十六进制)有理数;指数部分的数字序列被解释为十进制整数。[...] 对于十进制浮点常数,以及当 FLT_RADIX 不是 2 的幂时,十六进制浮点常数,结果要么是最近的可表示值,要么是接近最近的可表示值的大或小可表示值,以实现定义的方式选择。[...]

——ISO C99,第 6.4.4.2 节 浮点常数,第 3 段(加粗为原文所加)

确实,以这种精度解析十进制浮点数相对容易。十六进制浮点数源于这种传统,但 Rust 不必如此!十六进制浮点数仍然可以用于手动写入浮点位,或用于从其他语言转换,然而。这个库就是为了那些罕见的使用场景而存在的。

有关更多背景信息,请参阅 rust-lang/rust#1433

依赖关系

~1.5MB
~39K SLoC