Hellow DEV community, how are you?
Can we challenge ourselves in this fun "game"?
Let's see how many languages we can enumerate by writing the Fi...
For further actions, you may consider blocking this person and/or reporting abuse
I'll continue with javascript.
(Look mum, with a single expression function!)
To be absolutely pedantic, this code is valid and will work with large numbers because it is written in EcmaScript 6. Part of the ES6 standard is for the language interpreter to implement tail call optimization (TCO). EcmaScript is a language defined by a standard, not by an implementation.
Now, at present, barely any interpreters implement TCO - here's a fun comparison table to see which do or don't. This makes me sad, but there we are.
But, as I say, the function above will work just fine according to the language standard. Whether this code blows the call stack of your interpreter is dependent on whether your interpreter implements the full ES6 standard. Which it probably doesn't.
To put it strongly, complaining that this code doesn't run on an JS interpreter without TCO is like complaining that it can't run by a Ruby interpreter. The fault is with the interpreter, not the code.
I like this! Don't think you need the outer parens though :D
Should work without, I'm just used to wrapping ternary expressions between them for some reason and I find it weird without :)
I haven't seen a SQL implementation yet, so here's one:
Here's interesting one for SQL Server with maximum value before arithmetic overflow due to data type limit:
Here it is in Oracle SQL:
The limit of 605 is the limit before numeric overflow.
👏👏 I never thought you could do that with SQL!
Fuck yes SQL!
I feel like every time someone responds to one of these with a SQL implementation that a) my heart grows a few sizes and b) they earn extra special bonus points in my head because hell yeah.
⭐️
(nonironic gold star, fwiw)
I'll follow up in C# (and LINQ):
(Look ma', single expression lambda without recursion!)
Imaginative, I like it (even if it's not recursive :P)!
I lied a bit. The recursion is there, hidden in the Aggregate function. It's the framework abstraction that masks it.
Otherwise it wouldn't qualify as an answer to OP challenge, or would it? ;)
I know nothing about C#, but I thought that the
Aggregate
function was somehow invoking an anonymous function here that given current and previous values returns the next element. If that's the case, and it's a function calling another function multiple times instead of the function invoking itself, can we still call it recursion?The
Aggregate
function is member of theEnumerable
type and applies an anonymous accumulator function looping all elements in that "array/set". Hard to tell if we can treat it as a recursion. I would have to look at the stack if there are pointers left to the originating caller.Fibonacci's sequence is strictly sequential so it works well but for more parallel calculations, like SUM, AVG, MAX, MIN accumulator functions you can do:
And it will multithread across many OS threads to achieve the best efficiency.
Edit: This is however not plain C# .Net anymore but LINQ ;)
Since I doubt anybody else is going to do it, here is an implementation in Scheme
Tested for values of
n
up to10001
.Please do not feed this troll.
He picked fib(10000) because it blows Int64 and now he's trying to victoriously convince everyone their programming language of choice is crap.
The same as if I would say I can compute and save a file containing Pi to 1e+13 numbers and don't tell anyone I have 12TB NAS storage attached...
Aleksei, if you try to work with very large numbers in Javascript, at some point (before the 10000th element in the fibonacci series) it just returns
Infinity
because it can't deal with them.man, just sit down and relax. there is no point for all this harassement.
If you think it's important enough for a code challenge to have a Javascript implementation that returns
Infinity
instead of blowing the stack for large values, be my guest and suggest an alternative implementation.Just posting the console output of calling my function with an arbitrarily long value seems rather pointless. I agree my solution is not perfect but I'd appreciate a better solution more than an error message.
I did this some time ago in Rust.
My first approach (the naive one) is very similar to @rapidnerd 's (George Marr's) solution in R and @andreanidouglas ' (Douglas R Andreani's) solution in Python:
I realized that this solution quickly exceeded in execution time for n > 40, so I optimized it using a mathematical theorem:
This means, we can break down numbers with odd indices into to numbers with about the half of the index – and do this again and again and again. This dramatically reduces execution time:
Inspired by @avalander 's answer, I also added this even faster algorithm:
fib_fast
andfib_super_fast
execute within microseconds even for higher indices. However, indices of 94 and higher cause a crash:Some performance measurements:
Just for a nice style, you could factor out the
return
s asif
is an expression...Nice!
Since writing my implementation I've remembered that the parameter
i
is unnecessary and you can decreasen
instead until it's 0.By the way, you didn't set default values for
curr
andprev
, how does that work, do you need to call it withfib_super_fast(n, 1, 0)
?Yes, I do. But I have to use fib_super_fast(n, 1, 1, 0) as my other implementations also begin with 1. The code for calling the fibonacci methods is:
Here's a Python variant for quite large numbers. Alas, due to recursion depth restrictions, any new calculated Fibonacci number should not have a larger sequence position than about 500 more than that of the highest already calculated.
Technically lazy evaluation of a endless stream is iterative, not recursive, but anyway, here is a solution in Haskell:
C++ can, of course, do it at build time with a bit of templates.
Here, we're definitely recursing - twice, because it's simpler. At runtime, it's just printing the value out that's been calculated by the compiler during the build.
I see what you did there. Trying to troll languages that you think may not have Int128 support :D. Nice try!
Funge++:
I'm just letting everyone (else) know I'm not reacting to his childish unsuccessfull trolling attempts anymore... I'm not his mother to raise him to his adulthood.
I know my shit, anyone who writes C# can see it as well. I will now just silently laugh...
No worries @avalander . You all did right, it is just JS doesn't support TCO there were some attempts (as far as I remember it is hold back by Microsoft member or committee or something like that). There is still way around - you can use trampoline
I doubt you would want to use this in production, but just to make a point.
TCO - stands for tail call optimisation, to prevent Maximum call stack error
Trampoline is the way how some compilers implement TCO, they convert recursion to a loop
UPD: read about TCO status in Chrome here stackoverflow.com/questions/427881...
Wow, that's great, I didn't know this trick, thank you!
And your point is...?
Common Lisp!
(and for the TCO crowd... it's implementation dependent, so YMMV)
I have haskell here with the best form of recursion: Self-recursion!
Here
fibs
is an infinite List of all fibonacci numbers, the!!
function returns the nth element of the list.I also have the boring tail recursive version here:
Quick bit of Python. The error handling probably isn't complete, but Python has the useful benefit here that it has native, transparent, Big Number support - you can do fib(10000) if you want (or much higher if you have the memory).
But yeah, I just noticed Douglas wanted a recusrive algorithm, whereas I've done it iteratively without thinking. In general, iterative solutions will execute faster - though this isn't always the case.
It's also rather convenient to claim that other people's proposal is incorrect because they have to implement things that your language of choice gives you for free (or, in the case of Ruby, you need to enable a runtime option; still beats Javascript's strategy of not having it at all).
According to you I should not only hack tail-call optimisation into Javascript somehow (most current runtimes don't do any kind of tail-call optimisation, ever), but roll my own custom system to handle arbitrarily large numbers. I don't really think this was the point of the challenge.
Also, let's keep in mind that my solution blows when the stack isn't big enough to keep track of all the function calls, and yours blow when the number is too large to be kept in memory. So, while in practice my solution blows much, much earlier than yours, both are, technically, incorrect if the definition of correct is that it works for all natural numbers, and they are both incorrect for the same reason: computer limitations apply.
The word you are looking for is "totality". Function is total if it returns a value for each input in the domain
An Emacs Lisp version. Warning!! This will likely freeze your Emacs!!
UPDATE
Just realized it counts as a Common Lisp version too
Modern C++ can do it more simply, though - this uses constexpr to tell the compiler that it can calculate these at build time if it wants. Using a constexpr arg (here a literal), it probably will do, but we could also pass in a variable to make it calculate it at runtime.
@mudasobwa I think pointing out a defect, or even just something that can be improved is fine. However I do think that making your point once is good enough. Also I recommend an approach where you say something like “this works fine when N is small enough, but you can extend the domain of this function to larger input values if you avoid using recursion.” If you can make your point while remaining friendly, why not do so?
I'll continue with it in R
Respectfully, if you want to help newbies on a general issue such as recursion, just make a top-level comment addressing this problem. Show an example of the problem and suggest ways it can be fixed. That way, if the community deems the comment to be helpful, it will bubble up near the top of the discussion and it will be one of the first comments that newbies encounter.
In this manner, you won't be repeating the same comment all over the place, and you will have something clear that novices can wrap their minds around. In my opinion, making grumpy statements to the effect of "this crashes when the input reaches X" doesn't really help the very novices you say you most want to reach.
Edit: Added "in my opinion" :)
You said you doubt it can compute fib(10000). What were your doubts based on if you have no clue about C#? Plain trolling.
I will be starting with python.
Lord, we got it, you're the best fibonnaci solver out there. Congratulations on this!
As a Ruby fan, I'm sure glad Ruby has such a great ambassador in here.
Argh, I was going to write a similar one in Elixir! I do like your join with the arrow!
I am using Kotlin here.
Read The Culture Map? :)