Multi language Fibonacci benchmark made the front of HN

Elixir is included.

Here’s the actual HN thread:

1 Like
defmodule Fib do
  def fib(0) do 1 end
  def fib(1) do 1 end
  def fib(n) do fib(n-1) + fib(n-2) end

IO.puts Fib.fib(46)

Is not TCO. Also, it’s a script because of it’s extension. Please rename a file to fib.ex and use instead something like:

defmodule Fib do
  def fib(curr \\ 1, acc \\ 0, n)
  def fib(_, acc, n) when n <= 0, do: acc
  def fib(curr, acc, n), do: fib(acc, curr + acc, n - 1)

Apparently, there’s an existing PR out there for some tweaks.

1 Like

A Fibonacci benchmark?
Am I missing the value?


According to this thread using tail call qualifies as a way to cheat at performance test :smiley:


Their response:

This code no longer uses same recursive formula F_n = F_n-1 + F_n-2 as C and other correct submission does

long fib(long n) {
  if (n <= 1) return 1;
  return fib(n - 1) + fib(n - 2);

This is not competition how you can cheat out fastest solution but how real recursion in each language performs.



1.) The fact that a language/platform is bothered with last call optimization is an indication that is takes recursion seriously - i.e. it’s not a cheat.
2.) If you are actually benchmarking “recursion” then choose some scenario involving mutual recursion that can’t be easily optimized away with iteration - not Fibonacci.


Well, that repo did take two years to get noticed around here …


Take this as an illustration of how uninterested people are in real results and behavior.


So, what you’re saying is that this is a benchmark administered by idiots!


Next on “Highly Relevant Benchmarks”, “Fastest Sledgehammer to cut your hair”


Yea, after seeing the objection to that PR…I don’t really understand. Decided to at least voice my confusion for other potential visitors.


I found the issue:

He created the benchmark to demonstrate Crystal. For some reason, all of the Crystal benchmarks that mention Elixir always seem to emphasize bad Elixir code to try to show off Crystal. I don’t know if it’s intentional. Reminds me of that other Crystal benchmark that was heavily discussed on here before.


Yeah there’s something odd about Crystal’s community. Crystal itself is a language that is by all accounts had a huge growth initially but I’ve seen nothing lately. It has no parallel abilities short of forking the process itself (ala python and ocaml), a very limited set of libraries, gets bested by Nim at every turn (I really need to learn Nim…), and seems to be people trying to show how fast it is in super limited tiny single-core problems (which still gets beat by Nim).


It looks pretty fantastic, yeah. They’ve done some really nice things with purity notation for procs, etc., even going so far as making a keyword func that actually is an alias for proc ... {.noSideEffects } or whatever their notation for it was. The compiler actually does some interesting static checking to verify it, though I’m not clear on exactly how accurate it is.

I think that this guy has pretty much shown he just doesn’t understand what’s going on and it’s not about malice. With that said, he clearly also isn’t interested in learning what’s going on and would rather misrepresent things than correct it. As we’ve all pretty much agreed, it’s just a matter of ignoring these kinds of things at this point.


What on earth…

$ rm fib && nim cpp -d:release fib.nim && time ./fib 
Hint: used config file '/etc/nim.cfg' [Conf]
Hint: system [Processing]
Hint: fib [Processing]
Hint:  [Link]
Hint: operation successful (11721 lines compiled; 0.152 sec total; 18.246MiB peakmem; Release Build) [SuccessX]
./fib  0.29s user 0.00s system 99% cpu 0.292 total
$ rm fib && g++ -O3 -o fib fib.cpp && time ./fib
./fib  5.84s user 0.00s system 99% cpu 5.852 total
$ rm fib && gcc -O3 -o fib fib.c && time ./fib
2971215073./fib  4.96s user 0.00s system 99% cpu 4.961 total
1 Like

I was being polite, but yes, if they play “that’s how everyone else does it” card then it would make more sense if everyone did tail call cause that’s how recursion is done, that’s what compilers expect from us :slight_smile: They are welcome to solve this without recursion in imperative languages though.

1 Like

LOL, you saw the same thing I did eh (I made an issue in the issue tracker for it). ^.^

It appears NIM is smart enough to recognize the dual-self recursion and turn it into a tested iteration instead. If I get time this evening I was thinking of looking at the generated assembly to see for sure. It’s still slower than it’s memoized version though so it is still doing some substantial work in comparison, hence why I’m curious. I’m wondering if it manages to collapse the 2 internal fib calls together and keep the 2 values. Impressive if so. Whatever the change was I think it only happened in NIM 0.19.0 as 0.18 on the readme itself did not have such a boost (though still the fastest).

I am personally a huge fan of compilers optimizing Everything, as long as it still maps all inputs to all outputs as I expect, which is why I keep meaning to look at NIM. :slight_smile:

To be honest though, he only did it to compare crystal to ruby, he just added in the others because he was ‘curious’ how crystal did among others.