2011-01-05 32 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); 
}