2012-07-31 10 views
6

Właśnie zaimplementowałem (jeszcze raz) szablon rekurencyjny do obliczania silni liczby całkowitej w czasie kompilacji (kto by pomyślał, że pewnego dnia będę go potrzebować!). Jednak zamiast przetaczać własne, poszedłem do Boost szukając odpowiedzi. Jednak funkcja silni w specjalnej matematyce wyraźnie zabrania jej używania z typami całkowitymi, więc napisałem własną.Obliczanie silni małej liczby całkowitej w czasie kompilacji

Nadal czy jest jeszcze inna funkcja w Boost, której powinienem użyć? Czy powinienem rzucić moją liczbę całkowitą na double i użyć funkcji boost::factorial? Czy obliczenia wykonywane są w czasie kompilacji?

+0

Istnieje ograniczona głębia, na której szablon może się powtarzać, więc przyspieszenie IRL z obliczania silni podczas kompilacji nie jest zbyt duże (szczególnie, jeśli używasz programowania dynamicznego). –

+0

Zobacz odpowiedź "R .." pod tym pytaniem: http://stackoverflow.com/questions/3786207/howto-compute-tactiv-ofactor-x. Przepełnienie jest bardzo prawdopodobne, dlatego Boost nie chce, abyś użył int do tego. – mwigdahl

+0

@mwigdahl Mogę zmieścić do 20! do niepodpisanego długiego int, który jest większy niż to, czego potrzebuję (jednak sprawdzenie przepełnienia byłoby jednym z powodów, które skłoniłyby mnie do preferowania używania funkcji bibliotecznej, moja implementacja tego nie sprawdza). – gnzlbg

Odpowiedz

9

Nie trzeba Boost to tylko 1-liner, jeśli masz C++ 11:

constexpr uint64_t factorial(uint64_t n) { 
    return n == 0 ? 1 : n * factorial(n-1); 
} 

i będzie działać, nawet jeśli arg nie jest zbyt stały czas kompilacji. uint64_t będzie działał z n < 21.

Jeśli robisz to w czasie kompilacji i mnożysz z wartością zmiennoprzecinkową - nie będzie żadnych kosztów konwersji (konwersja będzie również w czasie kompilacji).

3

Ponieważ istnieje ograniczona liczba silni, które mieszczą się wewnątrz liczby całkowitej, można wstępnie wstępnie obliczyć pierwsze 20 wartości ręcznie i zapisać je w globalnej lub statycznej tablicy. Następnie za pomocą funkcji globalnego lub statyczne do wyszukiwania silni w tablicy:

#include <iostream> 

const int factorials[] = 
{ 
    1, 
    1, 
    2, 
    6, 
    24, 
    // etc... 
}; 

inline const int factorial(int n) {return factorials[n];} 

int main() 
{ 
    static const int fourFactorial = factorial(4); 
    std::cout << "4! = " << fourFactorial << "\n"; 
} 

Jeśli używasz dosłownym jako argument do factorial, to kompilator powinien po prostu zastąpić wywołanie funkcji z wynikiem (po optymalizacji jest włączona). Próbowałem powyższy przykład w Xcode 4.4 (na komputerze Mac) i widzę w zespole, który inicjuje fourFactorial ze stałą 24:

.loc 1 20 38 ## /Users/emile/Dev/sandbox/sandbox/main.cpp:20:38 
movl $24, __ZZ4mainE13fourFactorial(%rip) 

Metoda ta może skutkować szybszym kompilacji niż za pomocą rekurencyjnego kompilacji wydziwianie.

Powiązane problemy