From 799516005fe6adb49260eb51c8d31891b4ac8749 Mon Sep 17 00:00:00 2001 From: "Dr. Matthias Ratajczak" Date: Tue, 16 Aug 2022 18:59:17 +0200 Subject: [PATCH] more performance optimizations for 51 --- lib/primes/src/lib.rs | 12 +++++-- src/euler51/src/main.rs | 75 ++++++++++++++++++++++++++++++++--------- 2 files changed, 68 insertions(+), 19 deletions(-) diff --git a/lib/primes/src/lib.rs b/lib/primes/src/lib.rs index 8cfaaef..f99018d 100644 --- a/lib/primes/src/lib.rs +++ b/lib/primes/src/lib.rs @@ -12,7 +12,7 @@ use num::ToPrimitive; #[derive(Clone)] pub struct Primes { - vector: Vec, + pub vector: Vec, set: HashSet, } @@ -157,14 +157,20 @@ mod test { #[ignore] #[test] - fn test_performance() { + fn test_performance_1() { + let _ = Primes::get_between(100_000, 999_999); + } + + #[ignore] + #[test] + fn test_performance_2() { let primes = Primes::get_between(2, 10_000_000); assert_eq!(primes.len(), 664_579); } #[ignore] #[test] - fn test_performance_2() { + fn test_performance_3() { let primes = Primes::get_between(2, 1_000_000_000); assert_eq!(primes.len(), 50_847_534); } diff --git a/src/euler51/src/main.rs b/src/euler51/src/main.rs index 0beb462..f82733c 100644 --- a/src/euler51/src/main.rs +++ b/src/euler51/src/main.rs @@ -1,7 +1,7 @@ extern crate combination; extern crate primes; -use std::process::exit; +use std::{collections::HashSet, process::exit}; use combination::PositionCombinations; use primes::Primes; @@ -32,18 +32,26 @@ const DIGITS: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; fn main() { let all_primes = Primes::get_between(MIN_VALUE, MAX_VALUE); + let mut processed_cases = HashSet::new(); + let mut primes_matching_pattern = Vec::with_capacity(TARGET_LENGTH); for pattern in PositionCombinations::new(MIN_LENGTH, MAX_LENGTH, LENGTH) { - let mut primes_to_check = all_primes.clone(); + for prime in &all_primes.vector { + primes_matching_pattern.clear(); - while let Some(first) = primes_to_check.pop() { - let mut primes_matching_pattern = vec![]; + let digits = prime.to_digits(); + + let case = get_case_string(&digits, &pattern); + if processed_cases.contains(&case) { + continue; + } else { + processed_cases.insert(case.clone()); + } - let digits = first.to_digits(); for digit in DIGITS { let could_be_prime = - replace_digits_according_to_pattern_with_digit(&digits, digit, &pattern); - if primes_to_check.contains(&could_be_prime) || could_be_prime == first { + replace_digits_with_new_digit_according_to_pattern(&digits, digit, &pattern); + if all_primes.contains(&could_be_prime) { primes_matching_pattern.push(could_be_prime); } } @@ -55,7 +63,15 @@ fn main() { } } -fn replace_digits_according_to_pattern_with_digit( +fn get_case_string(digits: &[u8], pattern: &[bool]) -> String { + digits + .iter() + .zip(pattern) + .map(|(d, b)| if *b { '*' } else { *d as char }) + .collect() +} + +fn replace_digits_with_new_digit_according_to_pattern( prime_as_digits: &[u8], new_digit: u8, pattern: &[bool], @@ -86,24 +102,36 @@ trait ToDigits { #[allow(clippy::needless_range_loop)] impl ToDigits for Int { fn to_digits(&self) -> Vec { - let oom = (*self as f64).log10().floor() as i32; - let length = oom as usize + 1; + let oom = get_order_of_magnitude(*self); + let length = oom as usize; let mut var = *self; let mut result = vec![0; length]; - for i in 0..length as usize { - let power = 10_f64.powi(oom - i as i32); - let digit = (var as f64 / power).floor(); + for i in 0..length { + let power = 10_u64.pow(oom - i as u32 - 1); + let digit = var / power; var -= (digit * power) as Int; result[i] = digit as u8; } - assert_eq!(var, 0); + debug_assert_eq!(var, 0); result } } +fn get_order_of_magnitude(x: Int) -> u32 { + let mut tmp = 1; + let mut oom = 1; + while tmp - 1 < x { + oom += 1; + tmp *= 10; + } + oom - 1 +} + #[cfg(test)] mod test { - use crate::{replace_digits_according_to_pattern_with_digit, ToDigits}; + use crate::{ + get_order_of_magnitude, replace_digits_with_new_digit_according_to_pattern, ToDigits, + }; #[test] fn test_num_to_digits() { @@ -117,7 +145,11 @@ mod test { let new_digit = 0; let pattern = [false, true, true, true, false, false]; assert_eq!( - replace_digits_according_to_pattern_with_digit(&prime_as_digits, new_digit, &pattern), + replace_digits_with_new_digit_according_to_pattern( + &prime_as_digits, + new_digit, + &pattern + ), 500_021 ); } @@ -127,4 +159,15 @@ mod test { let num = 37871_u64; assert_eq!(vec![3, 7, 8, 7, 1], num.to_digits()); } + + #[test] + fn test_oom() { + assert_eq!(get_order_of_magnitude(3), 1); + assert_eq!(get_order_of_magnitude(9), 1); + assert_eq!(get_order_of_magnitude(10), 2); + assert_eq!(get_order_of_magnitude(32), 2); + assert_eq!(get_order_of_magnitude(10_000), 5); + assert_eq!(get_order_of_magnitude(10_001), 5); + assert_eq!(get_order_of_magnitude(37_871), 5); + } }