Fibonacci products

13

You can decompose a number greater than 0 as a unique sum of positive Fibonacci numbers. In this question we do this by repeatedly subtracting the largest possible positive Fibonacci number. E.g.:

1 = 1
2 = 2
3 = 3
4 = 3 + 1
12 = 8 + 3 + 1
13 = 13
100 = 89 + 8 + 3

Now, I call a Fibonacci product the same lists as above, but with the addition replaced by multiplication. For example, f(100) = 89 * 8 * 3 = 2136.

Write a program or function that given a positive integer n returns the Fibonacci product of that number.


Testcases:

1: 1
2: 2
3: 3
4: 3
5: 5
6: 5
7: 10
8: 8
9: 8
42: 272
1000: 12831
12345: 138481852236

orlp

Posted 2016-05-13T09:44:59.050

Reputation: 37 067

6The statement isn't quite correct. E.g. 2 can be decomposed as -1 + 3. The correct statement of Zeckendorf's theorem is that a positive Fibonacci number can be uniquely decomposed as a sum of non-consecutive Fibonacci numbers with positive index. – Peter Taylor – 2016-05-13T10:07:07.737

1@PeterTaylor I don't consider negative Fibonacci numbers part of the series for this question. Consecutive or not only matters when you want the indices, we do not care about the indices for this question. – orlp – 2016-05-13T10:09:05.640

1I'm not saying that you should change the question to support negative Fibonacci numbers: I'm saying that you should edit it to be explicit about the assumptions which you're making. – Peter Taylor – 2016-05-13T11:03:44.453

1@orlp consecutive or not matters quite a bit, since two different forms would give two different products. You already stated the problem in a way that already implicitly rules out consecutive Fibonacci terms, though, so there's nothing to worry about there. – hobbs – 2016-05-13T20:44:06.483

