2012-01-17 5 views
1

그래서 나는 2^n을 계산하는보다 효율적인 방법을 구현하려고합니다.반복의 효율성 대 지수의 반복

나는 이것을 O(logn)이되도록 분할 할 수 있으며 재귀를 사용하여 쉽게 할 수 있음을 알고 있습니다. 당신은 2로 나누기를 계속하고 그것의 이상 (또는 그런 것)이있을 때 그것을 더 낮은 힘으로 곱하십시오. 문제는 큰 숫자에 대한 곱셈 방법을 손으로 썼다는 것입니다. 따라서 하나 이상의 매개 변수를 반환해야합니다.

제가 생각할 수있는 한 가지 해결책은 모든 필요한 정보가 포함 된 쌍을 만드는 것입니다. 그 외에도 반복을 사용하여 작성하는 방법을 알아 내려고 노력했습니다. 내가 볼 수있는 유일한 방법은 일종의 데이터 구조를 사용하고 n을 2로 나누고 n이 홀수 일 때 값을 저장하는 것입니다. 그런 다음 for 루프를 작성하고 값이 데이터 구조에 포함되어 있으면 각 반복마다 점검하십시오. 이것은 비교적 비용이 많이 드는 작업처럼 느껴집니다.

재귀 버전보다 효율성이 떨어질 가능성이 있습니까?

  1. 내가 얻을 수없는 한나라당 작업 :

    나는이 때문에하고 있어요.

  2. 큰 숫자 클래스를 작성하고 함께 작업하는 것을 배우고 있다고 생각합니다.
+0

비트 이동을 시도해 보셨습니까? 또는 매우 큰 숫자의 경우 10 진수로 표시해야합니까? – Mysticial

+0

저는 자연수 만 사용하고 있습니다 만, 2^100000만큼 큰 숫자는 정확해야합니다. 현재 내 프로그램은 반복 횟수가 간단하므로 지수가 2의 거듭 제곱이면 13 초가 걸리지 만 그렇지 않으면 효율적인 알고리즘을 한 지점까지 누른 다음 2를 곱하기 시작하여 소요 시간을 늘립니다. – emschorsch

+0

관련 : http://stackoverflow.com/questions/8771713/efficient-exponentiation-for-huge-numbers-im-talking-googols 답변을 바이너리가 아닌 십진수로 표시하려는 경우. 그렇다면 이진에서 십진수로 효율적으로 변환하는 방법에 대한 질문이 더 많습니다. – Mysticial

답변

6

큰 숫자로 작업하려면 바퀴를 다시 열지 말고 GNU MP Bignum Library을 살펴보십시오.

재귀 대 반복 질문과 관련하여 답은 언제나 동일하게 작성 될 수 있다는 것입니다. tail call으로 만 호출하는 재귀 함수는 while 루프만큼 효율적입니다 (, 컴파일러에서 꼬리 호출 최적화를 지원하지만 가장 일반적인 컴파일러는을 제공). 예를 들어, 당신이 묘사하는 빠른 지수 함수의 꼬리 재귀 버전 (의사 코드)입니다 :

function fastExp(base, exponent, accumulator) { 
    if(exponent == 0) { 
    return accumulator; 
    } else if(exponent % 2 == 0) { 
    return fastExp(base * base, exponent/2, accumulator); 
    } else { 
    return fastExp(base, exponent-1, base * accumulator); 
    } 
} 

루핑 조건이 exponent != 0이다 루프 등이 재귀 함수를 생각하고, 재귀 호출은 루프 시작 부분에 goto과 같습니다. (당신은 당신이 시작할 때 그런데, accumulator = 1로를 호출해야합니다.) 그것은 다음과 동일하다 :

function fastExp(base, exponent) { 
    var accumulator = 1; 
    while(exponent != 0) { 
    if(exponent % 2 == 0) { 
     base *= base; 
     exponent /= 2; 
    } else { 
     exponent -= 1; 
     accumulator *= base; 
    } 
    } 
    return accumulator; 
} 

그래서 당신은 그들이 동일하다는 것을 볼 수있다, 따라서 작업의 같은 번호를 수행합니다.

+0

tail 호출을 사용하는 재귀 함수가 while 루프만큼 효율적이라는 문장은 컴파일러에서 최적화하는 경우에만 true입니다. gcc가하는 동안, 나는 tail-recursive 코드를 작성하는 것이 C++에서 공통적이지 않다는 점을 감안할 때 일반적으로 얼마나 일반적인지는 모르겠다. – celtschk

+0

그게 유효한 지적입니다. gcc는 그것을 수행하고, Visual Studio는 그것을 수행하고, LLVM은 그것을 수행합니다. 나는 다른 것들에 대해서는 확실히 알지 못한다. 그러나 심각한 컴파일러가 최적화를 구현한다고 추측한다. – Philippe

+0

그저 여기에 와서이 질문을하기 전에 지수와 함께 좀 더 많은 규칙을 찾아야했습니다. 내가 배열을 사용하고 있기 때문에 나는 하나의 최적화를 생각했다. 만약 누산기가 1이면 if 테스트를 포함 할 것이고 특히 지수가 2^n의 매우 큰 힘이라면 시간을 절약 할 수있을 것이다. 비록 내가 저장 한 최대 시간은 응답의 숫자의 2 배입니다 (코드에서 2 루프). – emschorsch

0

하면 1의 시퀀스와 0 s..ie 전부를 저장하는 경우. 바이너리 형식에서 2^N 단순히 단일 한 앞에는 0 S의 서열이다 이것이 내가 필립

0,123,516을 제안 것 같은 표준 임의 정밀도 라이브러리와 함께 갈 것입니다 학습 운동은하지 않는는, 어쩌면 당신은, 등

2^1 = 10 
2^2 = 100 
2^3 = 1000 
2^4 = 10000 

등 단순히 코드에 사실을 사용할 수 있습니다

+0

내 구현은 현재 각 인덱스가 한 자리를 나타내는 int 배열입니다. 나는 아마 같은 문제의 대부분을 가지고 있지만 아마 벡터로 변환 할 것입니다. – emschorsch

+0

@ emschorsch 숫자를 기본 2 배열에 저장하면 매우 간단합니다. –

+0

하지만 최종 답을 위해 10 진수로 다시 변환해야합니다. – emschorsch