1

Given an number A, I want to find the Ath Fibonacci number that is multiple of 3 or if the number representation has at least a 3 on it.

Example:

Fibonacci > 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, ...

Input: 1, Output: 3;

3 is the first Fibonacci number that is multiple of 3 or has an 3 on it.

Input: 3, Output: 21;

21 is the third Fibonacci number that is multiple of 3 or has an 3 on it.

Edit: Variable type changed to unsigned long long int and ajust on Fibonacci generator. Thanks @rcgldr and @Jarod42 for the help!

My code:

#include<bits/stdc++.h>

using namespace std;

int tem(unsigned long long int i){

    while(i != 0){
        if(i%10 == 3){
            return true;
        }
        i = i/10;
    }
    return false;
}

int main(){

    int a, count = 0;
    unsigned long long int f1 = 1, f2 = 1;

    while(scanf("%d", &a) != EOF){
        for(unsigned long long int i = 2; i > 0; i++){
            i = f1 + f2;
            f1 = f2;
            f2 = i;
                if((i%3 == 0) || tem(i)){
                    count++;
                    if(count == a){
                        cout << i << endl;
                        break;
                    }
                }

        }
    }
}

When A > 20, it starts to slow down. Makes sense because it tends to be exponecial. My code is not very efficient, but I didn't find an better logic to use.

I looked into these links, but didn't find an conclusion:

1 - Recursive Fibonacci

2 - Fibonacci Optimization

Any ideas? Thanks for the help!

Community
  • 1
  • 1
Katreque
  • 338
  • 1
  • 4
  • 11
  • 2
    If the number in question isn't too large you can use Binet's Formula to calculate the nth Fibonacci Number. See: http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibFormula.html#section1 – mba12 Mar 30 '17 at 19:47
  • Isn't every 4th number dividable by 3? And only those? – MSalters Mar 30 '17 at 19:49
  • @mba12 Tha's some great stuff to read; Thanks for the link! – Katreque Mar 30 '17 at 19:53
  • @MSalters Yep. According to this link, I think it is true. http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibtable.html – Katreque Mar 30 '17 at 19:58
  • `if(i == (f1 + f2))` ? go directly to `i = fi + f2`... – Jarod42 Mar 30 '17 at 19:58
  • @Jarod42 Good point my friend! I fixed it and it is a lot better. When I try A <= 40, it works really well. However, after that I starts to get slow again. – Katreque Mar 30 '17 at 20:14
  • `while(i%10 !=0)` should be `while(i !=0)` – Jarod42 Mar 30 '17 at 20:16

3 Answers3

2

You can speed up the Fibonacci part using this sequence

uint64_t f0 = 0;    // fib( 0)
uint64_t f1 = 1;    // fib(-1)
int n = ... ;       // generate fib(n)
    for(int i = 0; i < n; i++){
        std::swap(f0,f1);
        f0 += f1;
    }

Note Fib(93) is the maximum Fibonacci number that fits in a 64 bit unsigned integer, it also has a 3 in it. Fib(92) is the maximum Fibonacci number that is a multiple of 3.

I used this example code to find all of the values (a ranges from 0 to 62), it seems to run fairly fast, so I'm not sure what the issue is. Is optimization enabled?

#include <iostream>
#include <iomanip>

typedef unsigned long long uint64_t;

int tem(uint64_t i){
    while(i != 0){
        if(i%10 == 3)
            return true;
        i = i/10;
    }
    return false;
}

int main(){
    int a = 0, n;
    uint64_t f0 = 1, f1 = -1;  // fib(-1), fib(-2)

    for(n = 0; n <= 93; n++){
        std::swap(f0, f1);     // f0 = next fib
        f0 += f1;
        if((n&3) == 0 || tem(f0)){
            std::cout << std::setw( 2) << a << " " 
                      << std::setw( 2) << n << " "
                      << std::setw(20) << f0 << std::endl;
            a++;
        }
    }
    return 0;
}

Depending on the compiler, i%10 and i/10 may use a multiply by "magic number" and shift to replace divide by a constant. Code generated by Visual Studio 2015 for tem(), which is fairly "clever":

tem     proc                                ;rcx = input
        test    rcx,rcx                     ; return false if rcx == 0
        je      SHORT tem1
        mov     r8, 0cccccccccccccccdh      ;magic number for divide by 10
