2011-01-05 68 views
3

我使用編譯時INT權力的計算能力,計算ñ** P。它使用整數。 我想計算一些比int更大的東西,好嗎? 它符合u64(無符號long long)。 C++模板可以在u64上進行編譯時計算嗎?枚舉不能做到這一點。 雙打?可能嗎?編譯時間模板化C++計算無符號long long?雙打?

我真正想要的類型來精氨酸的模板。可能嗎 ? 我的編譯器不是C++ 0x。

感謝 安德烈

template<int N, int P> struct Power { 
    enum { val = N * Power<N, P-1>::val }; 
}; 

template<int N> struct Power<N, 0> { 
    enum { val = 1 }; 
}; 

int result = Power<2, 5>; // 2**5 == 32 
+0

對於那些在今年閱讀+ + C + + 11和更新版本支持constexpr,它是一個更簡單,更美麗,做同樣的工作。 – 2013-04-21 21:00:57

回答

3

是的,你可以在任何原始的整數類型做編譯時計算。但是,您不能對浮點值進行計算,因爲模板無法通過這些值進行參數化。即將到來的C++ 0x標準將引入特殊的類來進行編譯時理性計算,所以如果你願意,你可以使用它。

+0

你說的是,在c0x C++之前,這是不可能的,對。 – Andrei 2011-01-05 20:35:57

+0

在當前C++標準中可以使用整型。如果你想投入精力這樣做,你可以建立編譯時理性的算術庫,以便它們能夠與當前的C++一起工作 - 它們不使用任何特殊的語言特性 - 但工作已經爲你完成了在C++ 0x。並且C++ 0x和當前C++都不支持具有實值參數的模板。 – templatetypedef 2011-01-05 20:37:27

2
template<int N, unsigned int P> struct Power { 
    static const unsigned long long val = N * Power<N, P-1>::val; 
}; 

template<int N> struct Power<N, 0> { 
    static const unsigned long long val = 1; 
} 

注意,我做了一個Punsigned int,因爲你的模板將失敗負值。

+0

這不會編譯pre-c0x。 – Andrei 2011-01-05 20:34:03

+0

@Andrei:爲什麼不呢? VC9和[Comeau Online](http://www.comeaucomputing.com/tryitout/)都接受它。 – sbi 2011-01-05 20:45:11

+0

@Andrei:您現在已經使用過兩次「pre-c0x」,所以我不認爲這是一個錯字。下一個(和第三版)的C++被稱爲C++ 0x,所以你應該使用「pre-C++ 0x」來引用以前的版本。 C0x也可能與[C1X](http://en.wikipedia.org/wiki/C1X)混淆,這是C標準的下一個版本,我之前已經將它命名爲C0X。 – 2011-01-06 13:05:50

2

要擴大SBI的實施,這裏是一個沒有冪按平方(這需要較大的功率更少的模板實例)。

請注意,如果你真的只需要計算2的冪,你好得多僅僅左移(即2**x == 1 << x),而不是做這一切的模板的東西。

#include <iostream> 

template <unsigned long long N, unsigned int P, int Odd = (P&1)> struct Power; 

template <unsigned long long N, unsigned int P> 
struct Power<N,P,0> { // even (square N and halve the power) 
    static const unsigned long long val = Power<N*N,(P/2)>::val; 
}; 

template <unsigned long long N, unsigned int P> 
struct Power<N,P,1> { // odd (multiply by N and decrement the power) 
    static const unsigned long long val = N * Power<N,(P-1)>::val; 
}; 

template <unsigned long long N> 
struct Power<N,0,0> { // zero (x**0 is 1 for all x != 0) 
    static const unsigned long long val = 1; 
}; 

int main() { 
    std::cout << "2**0 = " << Power<2,0>::val << "\n"; 
    std::cout << "2**1 = " << Power<2,1>::val << "\n"; 
    std::cout << "2**2 = " << Power<2,2>::val << "\n"; 
    std::cout << "2**3 = " << Power<2,3>::val << "\n"; 
    std::cout << "2**4 = " << Power<2,4>::val << "\n"; 
    std::cout << "2**5 = " << Power<2,5>::val << "\n"; 
    std::cout << "2**6 = " << Power<2,6>::val << "\n"; 
    std::cout << "2**7 = " << Power<2,7>::val << "\n"; 
    std::cout << "2**8 = " << Power<2,8>::val << "\n"; 
    std::cout << "2**9 = " << Power<2,9>::val << "\n"; 
    std::cout << "2**10 = " << Power<2,10>::val << "\n"; 
    std::cout << "2**11 = " << Power<2,11>::val << "\n"; 
    std::cout << "2**12 = " << Power<2,12>::val << "\n"; 
    std::cout << "2**30 = " << Power<2,30>::val << "\n"; 
    std::cout << "2**40 = " << Power<2,40>::val << "\n"; 
    std::cout << "2**50 = " << Power<2,50>::val << "\n"; 
    std::cout << "2**60 = " << Power<2,60>::val << "\n"; 
    return 0; 
} 

聲明:我不作任何索賠,該代碼必然編譯更快,因爲在模板實例的數量的減少(儘管它可能)。我真的只是把它寫成玩具演示。我把它作爲一個練習的讀者寫一個版本,是不是容易受到別人使用Power<>時明確地傳遞一個值的Odd參數。

+0

'template struct Power {enum {Odd = P &1 }; static const unsigned long long val =(Odd?N:1)* Power :: val; } - 減少33%的模板,減少一半的代碼,刪除奇怪的bug。 – Yakk 2013-01-04 20:18:25

2

您可以使用多精度數學的方法計算大量的(在我的例子下面我用96位的計算與3模板參數,你可以使用任何常數)。您需要有多個整數作爲模板參數。

在執行編譯時乘法時,應該乘以具有64位結果的32位數;結果應該分成2個模板參數。

溢出檢查可能是可能的,但可能會非常棘手。

const uint64_t W = 1000000000; // word size: 2^32 is best; any smaller number is OK 
// I use a power of 10 as word size for ease of printing (see main() below) 

// The following class performs multiplication of (n0 + W*n1 + W*W*n2) by (base) 
template <unsigned n0, unsigned n1, unsigned n2, uint64_t base, unsigned p> class power_temp 
{ 
    typedef power_temp< 
     n0 * base % W, 
     n1 * base % W + n0 * base/W, 
     n2 * base % W + n1 * base/W, 
     base, p - 1> mult_type; 
public: 
    static const unsigned x0 = mult_type::x0; 
    static const unsigned x1 = mult_type::x1; 
    static const unsigned x2 = mult_type::x2; 
}; 

// The following partial specialization is used to end recursion 
template <unsigned n0, unsigned n1, unsigned n2, uint64_t base> 
class power_temp<n0, n1, n2, base, 0> 
{ 
public: 
    static const unsigned x0 = n0; 
    static const unsigned x1 = n1; 
    static const unsigned x2 = n2; 
}; 

// The following class calculates a power, using compile-time calculations 
template <unsigned base, unsigned p> struct power 
{ 
    static const unsigned x0 = power_temp<1, 0, 0, base, p>::x0; 
    static const unsigned x1 = power_temp<1, 0, 0, base, p>::x1; 
    static const unsigned x2 = power_temp<1, 0, 0, base, p>::x2; 
}; 

int main() 
{ 
    typedef power<123456789, 3> my1; 
    printf("%09d%09d%09d\n", my1::x2, my1::x1, my1::x0); 

    typedef power<5, 33> my2; 
    printf("%09d%09d%09d\n", my2::x2, my2::x1, my2::x0); 
}