2 个不稳定版本
0.2.0 | 2021 年 1 月 13 日 |
---|---|
0.1.0 | 2021 年 1 月 10 日 |
#23 在 解析工具
165,332 每月下载量
在 248 个 crate (29 直接) 中使用
85KB
2K SLoC
fast-float
此 crate 提供了一个从字符串到浮点数的超级快速十进制数解析器。
[dependencies]
fast-float = "0.2"
没有依赖项,可以通过禁用 "std" 功能在无 std 环境中使用此 crate。
编译器支持:rustc 1.37+。
使用方法
提供了两个顶级函数: parse()
和 parse_partial()
,两者都接受字符串或字节数组切片,并将输入解析为 f32
或 f64
parse()
将整个字符串视为十进制数,如果字符串中有无效字符或字符串为空,则返回错误。parse_partial()
尝试在给定的输入字符串的开始处找到最长的可以解析为十进制数的子字符串,在成功的情况下,返回解析值以及处理的字符数;如果字符串不以十进制数开头或为空,则返回错误。此函数在构建更复杂的解析器或解析数据流时非常有用。
示例
// Parse the entire string as a decimal number.
let s = "1.23e-02";
let x: f32 = fast_float::parse(s).unwrap();
assert_eq!(x, 0.0123);
// Parse as many characters as possible as a decimal number.
let s = "1.23e-02foo";
let (x, n) = fast_float::parse_partial::<f32, _>(s).unwrap();
assert_eq!(x, 0.0123);
assert_eq!(n, 8);
assert_eq!(&s[n..], "foo");
详细信息
此 crate 是 Daniel Lemire 的 fast_float
C++ 库的直接移植(在移植过程中与 Daniel 的宝贵讨论帮助塑造了 crate 并使其达到现在的性能水平),并进行了一些针对 Rust 的调整。请参阅原始仓库以获取有关算法和实现的许多有用细节。
解析器是区域无关的。生成的值是最近的浮点值(使用f32
或f64
),对于本应介于两个值之间的值,使用“四舍六入五留双”的约定。也就是说,我们提供符合IEEE标准的精确解析。
可以解析无穷大和NaN值,以及科学记数法。
支持小端和大端平台,并在小端架构上启用额外的优化。
测试
有几种方法对这个crate进行测试
- 一套显式测试(来自原始库),覆盖了很多边缘情况。
- 基于文件的测试套件(来自原始库;归功于Nigel Tao),约5M次测试。
- 通过ryu格式化器将所有4B个float32数字完全往返。
- 通过ryu格式化器往返大量随机float64数字。
- 通过cargo-fuzz往返float64数字和模糊随机输入字符串。
- 所有显式测试套件都在CI上运行;往返和模糊测试是手动运行的。
性能
所提供的解析器似乎在所有我们目前所知的C/C++/Rust浮点解析器中都有很大的优势,我们在所有测试过的数据集上测试了它 – 请见下文的详细基准测试(唯一的例外是原始的fast_float C++库 – 其性能与此crate的噪声界限相似)。在像Apple M1这样的现代机器上,解析吞吐量可以达到高达1.5 GB/s。
特别是,它比Rust标准库的FromStr::from_str()
快2-8倍(对于较长的浮点字符串,因子更大),并且通常比最近的竞争对手快2-3倍。
有关算法的各种细节可以在原始C++库的存储库中找到,这里有一些简要的说明
- 解析器针对最多19位有效数字的输入进行了优化,可以闪电般快速处理(这构成了所谓的“快速路径”)。我们相信大多数实际输入应该属于这一类别,我们将较长的输入视为“退化的”边缘情况,因为它不可避免地会导致溢出和精度损失。
- 如果尾数超过19位,解析器将回退到“慢速路径”,在这种情况下,其性能大致与顶级Rust/C++库相当(尽管大多数时候仍然比它们快,但差距不大)。
- 在小端系统上,对小数点后超过8位数的数字有额外的优化。
基准测试
以下是解析单个数字到64位浮点数的最佳时间(纳秒)表。
Intel i7-4771
Intel i7-4771 3.5GHz,macOS,Rust 1.49。
canada |
mesh |
uniform |
iidi |
iei |
rec32 |
|
---|---|---|---|---|---|---|
fast-float | 21.58 | 10.70 | 19.36 | 40.50 | 26.07 | 29.13 |
lexical | 65.90 | 23.28 | 54.75 | 75.80 | 52.18 | 75.36 |
from_str | 174.43 | 22.30 | 99.93 | 227.76 | 111.31 | 204.46 |
fast_float (C++) | 22.78 | 10.99 | 20.05 | 41.12 | 27.51 | 30.85 |
abseil (C++) | 42.66 | 32.88 | 46.01 | 50.83 | 46.33 | 49.95 |
netlib (C++) | 57.53 | 24.86 | 64.72 | 56.63 | 36.20 | 67.29 |
strtod (C) | 286.10 | 31.15 | 258.73 | 295.73 | 205.72 | 315.95 |
Apple M1
Apple M1,macOS,Rust 1.49。
canada |
mesh |
uniform |
iidi |
iei |
rec32 |
|
---|---|---|---|---|---|---|
fast-float | 14.84 | 5.98 | 11.24 | 33.24 | 21.30 | 17.86 |
lexical | 47.09 | 16.51 | 43.46 | 56.06 | 36.68 | 55.48 |
from_str | 136.00 | 13.84 | 74.64 | 179.87 | 77.91 | 154.53 |
fast_float (C++) | 13.71 | 7.28 | 11.71 | 32.94 | 20.64 | 18.30 |
abseil (C++) | 36.55 | 24.20 | 38.48 | 40.86 | 35.46 | 40.09 |
netlib (C++) | 47.19 | 14.12 | 48.85 | 52.28 | 33.70 | 48.79 |
strtod (C) | 176.13 | 21.48 | 165.43 | 187.98 | 132.19 | 190.63 |
AMD Rome
AMD Rome,Linux,Rust 1.49。
canada |
mesh |
uniform |
iidi |
iei |
rec32 |
|
---|---|---|---|---|---|---|
fast-float | 25.90 | 12.12 | 20.54 | 47.01 | 29.23 | 32.36 |
lexical | 63.18 | 22.13 | 54.78 | 81.23 | 55.06 | 79.14 |
from_str | 190.06 | 26.10 | 102.44 | 239.87 | 119.04 | 211.73 |
fast_float (C++) | 21.29 | 10.47 | 18.31 | 42.33 | 24.56 | 29.76 |
abseil (C++) | 44.54 | 34.13 | 47.38 | 52.64 | 43.77 | 53.03 |
netlib (C++) | 69.43 | 23.31 | 79.98 | 72.17 | 35.81 | 86.91 |
strtod (C) | 123.37 | 65.68 | 101.58 | 118.36 | 118.61 | 123.72 |
解析器
fast-float
- 这个cratelexical
–lexical_core
,v0.7(无损;性能与有损相同)from_str
– Rust标准库,FromStr
traitfast_float (C++)
– 'fast-float'方法的原始C++实现abseil (C++)
– Abseil C++ Common Librariesnetlib (C++)
– C++ Network Librarystrtod (C)
– C标准库
数据集
canada
– 存储在canada.txt
文件中的数字mesh
– 存储在mesh.txt
文件中的数字uniform
– 0到1之间的均匀随机数iidi
– 格式为%d%d.%d
的随机数iei
– 格式为%de%d
的随机数rec32
– 随机32位整数的倒数
注意
- 上述两个测试文件可以在这个仓库中找到。
- 表中的Rust部分(以及一些其他基准测试)可以通过该仓库下
extras/simple-bench
中的基准测试工具生成。 - 表中的C/C++部分(以及一些其他基准测试和解析器)可以通过该仓库中的C++实用工具生成。
许可证
根据您的选择,受Apache许可证,版本2.0或MIT许可证的许可。除非您明确声明,否则根据Apache-2.0许可证定义的,您有意提交以包含在此软件包中的任何贡献,都应如上所述双重许可,而不附加任何额外的条款或条件。