In my experience, most of such synthetic challenges are significantly skewed due to a suboptimal algorithm. In this example, we can significantly improve the running time by changiing the algorithm. Here’s a demo on 40th fibonacci:
defmodule NaiveFib do
def of(0), do: 0
def of(1), do: 1
def of(n), do: of(n - 1) + of(n - 2)
end
{time, res} = :timer.tc(fn -> NaiveFib.of(40) end)
IO.puts("Naive fib returned #{res} in #{time} microseconds")
defmodule BetterFib do
def of(0), do: 0
def of(1), do: 1
def of(n), do: of(0, 1, 2, n)
defp of(x, y, n, n), do: x + y
defp of(x, y, m, n), do: of(y, x + y, m + 1, n)
end
{time, res} = :timer.tc(fn -> BetterFib.of(40) end)
IO.puts("Better fib returned #{res} in #{time} microseconds")
Output:
Naive fib returned 102334155 in 2776981 microseconds
Better fib returned 102334155 in 0 microseconds
As we can see, the algorithmical optimization leads to an almost instantaneous computation. Of course, the equivalent go version would still be faster, but at this speed the difference doesn’t matter. So more generally, an algorithmical optimization can do wonders for performance. If that still doesn’t cut it, it’s perhaps time to consider a faster language. If that is the case, I’d probably go for C or Rust instead of go. But in my experience, more often than not, the challenge can be solved within a reasonable time using a proper algorithmical/technical combo 