Почему так происходит?
От: DangerMan  
Дата: 27.09.07 20:43
Оценка:
Вычисление чисел Фибоначчи, по всем, наверное, хорошо известному примитивному алгоритму. Для достаточно больших значений (>45) вычисляется очень долго. При реализации на С++ была идея перенести вычисления на стадию компиляции. Но! Обнаружилось что и сборка исходика, и выполнение делаются практически моментально и никак не похоже, что в это время что-то вычисляется. Хотя я считал, что компилироваться это должно очень долго. Почему так происходит?

#include <stdio.h>
#include <stdlib.h>

unsigned long long fib(unsigned long long n) {
    if (n < 2) {
        return n;
    } else {
        return fib(n - 1) + fib(n - 2);
    }
}

int main(int argc, char** argv) {
    if (argc < 2) {
        return EXIT_SUCCESS;
    }
    long long n = atoll(argv[1]);
    unsigned long long res = fib(n < 0 ? -n : n);
    if (n < 0 && (n % 2) == 0) {
        printf("%lld\n", -res);
    } else {
        printf("%llu\n", res);
    }
    return EXIT_SUCCESS;
}


Это-же самое, переписанное на C++:

#include <cstdio>
#include <cstdlib>
#include <stdexcept>

template <int N> struct Fib { static const unsigned long long VALUE = Fib<N - 1>::VALUE + Fib<N - 2>::VALUE; };
template <> struct Fib<0> { static const unsigned long long VALUE = 0; };
template <> struct Fib<1> { static const unsigned long long VALUE = 1; };

#define FIB_V(n) (Fib<(n)>::VALUE)

unsigned long long fib(unsigned long long n) {
    static const unsigned long long fib_nums[] = {
        FIB_V(0), FIB_V(1), FIB_V(2), FIB_V(3), FIB_V(4), FIB_V(5), FIB_V(6), FIB_V(7), FIB_V(8), FIB_V(9),
        FIB_V(10), FIB_V(11), FIB_V(12), FIB_V(13), FIB_V(14), FIB_V(15), FIB_V(16), FIB_V(17), FIB_V(18), FIB_V(19),
        FIB_V(20), FIB_V(21), FIB_V(22), FIB_V(23), FIB_V(24), FIB_V(25), FIB_V(26), FIB_V(27), FIB_V(28), FIB_V(29),
        FIB_V(30), FIB_V(31), FIB_V(32), FIB_V(33), FIB_V(34), FIB_V(35), FIB_V(36), FIB_V(37), FIB_V(38), FIB_V(39),
        FIB_V(40), FIB_V(41), FIB_V(42), FIB_V(43), FIB_V(44), FIB_V(45), FIB_V(46), FIB_V(47), FIB_V(48), FIB_V(49),
        FIB_V(50), FIB_V(51), FIB_V(52), FIB_V(53), FIB_V(54), FIB_V(55), FIB_V(56), FIB_V(57), FIB_V(58), FIB_V(59),
        FIB_V(60), FIB_V(61), FIB_V(62), FIB_V(63), FIB_V(64), FIB_V(65), FIB_V(66), FIB_V(67), FIB_V(68), FIB_V(69),
        FIB_V(70), FIB_V(71), FIB_V(72), FIB_V(73), FIB_V(74), FIB_V(75), FIB_V(76), FIB_V(77), FIB_V(78), FIB_V(79),
        FIB_V(80), FIB_V(81), FIB_V(82), FIB_V(83), FIB_V(84), FIB_V(85), FIB_V(86), FIB_V(87), FIB_V(88), FIB_V(89),
        FIB_V(90), FIB_V(91), FIB_V(92), FIB_V(93)
    };
    if (n < (sizeof(fib_nums) / sizeof(fib_nums[0]))) { return fib_nums[n]; }
    else { throw std::overflow_error("overflow error"); }
}

int main(int argc, char** argv) {
    if (argc < 2) {
        return EXIT_SUCCESS;
    }
    long long n = std::atoll(argv[1]);
    try {
        unsigned long long res = fib(n < 0 ? -n : n);
        if (n < 0 && (n % 2) == 0) {
            std::printf("%lld\n", -res);
        } else {
            std::printf("%llu\n", res);
        }
    } catch (std::overflow_error const& e) {
        std::printf("%s!\n", e.what());
    }
    return EXIT_SUCCESS;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.