diff --git a/benchmark.txt b/benchmark.txt index 857cfd7..1313221 100644 --- a/benchmark.txt +++ b/benchmark.txt @@ -3,4 +3,5 @@ 107 nightly, build-std 109 native cpu (doesn't seem to work) 95 FxHashMap - 75 mmap, reduced UTF8 parsing (names) + 71 mmap, reduced UTF8 parsing (names) + 50 manual number parsing diff --git a/src/main.rs b/src/main.rs index ce7fed0..bd8b9e5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,13 +30,12 @@ fn main() { let mut split = line.split(|&c| c == b';'); let station = split.next().unwrap(); - let parsed: f64 = String::from_utf8(split.next().unwrap().to_vec()) - .unwrap() - .parse() - .unwrap(); + let number = split.next().unwrap(); + let parsed = parse_number(number); + // panic!(); data.entry(station) - .and_modify(|values: &mut (f64, f64, usize, f64)| { + .and_modify(|values: &mut (i64, i64, usize, i64)| { values.0 = values.0.min(parsed); values.1 += parsed; values.2 += 1; @@ -48,7 +47,7 @@ fn main() { } let mut stations: Vec<_> = data.keys().collect(); - stations.sort(); + stations.sort_unstable(); print!("{{"); @@ -60,9 +59,9 @@ fn main() { print!( "{s}={:.1}/{:.1}/{:.1}", - entry.0, - entry.1 / (entry.2 as f64), - entry.3 + entry.0 as f64 / 10., + (entry.1 / (entry.2 as i64)) as f64 / 10., + entry.3 as f64 / 10. ); if iter.peek().is_some() { print!(", "); @@ -70,3 +69,37 @@ fn main() { } println!("}}"); } + +fn parse_number(number: &[u8]) -> i64 { + let sign = if *number.first().unwrap() == b'-' { + -1 + } else { + 1 + }; + + let mut iter = number.iter().rev(); + + // 48: ASCII '0' + let mut result = (iter.next().unwrap() - 48) as i64; + iter.next(); // skip '.' + result += ((iter.next().unwrap() - 48) as i64) * 10; + + if let Some(hundreds) = iter.next() + && *hundreds != b'-' + { + result += ((hundreds - 48) as i64) * 100; + } + + sign * result +} + +#[cfg(test)] +mod tests { + use super::parse_number; + + #[test] + fn test_parse_number() { + let input = [49, 53, 46, 51]; // "15.3" + assert_eq!(parse_number(&input), 153); + } +}