자료형 관련 질문입니다.
글쓴이: fopenfclose / 작성시간: 금, 2016/06/24 - 8:03오후
Background
재민이는 프로그램 코딩을 할 때, math.h를 활용하여 다양한 수학 함수를 활용하고 있다. 이런 점이 못마땅한 seaguy 샘이 재민이에게 더 이상 math.h 함수를 사용하지 않고 연산을 하도록 다음과 같은 문제를 제시하였다.
n^m을 계산하는 문제이다. 일반적으로 pow()함수를 이용하면 간단하게 계산할 수 있지만 사용할 수가 없으니 이제는 다른 방법으로 문제를 해결해야 한다.
재민이를 도와 n^m을 계산하는 프로그램을 작성해보자.
Input
첫 번째 줄에 정수 n, m이 입력으로 주어진다. (단, 0 <= n, m <= 100,000)
Output
n^m의 결과를 출력한다. 단, 수가 너무 크므로 1,000,000,007로 나눈 값을 출력한다.
IO Example
입력
3 2
출력
9
의 문제를 풀고 있는데
저는 아래와 같이 소스를 작성했습니다.
#include <iostream> using namespace std; long long pownew(int n, int m); int main(int argc, char * argv[]) { int n, m; cin >> n >> m; cout << pownew(n, m) % 1000000007; return 0; } long long pownew(int n, int m) { if (m == 1) return n; long long v = pownew(n, m / 2); if (!(m % 2)) return v * v; else return v * v * n; }
사이트에서 결과를 돌려보니 3개의 테스트 케이스까진 통과인데
4번째 테스트 케이스에선 411081351 이게 답이라고 뜨면서 틀렸다고 나옵니다.
3번째 까진 맞다가 4번째에선 틀린것이 좀 이상한데 코드에서 로직이 잘못된 건지
아니면 자료형이 잘못되서 결과가 잘못나오는건지 모르겠습니다.
정수형에서 가장 큰 범위를 갖고 있는 자료형이 long long 으로 알고 있는데,, 어떻 자료형을 써야 하나요?? 큰 범위를 커버하려면요
Forums:
이런 종류의 프로그래밍을 할 때는
기초적인 정수론, 특히 모듈러 산술을 공부해 두는 편이 좋습니다.
pownew
함수는long long
만을 가지고 끝까지 계산한 뒤 마지막에 한 번 1000000007으로 나머지 연산하려고 하셨던 거 같은데요.계산 과정에서 숫자가 100,000^100,000까지 올라가버릴 수 있기 때문에
long long
가 어지간히 커도 계산 중간에 정수 오버플로우가 발생하고 값이 손실됩니다.해결 방법은 간단합니다.
long long
이 1000000006 * 1000000006 = 1000000012000000036 정도는 커버할 수 있기 때문에,(이 숫자는 60비트 수로군요.)매번 곱셈을 할 때마다 1000000007으로 나누어주어 1000000006 이하의 수로 만들어버리면 정수 오버플로우가 절대 일어나지 않습니다.
그런 식으로 계산해도 최종 결과값은 동일하다는 게 모듈러 산술이 보장하는 것이고요.
그런데 매번 곱셈마다 1000000007으로 나누어주는 건 코드가 지저분해지고, 자칫 깜빡해서 빠트리기 쉽지요. 게다가 그런 실수는 나중에 찾기가 무척 어려울 수도 있어서, 저는 보통 코드가 조금 길어지더라도 안전한 방법을 선택해요. 뭐 예컨대 아래와 같습니다.
질문자님의 코드를 그대로 옮기기만 하는 건 재미가 없어서, 제 방식대로도 한 번 풀어 봤습니다.(
pownew2
)한 번 참고해보세요. 1) 재귀 호출을 피하고, 2) * 연산자 대신 *= 연산자를 사용하는 등 조금 더 개선되었다고 볼 여지가 있습니다.
덧. 소스코드에서 <은 <으로, >은 >으로 바꿔주세요. kldp <code> 태그의 고질적인 문제인데 언제쯤 고쳐질지 원...
마이크로 최적화의 여지는 광활하고...
마이크로 최적화의 여지는 광활하고...
그런 데 쓸데없이 자기 시간 쏟아붇는 사람도 많은 법이죠.
이러면 아주 약간 나아질지도 모릅니다. 물론 나아진다고 해봤자 루프 하나당 몇 클럭 사이클 정도일 것이고, 하루종일 돌려 봤자 제가 이 코드 짜는 데 걸린 시간만큼이라도 아낄 수 있을까 말까 뭐 그렇겠죠 ㅎ.
뭐, 그래도 재미로 하는 거 아니겠습니까.
댓글 달기