Finding the closest fibonacci numbers

前端 未结 11 2180

I am trying to solve a bigger problem, and I think that an important part of the program is spent on inefficient computations.

I need to compute for a given number N, th

11条回答
  •  醉酒成梦
    2021-02-02 14:05

    Build a table of Fibonacci numbers that will fit in 8 bytes; there's only 94. That will save you calculating them through each iteration. There's no need for floating point math here.

    Then use a binary search to find the number below and above your number in the time. That will save you comparing all the numbers, and reduce your search to a constant search time.

    This meets your requirements, but note that your requirements do not specify what should be returned for N such that there is no Q in 64 bit integer space, i.e. N > 12,200,160,415,121,876,738. If you care about that, decide how you want to handle it. :)

    #include "stdint.h"
    #include "stdio.h"
    #include "stdlib.h"
    #include "time.h"
    
    /* build a table of all fibonacci numbers that fit in a uint64_t. */
    static const int fibonacciCount = 94;
    uint64_t fibonacciSequence[fibonacciCount];
    static void precalc(void) {
        fibonacciSequence[0] = 0;
        fibonacciSequence[1] = 1;
        for (int i = 2; i < fibonacciCount; ++i) {
            fibonacciSequence[i] = fibonacciSequence[i-2] + fibonacciSequence[i-1];
        }
    }
    
    /* do a binary search for the Fibonacci numbers >= N and <= N */
    static void find_closest_fibonacci(uint64_t N, uint64_t *P, uint64_t *Q) {
        int upper = fibonacciCount;
        int lower = 0;
        do {
            int mid = ((upper - lower) >> 1) + lower;
            uint64_t midValue = fibonacciSequence[mid];
            if ( midValue > N ) {
                upper = mid;
            } else if ( midValue < N ) {
                lower = mid + 1;
            } else {
                *P = fibonacciSequence[ mid ];
                *Q = fibonacciSequence[ mid ];
                return;
            }
        } while ( upper > lower );
        *P = fibonacciSequence[ lower - 1 ];
        *Q = fibonacciSequence[ lower ];
    }
    
    /* hacked together 64 bit random number generator,
     used just in tester only */
    static uint64_t rand64(void) {
        /* totally flawed as a random number generator,
         but that's not the point here. */
        uint64_t v = 0;
        for (int i = 0; i < 8; ++i) {
            v = (v << 8) + (rand() % 256);
        }
        return v;
    }
    
    int main (int argc, const char * argv[]) {
        srand( (unsigned)time( NULL ) );
    
        precalc(); /* do this once only */
    
        uint64_t upperBound = fibonacciSequence[fibonacciCount - 1];
        printf( "Upper bound is %qu\n", upperBound );
    
        /* build a sample to run against the algorithm
         we favor mostly numbers below RAND_MAX, because
         if we test across all of UINT64_MAX the results are
         pretty boring. */
        static const int sampleCount = 100;
        static const int normalSampleCount = 90;
        uint64_t numbers[sampleCount];
        for (int i = 0; i < normalSampleCount; ++i) {
            numbers[i] = rand();
        }
        for (int i = normalSampleCount; i < sampleCount; ++i) {
            uint64_t number;
            do {
                number = rand64();
            } while ( number > upperBound );
            numbers[i] = number;
        }
    
        /* use described algorithm */
        for (int i = 0; i < 100; ++i) {
            uint64_t P;
            uint64_t Q;
            uint64_t N = numbers[i];
            find_closest_fibonacci(N, &P, &Q);
            printf( "%qu [%qu,%qu]\n", N, P, Q );
        }
    
        return 0;
    }
    

    Put whatever other algorithm you have in the same file, and run it against the same tester.

提交回复
热议问题