2(specifically: F(n) and F(n+1) can't both appear in the output because the algorithm guarantees that, before considering them, the remainder is already less than F(n+2) = F(n) + F(n+1)) – hobbs – 2016-05-13T20:46:20.690

Answers

5

Jelly, 16 15 bytes

Rf1+С¤ṪạµÐĿIAP

Not particularly fast or memory friendly, but efficient enough for all test cases. Try it online!

How it works

Rf1+С¤ṪạµÐĿIAP  Main link. Argument: n (integer)

         µ       Combine the chain to the left into a link.
          ÐĿ     Apply that link until the results are no longer unique.
                 Return the list of unique results.
      ¤            Combine the two links to the left into a niladic chain.
  1                  Set the left (and right) argument to 1.
   +D¡               Apply + to the left and right argument, updating the left
                     argument with the sum, and the right argument with the
                     previous value of the left one. Return the list of results.
                     Repeat this process n times.
                   This yields n + 1 Fibonacci numbers, starting with 1, 2.
R                  Range; map k to [1, ..., k].
 f                 Filter; keep the items in the range that are Fibonacci numbers.
       Ṫ           Tail; yield the last one or 0 if the list is empty.
        ạ          Absolute difference with k.
                   This is the argument of the next iteration.
            I    Compute the increments of the arguments to the loop, yielding
                 the selected Fibonacci numbers (with changed sign).
             A   Apply absolute value to each.
              P  Compute their product.  

Dennis

Posted 2016-05-13T09:44:59.050

Reputation: 196 637

6This seems big, Dennis. – orlp – 2016-05-13T16:32:16.670

9

Python, 54 bytes

f=lambda n,a=1,b=1:n<1or b>n and a*f(n-a)or f(n,b,a+b)

Just some good old recursion.

Sp3000

Posted 2016-05-13T09:44:59.050

Reputation: 58 729

5

Perl, 69 63 + 4 (-pl61 flag) = 67 bytes

#!perl -pl61
while($_){$n=$m=1;($n,$m)=($m,$n+$m)until$m>$_;$_-=$n;$\*=$n}}{

Using:

> echo 42 | perl -pl61e 'while($_){$n=$m=1;($n,$m)=($m,$n+$m)until$m>$_;$_-=$n;$\*=$n}}{'

Ungolfed:

while (<>) {
# code above added by -p
    # $_ has input value
    # $\ = 1 by -l61
    while ($_ != 0) {
        my $n = 1;
        my $m = 1;
        while ($m <= $_) {
            ($n, $m) = ($m, $n + $m);
        }
        $_ -= $n;
        $\ *= $n;
    }
} {
# code below added by -p
    print;  # prints $_ (undef here) and $\
}

Ideone.

Denis Ibaev

Posted 2016-05-13T09:44:59.050

Reputation: 876

The explanation should mention that octal 061 is the ASCII encoding for the character '1'. Nice hack to use $\ to get it printed for near-free. – Peter Cordes – 2016-05-15T00:35:07.840

2

><>, 57 bytes

111\ ;n{/
:@+>:{:})?\$:@@
~{*}:0=?\}>:0${:})?$~:{$-$:1@?$

Expects the input number to be present on the stack at program start.

Builds up the Fibonacci sequence (f0, f1, f2, ..., fn) on the stack until a number is reached that is greater than the the input (i). Then, with a product (p) initialised to 1...

while (i != 0)
   if (fn <= i)
      i = i - fn
      p = p * fn
   else
      i = i - 0
      p = p * 1
   discard fn
output p

Try it out online!

Sok

Posted 2016-05-13T09:44:59.050

Reputation: 5 592

Nice! I suggest you post a link using an online compiler

– Luis Mendo – 2016-05-13T18:57:47.627

2

JavaScript (ES6), 78 42 bytes

f=(n,a=1,b=1)=>n?b>n?a*f(n-a):f(n,b,a+b):1

Port of @Sp3000's answer. Original 78 byte version:

f=(n,a=[2,1])=>n>a[0]?f(n,[a[0]+a[1],...a]):a.map(e=>e>n?0:(r*=e,n-=e),r=1)&&r

Neil

Posted 2016-05-13T09:44:59.050

Reputation: 95 035

1

Pyth, 28 bytes

K1WQJ0 .WgQH+Z~JZ1=*KJ=-QJ;K

I think it can be golfed much further...

Try it online!

Leaky Nun

Posted 2016-05-13T09:44:59.050

Reputation: 45 011

1

Javascript (ES6) 134 106 92 bytes

Thanks for @cat for spotting a space.

n=>{for(c=[a=b=s=1,1];a+b<=n;)a+=b,c.unshift(b+=a,a);c.map(i=>i<=n&&(n-=i)&(s*=i));alert(s)}

Just an unoptimized version made on my phone, I golf it down, once I get home. Ideas are welcome.

Bálint

Posted 2016-05-13T09:44:59.050

Reputation: 1 847

There's one superflouous whitespace. :P – cat – 2016-05-14T13:33:25.867

1

Pyth, 24 bytes

W=-QeaYh.WgQeH,eZsZ1;*FY

Try it online: Demonstration or Test Suite

Explanation:

Q is assigned with the input number.

The part h.WgQeH,eZsZ1 calculates the biggest Fibonacci number, that is smaller or equal to Q

h.WgQeH,eZsZ1
            1   start with H=Z=1
 .WgQeH         while Q >= end(H):
       ,eZsZ       H=Z=(end(Z), sum(Z))
h               first

So if Q = 10, it generates the numbers/pairs:

1 -> (1,1) -> (1,2) -> (2,3) -> (3,5) -> (5,8) -> (8,13) -> 8

The rest of the code calculates the partition and multiplies the numbers together:

W=-QeaY...;*FY    implicit: Y = empty list
     aY...        add the calculated Fibonacci number to the empty list
    e             take the last element of Y (yes the number we just added)
 =-Q              and update Q with the difference of Q and ^
W         ;       continue until Q == 0
           *FY    multiply all number in Y and print

There are obviously a lot of shorter solutions (with really bad run-times though), like *FhfqQsTyeM.u,eNsNQ1.

Jakube

Posted 2016-05-13T09:44:59.050

Reputation: 21 462

1

Haskell, 44 bytes

Yay for mutual recursion:

(a&b)c|c<1=1|b>c=a*f(c-a)|d<-a+b=b&d$c
f=0&1
  • a is the previous Fibonacci number
  • b is the current Fibonacci number
  • c is the input
  • f is the desired function

Less golfed:

(a & b) c | c == 0    = 1
          | c <  b    = a * f (c-a)
          | otherwise = b & (a + b) $ c
f x = (0 & 1) x

Michael Klein

Posted 2016-05-13T09:44:59.050

Reputation: 2 111

1

Actually, 22 bytes

W;╗uR♂F;`╜≥`M░M;╜-WXkπ

Try it online!

Explanation:

W;╗uR♂F;`╜≥`M░M;╜-WXkπ
                        (implicit input)
W                 W     while top of stack is truthy:
 ;╗                       push a copy of n to reg0
   uR♂F;                  push 2 copies of [Fib(a) for a in range(1, n+2)]
        `╜≥`M░            filter: take values where n <= Fib(a)
              M;          two copies of maximum (call it m)
                ╜-        subtract from n (this leaves n-m on top of the stack to be the new n next iteration, with a copy of m below it)
                   X    discard the 0 left over after the loop ends
                    kπ  product of all stack values

Mego

Posted 2016-05-13T09:44:59.050

Reputation: 32 998

Does Actually have its own encoding? I count 35 bytes across 22 chars. https://mothereff.in/byte-counter#W%3B%E2%95%97uR%E2%99%82F%3B%60%E2%95%9C%E2%89%A5%60M%E2%96%91M%3B%E2%95%9C-WXk%CF%80

– cat – 2016-05-14T13:31:44.567

1@cat Just like Seriously, it uses CP437. – Mego – 2016-05-14T14:56:14.313

1

RETURN, 44 bytes

[a:[a;][1$[¤¤+$a;->~][]#%$␌a;\-a:]#␁[¤][×]#]

Try it here.

Astonishingly inefficient anonymous lambda that leaves result on Stack2. Usage:

12345[a:[a;][1$[¤¤+$a;->~][]#%$␌a;\-a:]#␁[¤][×]#]!

NOTE: ␌ and ␁ are placeholders for their respective unprintable chars: Form Feed and Start of Heading.

Explanation

[                                           ]  lambda
 a:                                            store input to a
   [  ][                         ]#            while loop
    a;                                           check if a is truthy
        1$[¤¤+$a;->~][]#%                        if so, generate all fibonacci numbers less than a 
                         $␌                      push copy of TOS to stack2
                           a;\-a:                a-=TOS
                                   ␁[¤][×]#   get product of stack2

Mama Fun Roll

Posted 2016-05-13T09:44:59.050

Reputation: 7 234

I count 46 bytes across 42 chars. If RETURN uses some kinda special encoding, it should be 42 bytes across 42 chars, but it appears to be unicode, so it's 46. – cat – 2016-05-14T13:30:53.897

Actually, I just realized that I forgot to put in some unprintables. – Mama Fun Roll – 2016-05-14T17:32:13.893

I needed a microscope to tell what they are, so I linked to them for you. :D (I couldn't tell if it was SOH or BOM) – cat – 2016-05-14T17:39:03.693

0

PHP, 119 bytes

The code (wrapped on two lines for readability):

for($o=$c=1;$c<=$n=$argv[1];$f[++$k]=$c,$a=$b,$b=$c,$c+=$a);
for($i=$k;$i;$i--)for(;$n>=$d=$f[$i];$n-=$d,$o*=$d);echo$o;

The first line computes in $f the Fibonacci numbers smaller than $n (the argument provided in the command line). The second line computes the Fibonacci factors (by subtraction) and multiplies them to compute the product in $o.

Prepend the code with <?php (technically not part of the program), put it in a file (fibonacci-factors.php) then run it as:

$ php -d error_reporting=0 fibonacci-factors.php 100
# The output:
2136

Or run it using php -d error_reporting=0 -r '... code here ...' 100.

The ungolfed code and the test suite can be found on Github.

axiac

Posted 2016-05-13T09:44:59.050

Reputation: 749

0

Q, 47 Bytes

m:{*/1_-':|(0<){y-x x bin y}[*+60(|+\)\1 0]\x}

Test

+(i;m'i:1 2 3 4 5 6 7 8 9 42 1000 12345)

read it as pairs (i,map(m,i)), where m is the calculating function and i the different args

writes

1     1
2     2
3     3
4     3
5     5
6     5
7     10
8     8
9     8
42    272
1000  12831
12345 138481852236

Explanation

n funtion\arg applies function(function(function(...function(args))) n times (internally uses tal recursion), and returns the sequence of results. We calculate the 60 first items of fibonnaci series as *+60(|+\)\1 0. In that case the function is (|+): +\ applied over a sequence calculates partial sums (ex +\1 2 3 is 1 3 6), and | reverses seq. So each 'iteration' we calculate partial sums of the two previous fibonacci number and return the partial sums reversed. 60(|+\)\1 0 generates sequences 1 0, 1 1, 2 1, 3 2, 5 3, 8 5, 13 8, 21 13, ... *+ applied over this result flip (traspose) it and takes the first. Result is sequence 1 1 2 3 5 8 13 21 34 55 ..

(cond)function\args applies function(function(..function(args))) while cond true, and returns the sequence of partial results

function[arg] applied over a function of more than one argument creates a projection (partial application)

We can give name to the args, but the implicit names are x,y,z

{y-x x bin y}[*+60(|+\)\1 0] declares a lambda with args x,y with partial projection (arg x is fibonacci series, calculates as *+60(|+)\1 0). x represent fibonacci values, and y the number to process. Binary search (bin) is used to locate the index of the greater fibonacci number <=y (x bin y), and substract the corresponding value of x.

To calculate product from partial resuls we reverse them and calculate difference of each pair (-':|), drop the first (1_ because is 0) and multiply over (*/).

If we are interested in accumulated sum the code is the same, but with +/ instead of */. We can also use any other diadic operator instead of + or *

About execution efficiency

I know that in this contest efficiency is not an issue. But in this problem we can range from lineal cost to exponential cost, so i'm curious about it.

I developed a second version (length 48 Bytes excluding comment) and repeated test cases battery 1000 times on both versions.

f:*+60(|+\)\1 0;m:{*/1_-':|(0<){x-f f bin x}\x}    /new version

execution time is: original version 0'212 seg, new version 0'037 seg

Original version calculates fibbonaci serie once per function application; new version calculates fibonacci just one.

In both cases calculation of fibonacci series uses tail recursion

J. Sendra

Posted 2016-05-13T09:44:59.050

Reputation: 396