diff --git a/Cargo.toml b/Cargo.toml index d46c3cf..c835e81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,4 +12,5 @@ harness = false [profile.release] incremental = true +overflow-checks = true strip = "debuginfo" diff --git a/Dockerfile b/Dockerfile index 03505a9..c27ffc4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ FROM --platform=linux/i386 alpine:3.19 RUN apk add cargo -WORKDIR /project-euler +WORKDIR /github.com/tfpf/project-euler COPY . . diff --git a/src/solutions/longest_collatz_sequence.rs b/src/solutions/longest_collatz_sequence.rs index 54aec9f..3c6ca1b 100644 --- a/src/solutions/longest_collatz_sequence.rs +++ b/src/solutions/longest_collatz_sequence.rs @@ -1,27 +1,38 @@ /// Find the length of the Collatz sequence starting from the given number /// and ending at 1. /// -/// * `collatz_lengths` - Array to cache the lengths. +/// * `collatz_lengths` - Array to cache the lengths. Indexable with `num`. /// * `num` - Number to find the length of the Collatz sequence for. /// /// -> Length of Collatz sequence. fn get_collatz_length(collatz_lengths: &mut Vec, num: usize) -> i32 { - if num == 1 { - return 1; - } - if num < collatz_lengths.len() && collatz_lengths[num] != 0 { + if collatz_lengths[num] != 0 { return collatz_lengths[num]; } - let num_next = if num & 1 == 0 { num >> 1 } else { 3 * num + 1 }; - let len = 1 + get_collatz_length(collatz_lengths, num_next); - if num < collatz_lengths.len() { - collatz_lengths[num] = len; + // In the course of Collatz iterations, a 32-bit number will overflow, + // which could lead to problems on 32-bit systems. Temporarily use a 64-bit + // number. + let mut num_next = num as u64; + for count in 1.. { + // Keep transforming this number until it can be used as an index into + // the cache. + num_next = if num_next % 2 == 0 { + num_next / 2 + } else { + 3 * num_next + 1 + }; + if num_next >= collatz_lengths.len() as u64 { + continue; + } + collatz_lengths[num] = count + get_collatz_length(collatz_lengths, num_next as usize); + return collatz_lengths[num]; } - len + unreachable!(); } pub fn solve() -> i64 { let mut collatz_lengths = vec![0; 1000000]; + collatz_lengths[1] = 1; let result = (2..collatz_lengths.len()) .map(|num| (get_collatz_length(&mut collatz_lengths, num), num)) .max()