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+.
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
:
parse()
treats the whole string as a decimal number and returns an error if there are invalid characters or if the string is empty.parse_partial()
tries to find the longest substring at the beginning of the given input string that can be parsed as a decimal number and, in the case of success, returns the parsed value along the number of characters processed; an error is returned if the string doesn't start with a decimal number or if it is empty. This function is most useful as a building block when constructing more complex parsers, or when parsing streams of data.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");
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.
There are a few ways this crate is tested:
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:
Below are tables of best timings in nanoseconds for parsing a single number into a 64-bit float.
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, 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, 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
- this very cratelexical
– lexical_core
, v0.7 (non-lossy; same performance as lossy)from_str
– Rust standard library, FromStr
traitfast_float (C++)
– original C++ implementation of 'fast-float' methodabseil (C++)
– Abseil C++ Common Librariesnetlib (C++)
– C++ Network Librarystrtod (C)
– C standard librarycanada
– numbers in canada.txt
filemesh
– numbers in mesh.txt
fileuniform
– uniform random numbers from 0 to 1iidi
– random numbers of format %d%d.%d
iei
– random numbers of format %de%d
rec32
– reciprocals of random 32-bit integersextras/simple-bench
of this repo.RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4