Description: This node was taken out by the NodeReaper on Jun 04, 2021 at 12:10 UTC

You may view the original node and the consideration vote tally.

    Replies are listed 'Best First'.
    RE (tilly) 1: Fibonnaci
    by tilly (Archbishop) on Oct 03, 2000 at 03:20 UTC
      Without an array and starting from 0:
      $a=$b=1;{$b-=$a+=$b*=-1;print$a,$/;999999>$a&&redo}
        Wow! Ok, I'm impressed.
          Thanks, but I stopped golfing way too soon:
          $a=1;print$a-=$b+=$a*=-1,$/while$a<10**6
    RE: Fibonnaci
    by Adam (Vicar) on Oct 03, 2000 at 03:44 UTC
      I was thinking about my post and I realized that some people might not see the usefulness of it. So I'll extend here. The Fibonnaci sequence (invented by a mathematician named Fibonnaci and fascinating because it appears everywhere in nature and is closely connected to the golden ratio) is usually defined in a recursive manner.
      sub Fib($) { my $index = shift; return 0 if 0 == $index; return 1 if 1 == $index; return Fib( $index - 1 ) + Fib( $index - 2 ); }
      Which is very (very) very slow. Try finding Fib(30). My method uses an iterative approach, here I apply it to the subroutine style as before:
      sub Fib($) { my $index = shift; my $acc = 0; my $tmp = 1; while( $index-- ) { # Swap the accumulator and the temp. # Use an Xor swap for fun and to amaze your friends. $acc^=$tmp^=$acc^=$tmp; # Add the two together and store it in the acc. $acc += $tmp; } return $acc; }
      Which is significantly faster. You could even implement it with a cache and then do all your work directly on the cache. This has the added bonus of not having to re-calculate the whole sequence every time you call Fib in a program.
      { my @cache = (0, 1); # Localized so only &Fib sees it. sub Fib($) { my $index = shift; return $cache[$index] if defined $cache[$index]; $index -= $#cache; push @cache, $cache[-1] + $cache[-2] while $index--; return $cache[-1]; } }
      All of the above code has been tested. But I offer no garauntees.
    RE: Fibonnaci
    by AgentM (Curate) on Oct 05, 2000 at 22:32 UTC
        Hey, pretty cool. I thought there was a direct formula but I was unable to find it on my first attempt (and so moved on.) So using Binet's formula we could do:
        $a=sqrt 5;print+(((1+$a)/2)**$_-((1-$a)/2)**$_)/$a,$/for 0..73 # For comparison, here is the result of the golfing # that Tilly and I participated in earlier: $a=1;print$a-=$b+=$a*=-1,$/for 0..73
        Unfortunatly, Computers have a hard time with irrational numbers (like sqrt of 5) so this results in things like 75025.0000000001 which is ok for our purposes... but if you ever use this you might want to pass it through int.

        In case you were wondering, 73 is an arbitrary stopping place. I picked it because Fib(74) is too big a number for Perl, and results in the scientific notation: 1.30496954492866e+015 which just isn't as much fun.

        Update: Of course, what we really need is a benchmark! So here is the output:

        Benchmark: timing 100000 iterations of Binet, Golf... Binet: 1 wallclock secs ( 0.70 usr + 0.00 sys = 0.70 CPU) @ 142653. +35/s (n=100000) Golf: 5 wallclock secs ( 4.75 usr + 0.00 sys = 4.75 CPU) @ 21065.9 +4/s (n=100000)
        And that's just for Fib(30)! I also tried benchmarking the recursive version... hahahaha. So that it wouldn't take all day I dropped the count down to 10 iterations... still Fib(30) though.
        Recursive: 118 wallclock secs (116.37 usr + 0.00 sys = 116.37 CPU) @ + 0.09/s (n=10)
        No Benchmark post is truly complete with out the code used:
        #!perl -w use strict; use Benchmark; # Fibonnaci Number to calculate. use vars ('$n'); # Make it global, but appease strict. $n = 30; my $iter = 100_000; timethese( $iter, { Binet => '&FibBinet($n)', Golf => '&FibGolf($n)', # Recursive => '&FibRecursive($n)', }); sub FibRecursive { my $index = shift; return 0 if 0 == $index; return 1 if 1 == $index; return FibRecursive( $index - 1 ) + FibRecursive( $index - 2 ); } sub FibGolf { my $index = shift; my $acc = 1; my $tmp; while( $index-- ) { $acc-=$tmp+=$acc*=-1; } return $acc; } sub FibBinet { my $index = shift; my $root5 = sqrt 5; return ( ( ( 1 + $root5 ) / 2 ) ** $index - ( ( 1 - $root5 ) / 2 ) ** $index ) / $root5; }
          Note that this is a classic example of a "useless formula". In real life you would never want to use it because square roots are slow to calculate. Instead you use the formula:
          F(n+m) = F(n)F(m-1) + F(n-1)F(m+1)
          This is where F is the Fibonacci function, F(0)=0, F(1)=F(2)=1. In particular you use the special cases:
          F(2n) = F(n)F(n-1) + F(n-1)F(n+1) = F(n)F(n-1) + F(n-1)(F(n) + F(n-1)) = 2F(n)F(n-1) + F(n-1)F(n-1)
          and
          F(2n-1) = F(n-1)F(n-1) + F(n-2)F(n) = F(n-1)F(n-1) + (F(n)-F(n-1))F(n) = F(n)F(n) - F(n-1)F(n) + F(n-1)F(n-1)
          to calculate the powers of two and one off from the powers of two, then when you are done go to the general formula to calculate the number.

          Now why would one do this? Well it turns out that certain numbers can be tested for primality by answering a divisibility question about some close relative of the Fibonacci numbers (eg the Lucas numbers), so most of the "record primes" that you hear about involved some very big Fibonacci numbers being calculated somewhere.

          A good exercise for anyone who is interested, use the very slow Math::BigInt to come up with a function to calculate very large Fibonacci numbers.