Hi all,
I tried to code a solution to the following problem in Elixir: https://projecteuler.net/problem=14. Given an input n
, find the Collatz sequence for that number - for an even number, the next number is n / 2
; for an odd number, it is n * 3 + 1
. That sequence eventually halts when hitting the number 1
. I’m looping from 1
to 1,000.000
and figuring what number generates the longest sequence.
The problem is, the Elixir solution seems too slow when compared to the Ruby one (4 times slower).
Since both use the same algorithm, I wonder what optimizations I could apply to make my Elixir solution faster. I suspect Elixir is not the right tool for this job, but should it really be 4 times slower compared to the Ruby one?
Elixir solution:
$ elixir collatz.ex
Number with longest Collatz sequence: 837799
Longest sequence length: 525
elixir collatz.ex 2.89s user 0.15s system 99% cpu 3.071 total
Code:
defmodule NextCollatz do
def call(n, cache), do: call(n, 0, cache)
def call(1, length, _), do: length + 1
def call(n, length, cache), do: length_for(n, length, cache, cache[n])
defp length_for(n, length, cache, nil), do: call(next_for(n), length, cache) + 1
defp length_for(_, _, _, cache_value), do: cache_value
defp next_for(n) when rem(n, 2) == 0, do: div(n, 2)
defp next_for(n) when rem(n, 2) == 1, do: n * 3 + 1
end
defmodule LongestCollatzSequence do
def call(min, limit), do: call(min, %{}, limit, {0, 0})
def call(n, _, limit, result) when n > limit, do: result
def call(n, cache, limit, result) do
gather_iteration_result(n, cache, limit, result, NextCollatz.call(n, cache))
end
def gather_iteration_result(n, cache, limit, result, length) do
call(n + 1, Map.put_new(cache, n, length), limit, max(n, length, result))
end
defp max(n, length, {_, max_length}) when length > max_length, do: {n, length}
defp max(_, _, result), do: result
end
{max_n, max_length} = LongestCollatzSequence.call(1, 1_000_000)
IO.puts "Number with longest Collatz sequence: #{max_n}"
IO.puts "Longest sequence length: #{max_length}"
Ruby solution
$ ruby collatz.rb
Number with longest Collatz sequence: 837799
Longest sequence length: 525
ruby collatz.rb 0.78s user 0.01s system 95% cpu 0.827 total
URL: https://gist.github.com/thiagoa/6118393c49242d517a4a64024f74c1f7