Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Fibo Golf challenge on 3 monkeys

by RMGir (Prior)
on Jul 13, 2007 at 12:32 UTC ( [id://626425]=obfuscated: print w/replies, xml ) Need Help??

Over on the 3monkeys blog, they've posted a challenge to golf down the calculation and display of the first 20 fibonacci numbers.

I only got it as far as:

perl -e'@p=(1,1);map@p=(@p,$p[-1]+$p[-2]),A..R;$\=$,="\n";print@p'
I'm sure someone here can do much better...

Mike

Replies are listed 'Best First'.
Re: Fibo Golf challenge on 3 monkeys
by ambrus (Abbot) on Jul 16, 2007 at 09:07 UTC

    Let's see. We already have lots of fibonacci generator threads, like (OT) Fibonacci numbers in Ruby - final shot - 24 chars, Golfing a fibonacci number generator, Fibonacci Numbers, Fibonacci numbers (again)1 Fibonacci golf with one state variable1. We can use some ideas from those threads.

    Firstly, modifying my dc solution, we get

    dc -e1dp[pdsd+ldrlxx]dsxx|head -20

    Then there's the ruby one you can adapt

    ruby '-wex=i=1;20.times{p x;x+=i=x-i}'

    I'll try to improve these and update this node later if I can.

    Update: longer variants of the ruby line are:

    ruby '-wep 1,x=1;18.times{p x=(x/0.618).round}'
    or
    ruby '-we20.times{|x|p((1.61803**x/1.382).round)}'

    Update: I forgot to tell, but for just the first twenty numbers, the shorter dc one should work fine as well:

    dc -e1pd[pdk+Krlxx]dsxx|head -20
    Update: The following which doesn't use head is even shorter
    dc -e1pd[rpdk+Kd6666\>x]dsxx
    The following is yet one character shorter, but it takes some seconds to compute because it computes square roots to thousands of decimal places.
    dc -e1pd[rpdk+Kdv66\>x]dsxx
    Update: Even shorter and does not have the speed penalty is this:
    dc -e1pd[pdk+KrdZ5\>x]dsxx

    Update: And you can cut one more character:

    dc -e1d[prdk+KdZ5\>x]dsxx

    Update 2008 oct 5: added two links marked by 1.

      Not implemented yet because we just added it, but in Perl 6 you can just say:
      .say for 1,1...{$^a+$^b}
      or alternately:
      .say for 1,1...&infix:<+>
      The latter is likely to be more efficient, since it calls the builtin addition operator without the extra layer of function call implied by the first one (unless we get really fancy with the optimizer and notice it's an identity wrapper).

      Either of these works because the ... operator is defined to pass the last N numbers in the list repeatedly to the generator function, where N is determined by the arity of the function, which is 2 in this case.

      Very .... is "nice" the right term? :))

      I know this is perlmonks and not dcmonks, but I'd love to see an expanded and explained version of a few of those dc variants...

      I usually only use dc for simple arithmetic and base conversions, so those look like looking at APL and not knowing the keys, to me.


      Mike

        Right... let's look at this first

        dc -e1dp[pdsd+ldrlxx]dsxx|head -20

        This is my original infinite fibonacci sequence generator from Re: Fibonacci numbers (again), but I quickly added a head statement to limit it to 20 lines and a p statement to print an addittional 1 (this latter extra can be eliminated, but this was just the first attempt).

        In this, you have to look at the loop body, which is pdsd+ldr which breaks into six statements: p d sd + ld r. It's easiest if we trace through the execution of this in a later iteration. (The stack is shown with the top first.)

        stack cmd meaning 8 5 p prints the top of stack with a newline, without popping 8 5 d duplicate top of stack 8 8 5 sd store pop to named register "d" 8 5 + push sum of two pops 13 ld push contents of register "d" 8 13 r swap top two elements of stack 13 8

        As you can see, the stack contains a fibonacci number and the previous one before executing these statements, which they will advance to the next elements of the sequence, and print an element as a side-effect.

        At the beginning, we initialize the stack to two fibonacci numbers 1 1 by the statements 1d. Now you only have to understand the looping, which is done with recursion in dc. The loop itself is a string (which you create with square brackets). After those six statements, it does lx x which loads the same string from register "x" and executes it, while we start the loop by d sx x which duplicates the string, stores one copy to register "x", then executes it the first time.

        Now I basically use two tricks to make this shorter. The first one is to use k and K commands instead of sd and ld. These store in the special "scale" register, which affects the results in division and modulo and other similar operations, but that won't make too much difference in our script. That register can only store a nonnegative integer and is usually capped from above, but if we need only the first twenty elements, that's not a problem.

        The second is that instead of using |head -20, I limit the loop to the first 20 numbers in the dc script itself. This is done by the >x statement which compares two popped numbers and runs the macro in register "x" iff the first number is greater than the second. In the final version, I use the comparision on the length (number of digits, Z) of a fibonacci number with 5, because this seems to be the shortest. Other attempts (not all in the thread) compare a counter in a register I decrease every time, the fibonacci number itself, the square root of the fibonacci number, and the stack length (z) which then I increased by leaving an unused stack element in every iteration.

        Update: fixed link to original post about dc fibonacci.

Re: Fibo Golf challenge on 3 monkeys
by johnlawrence (Monk) on Jul 13, 2007 at 15:46 UTC
    How about:
    perl -e '$a-=$b=1;for(A..T){print$c=$a+$b,"\n";$a=$b;$b=$c;}'
    Or:
    perl -e '$b-=$a=1;for(A..T){$c=$a;print$a+=$b,"\n";$b=$c}'
      A tiny improvement, substituting $/ for "\n":
      perl -e '$b-=$a=1;for(A..T){$c=$a;print$a+=$b,$/;$b=$c}'

      --chargrill
      s**lil*; $*=join'',sort split q**; s;.*;grr; &&s+(.(.)).+$2$1+; $; = qq-$_-;s,.*,ahc,;$,.=chop for split q,,,reverse;print for($,,$;,$*,$/)
        I can shave off a couple characters by leveraging the fact that the length of the sequence is even. Also, the OP's sequence starts with F1=1, so if I start there too I don't have to initialize both variables.
        perl -e '$a=1;for(A..J){print$a+=$b,$/,$b+=$a,$/}'
        Update: Now that the loop is down to 1 statement I can switch to a postfix for. I can also fold the initialization into the loop.
        perl -e 'print$a+=$b||1,$/,$b+=$a,$/for A..J'
        ... and if you feel strongly about starting with F0=0,
        perl -e 'print$a+=$b,$/,$b+=$a||1,$/for A..J'
Re: Fibo Golf challenge on 3 monkeys
by shmem (Chancellor) on Jul 16, 2007 at 10:03 UTC
    thospel did say on #perlgolf (ircnet) without much thinking -
    perl -le'print$,=$.+++($.=$,||1)for h..z'
    ;-)

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      The output of this code starts at F(2)=1, which is somewhat non-standard. A minor change causes the output to begin at F(1)=1 like that of the OP's code.
      perl -le'print$,=$.+++($.=$,)||1for h..z'
Re: Fibo Golf challenge on 3 monkeys
by sh1tn (Priest) on Jul 21, 2007 at 12:24 UTC
    The same old story :)
    perl -e 'print$}+=$.=$}-$.||1,$/for+e..x' ruby -e 'x=-1;20.times{p$.+=x=$.-x}' ruby -e 'x=-1;(1..20).map{p$.+=x=$.-x}'


Re: Fibo Golf challenge on 3 monkeys
by Anonymous Monk on Jul 18, 2007 at 15:12 UTC
    I worked on this a while ago, and I know that this isn't the least possible, but 49 characters is what I got down to...

    die map{int(((1+($^=5**.5))/2)**$_/$^+.5).$/}0..9

    This uses a shortened version of the formula used to calculate the next number using Phi, as opposed to just adding the last two together. I'm pretty sure this can be shortened, I'm just not sure how at the moment... :) Good luck!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: obfuscated [id://626425]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (5)
As of 2024-04-16 07:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found