Question
The following iterative sequence is defined for the set of positive integers:
n \rightarrow \begin{cases} \tfrac{n}{2} & \text{if } n \text{ is even} \\ 3n+1 & \text{if } n \text{ is odd} \end{cases}
Using the rule above and starting with 13, we generate the following sequence:
13, 40, 20, 10, 5, 16, 8, 4, 2, 1
It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.
Which starting number, under one million, produces the longest chain?
NOTE: Once the chain starts the terms are allowed to go above one million.
Haskell
import Data.Word
import Data.Array
memoCollatz :: Array Word Word
= listArray (1, size) $ map collatz [1..size]
memoCollatz where size = 1000000
collatz :: Word -> Word
1 = 1
collatz | inRange (bounds memoCollatz) next = 1 + memoCollatz ! next
collatz n | otherwise = 1 + collatz next
where next = case n of
1 -> 1
| even n -> n `div` 2
n | otherwise -> 3 * n + 1
= print $ snd $ maximum $ map (\n -> (collatz n, n)) [1..1000000] main
$ ghc -O2 -o longest-chain longest-chain.hs
$ time ./longest-chain
real 0m0.350s
user 0m0.342s
sys 0m0.008s
Python
#!/usr/bin/env python
def next_collatz(n):
if n % 2 == 0:
return n / 2
else:
return 3*n + 1
def collatz(start):
if start < 1:
raise ValueError("start must be greater than or equal to 1")
elif start == 1:
return [1]
= [start]
res = False
done while not done:
+= [next_collatz(res[-1])]
res if res[-1] == 1: done = True
return res
= {}
_collatz_cache def lencollatz(start):
if start < 1:
raise ValueError("start must be greater than or equal to 1")
elif start == 1:
return 1
= start
n = 1
length = False
done while not done:
= next_collatz(n)
n try:
+= _collatz_cache[n]
length = True
done except:
+= 1
length if n == 1: done = True
= length
_collatz_cache[start] return length
= 0
max_len = None
max_i for i in range(1, 1000000):
= lencollatz(i)
l if l > max_len:
= l
max_len = i
max_i print(max_i)
$ time python3 longest-chain.py
real 0m3.686s
user 0m3.639s
sys 0m0.047s
Ruby
#!/usr/bin/env ruby
= 0
max_l = 0
max_i 500001.step(1000000, 2).each do |i|
= 0
l = i
j = 1 do
while j !if j.even?
/= 2
j else
= 3 * j + 1
j end
+= 1
l end
if l > max_l
= l
max_l = i
max_i end
end
puts max_i
$ time ruby longest-chain.rb
real 0m2.133s
user 0m2.133s
sys 0m0.000s
Rust
fn main() {
let mut collatz: Vec<usize> = vec![0; 1000000];
1] = 1;
collatz[let max = (2..collatz.len())
.max_by_key(|&i| {
let mut j: usize = i;
let mut len = 0;
loop {
if j < collatz.len() && collatz[j] != 0 {
break;
}
+= 1;
len if j % 2 == 0 {
/= 2;
j } else {
= 3 * j + 1;
j }
}
+= collatz[j];
len = len;
collatz[i]
len})
.unwrap();
println!("{}", max);
}
$ rustc -C target-cpu=native -C opt-level=3 -o collatz collatz.rs
$ time ./collatz
real 0m0.018s
user 0m0.018s
sys 0m0.000s