3 个不稳定版本
0.2.1 | 2021年3月29日 |
---|---|
0.2.0 | 2021年3月28日 |
0.1.0 | 2017年4月15日 |
#206 在 值格式化
5,135 每月下载量
在 22 个 crate 中使用 (4 直接使用)
29KB
435 行
hexf
为 Rust 1.45 或更高版本提供十六进制浮点数支持。
use hexf::hexf64;
assert_eq!(hexf64!("0x1.999999999999ap-4"), 0.1f64);
字面量是显式类型化的,应与以下模式匹配:SIGN "0x" INTEGRAL "." FRACTIONAL "p" EXPSIGN EXPDIGITS
,其中
-
所有拉丁字母都不区分大小写;
-
SIGN
和EXPSIGN
是+
、-
或空; -
INTEGRAL
和FRACTIONAL
是一个或多个十六进制数字,可选地由或以一个下划线 (_
) 分隔(但不能以它开始); -
INTEGRAL
或FRACTIONAL
中至少有一个应该存在(允许1.0
或.0
或1.
,不允许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_hexf32
和 parse_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
约 34K SLoC