tem0:   mov     rax, r8                     ;rax = magic number
        mul     rcx                         ;rdx = quotient << 3
        shr     rdx, 3                      ;rdx = quotient
        lea     rax, QWORD PTR [rdx+rdx*4]  ;rax = quotient*5
        add     rax, rax                    ;rax = quotient*10
        sub     rcx, rax                    ;rcx -= quotient * 10 == rcx % 10
        cmp     rcx, 3                      ;br if rcx % 10 == 3
        je      SHORT tem2
        mov     rcx, rdx                    ;rcx = quotient  (rcx /= 10)
        test    rdx, rdx                    ;loop if quotient != 0
        jne     SHORT tem0
tem1:   xor     eax, eax                    ;return false
        ret     0

tem2:   mov     eax, 1                      ;return true
        ret     0

tem     endp
rcgldr
  • 27,407
  • 3
  • 36
  • 61
  • Thanks for the help! However, we have an missunderstanding here. _"**or ** if the number representation has at least a 3 on it."_ If the number has a 3 on it, like 13, it should be accepted too. Just like the multiples of 3. – Katreque Mar 30 '17 at 20:28
  • @Katreque - I missed the "or has a 3 ...". I updated my answer. – rcgldr Mar 30 '17 at 20:37
  • The type of int is a good point. If we consider A > 60, the numbers start to pass an long long int. I will update to an **unsigned long long int**. I didn't even know about this swap func. Is it faster then `for(unsigned long long int i = 2; i > 0; i++) i = f1 + f2; f1 = f2; f2 = i;` ? – Katreque Mar 30 '17 at 20:45
  • @Katreque - depends on compiler optimizations and if the processor has a `swap` instruction.. Assuming f0 and f1 are in registers, for X86 or X64, there is an `xchg` instruction to do the swap, and the sequence could be something like `xchg r8,r9` | `add r8,r9` , just two instructions. – rcgldr Mar 30 '17 at 20:48
  • I think I got it. My knowledge about registers and low level information is not that good, but it is a starting point for me to dig a bit more. Really appreciate for sharing! – Katreque Mar 30 '17 at 20:56
  • @Katreque - I updated my answer to show an example that displays all of the numbers. – rcgldr Mar 30 '17 at 22:28
  • Very nice! Didn't know VS could do this kind of thing. Now my code are running very fast. It finds fib(93) almost instanly! I will try to find the execution time using iteration or swap. Pretty sure your runs faster. Well, thanks for the big help my friend. I learned a lot! Thank you again! – Katreque Mar 31 '17 at 12:43
  • @Katreque - if you mean replacing divide by constant with multiply and shift, GCC compiler also does this. Take a look at [why gcc uses strange number for divide](http://stackoverflow.com/questions/41183935/why-does-gcc-use-multiplication-by-a-strange-number-in-implementing-integer-divi/41224096#41224096) . For older processors this didn't do much, but with newer processors, multiply is 7x or more times as fast as divide (for 64 bit). – rcgldr Mar 31 '17 at 12:51
  • That's really clever! Thank you again for the link. Time to read and learn. It's new for me. – Katreque Mar 31 '17 at 12:59
  • @Katreque - I forgot to note my answer was to optimized the questions example. Faster still would be the [Lucas sequence method](https://en.wikipedia.org/wiki/Lucas_sequence#Specific_names), which is like an optimized version of raising a [matrix](https://en.wikipedia.org/wiki/Fibonacci_number#Matrix_form) to a [power via squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring). – rcgldr Jul 08 '18 at 01:52
1

Just pointing out some obvious coding errors

for(unsigned long long int i = 2; i > 0; i++)

is redundant.

for(;;){ 
  unsigned long long i = f1+f2;

should suffice. Secondly

return 0; 

is meaningless because it breaks out of the while loop. A break would be better.

Joe Chakra
  • 56
  • 3
1

There's a clever way to do Fibonacci.

http://stsievert.com/blog/2015/01/31/the-mysterious-eigenvalue/

Code's in python and is just for the nth number, but I think you get the idea.

def fib(n):
    lambda1 = (1 + sqrt(5))/2
    lambda2 = (1 - sqrt(5))/2
    return (lambda1**n - lambda2**n) / sqrt(5)
def fib_approx(n)
    # for practical range, percent error < 10^-6
    return 1.618034**n / sqrt(5)
Almo
  • 15,538
  • 13
  • 67
  • 95
  • Thanks for sharing! I will try to implement in C++ and see how fast it is and compare with my code. – Katreque Mar 31 '17 at 15:36