2011-01-05 2 views
3

나는 컴파일 시간 INT의 힘을 계산 전원, N ** P를 계산하기 위해 사용합니다. int를 사용합니다. int보다 큰 값을 계산하고 싶습니다. u64 (부호없는 long long)에 맞습니다. 는 C++ 템플릿은 컴파일 시간에 할 수있는 계산을 U64에? Enum은 이것을 할 수 없습니다. 두 배로? 가능한가?컴파일 타임 템플릿 된 C++ 계산을 부호없는 long long으로 컴파일 하시겠습니까? 복식?

은 정말 종류가 템플릿의 arg를해야 할 것입니다. 가능한가? 제 컴파일러가 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에 대한 지원을 훨씬 더 간단하고 아름답게 처리하며 동일한 작업을 수행합니다. –

답변

3

예, 당신은 어떤 원시적 인 통합 유형에 컴파일 시간을 계산을 할 수 있습니다. 그러나 부동 소수점 값에 대해 템플릿을 매개 변수화 할 수 없기 때문에 부동 소수점 값에 대한 계산을 수행 할 수 없습니다. 다가올 C++ 0x 표준은 컴파일 타임의 합리적인 산술을하기위한 특별한 클래스를 소개 할 것이므로, 원한다면 그것을 사용할 수있을 것입니다. 템플릿이 음수 값을 실패 때문에 제 자신이 unsigned intP했다

+0

pre-c0x C++에서는 이것이 가능하지 않다고 말하는 것입니다. – Andrei

+0

현재 C++ 표준에서 정수 유형을 사용할 수 있습니다. 그렇게하기 위해 에너지를 투자하고 싶다면 컴파일 타임의 합리적인 산술 라이브러리를 구축하여 현재의 C++에서 작동하도록 할 수 있습니다 - 특수 언어 기능을 사용하지는 않지만 이미 작업이 완료 될 것입니다 C++ 0x에서. 또한 C++ 0x 나 현재 C++에서는 실수 인수가있는 템플릿을 지원하지 않습니다. – templatetypedef

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; 
} 

참고.

+0

pre-c0x를 컴파일하지 않습니다. – Andrei

+0

@Andrei : 왜 안 되니? VC9와 [Comeau Online] (http://www.comeaucomputing.com/tryitout/) 모두 동의합니다. – sbi

+0

@Andrei : "pre-c0x"를 두 번 사용 했으므로 오타라고 생각하지 않습니다. C++의 다음 (및 제 3) 버전은 C++ 0x라고하며 이전 버전을 언급 할 때는 "pre-C++ 0x"를 사용해야합니다. 또한 C0x는 C 표준의 차기 버전이며 C0X라는 이전에 본 적이있는 [C1X] (http://en.wikipedia.org/wiki/C1X)와 혼동 될 수 있습니다. –

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 }; 정적 정수 부호없는 long long val = (홀수 N : 1) * Power :: val; }'- 33 % 적은 템플리트, 절반은 많은 코드,'Odd' 버그는 제거되었습니다. – Yakk

2

당신은 많은 수를 계산하기 위해 여러 정밀 수학을 사용할 수 있습니다 (전 3 템플릿 매개 변수를 사용하여 96 비트 연산을 사용하여 아래의 내 예를 들어, 당신은 어떤 상수를 사용할 수 있습니다). 템플릿 매개 변수로 둘 이상의 정수가 있어야합니다.

컴파일 타임 곱셈을 수행 할 때 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); 
} 
관련 문제