aldanor / fast-float-rust

Super-fast float parser in Rust (now part of Rust core)
https://docs.rs/fast-float
Apache License 2.0
274 stars 20 forks source link
floating-point high-performance parser rust

fast-float

Build Latest Version Documentation Apache 2.0 MIT Rustc 1.37+

This crate provides a super-fast decimal number parser from strings into floats.

[dependencies]
fast-float = "0.2"

There are no dependencies and the crate can be used in a no_std context by disabling the "std" feature.

Compiler support: rustc 1.37+.

Usage

There's two top-level functions provided: parse() and parse_partial(), both taking either a string or a bytes slice and parsing the input into either f32 or f64:

Example:

// 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");

Details

This crate is a direct port of Daniel Lemire's fast_float C++ library (valuable discussions with Daniel while porting it helped shape the crate and get it to the performance level it's at now), with some Rust-specific tweaks. Please see the original repository for many useful details regarding the algorithm and the implementation.

The parser is locale-independent. The resulting value is the closest floating-point values (using either f32 or f64), using the "round to even" convention for values that would otherwise fall right in-between two values. That is, we provide exact parsing according to the IEEE standard.

Infinity and NaN values can be parsed, along with scientific notation.

Both little-endian and big-endian platforms are equally supported, with extra optimizations enabled on little-endian architectures.

Testing

There are a few ways this crate is tested:

Performance

The presented parser seems to beat all of the existing C/C++/Rust float parsers known to us at the moment by a large margin, in all of the datasets we tested it on so far – see detailed benchmarks below (the only exception being the original fast_float C++ library, of course – performance of which is within noise bounds of this crate). On modern machines like Apple M1, parsing throughput can reach up to 1.5 GB/s.

In particular, it is faster than Rust standard library's FromStr::from_str() by a factor of 2-8x (larger factor for longer float strings), and is typically 2-3x faster than the nearest competitors.

While various details regarding the algorithm can be found in the repository for the original C++ library, here are few brief notes:

Benchmarks

Below are tables of best timings in nanoseconds for parsing a single number into a 64-bit float.

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

Parsers

Datasets

Notes


References

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.


Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.