큰 수를 저장하는 방법은 다양할 것입니다.
우선, char형 배열을 만들어서 각자리를 십진수로 저장하는 방법이 있습니다.
문제를 대략 설명드리면,
0.0 < R < 99.999 사이에, 소수점을 포함하여 6글자의 문자열을 입력받고
0 < n <= 25 사이의 숫자 n을 입력 받은 후,
R ^ n (R의 n승)을 구하는 문제였습니다.
R을 n번 곱하는 식으로 풀었는데,
char result[500];을 정의한 후, 문자열로 입력을 받아
두 십진수의 곱셈을 하는 식으로 하였습니다.
하지만 이런 방식에는 두가지의 문제점이 있습니다.
첫 번째, char형 배열로 숫자를 저장할 때는 공간이 낭비됩니다.
char a[3] = "10";
십진수 10을 저장하기 위해 '\n' 포함 3의 크기를 가지는 배열을 정의했습니다.
하지만 char형은 1바이트의 크기를 가집니다. 8비트이죠.
8비트로는 0부터 255(2^8-1)까지의 숫자를 저장할 수 있습니다.
하지만 이 거대한 공간에 단지 0부터 9까지의 숫자밖에 저장하지 않습니다.
0 ~ 9까지의 숫자를 입력 받는데는 4비트면 충분합니다.
숫자 한자리를 저장할 때마다 4비트씩이나!! 낭비되는 현상이 발생합니다.
작은 수라면 몰라도 만들려고 하는 BigInteger 클래스는 상당히 큰 수를 다루어야 하기 때문에
이런 방식은 고려 할 수 없습니다.
두 번째, 연산 과정이 느려집니다.
한자리한자리씩 연산하고 자릿수 올림,내림을 반복해야 하기 때문에 당연히 느릴 수 밖에 없습니다.
n자리의 두 정수의 곱셈을 한다고 가정해보겠습니다.
이 연산에서는 n^2번의 곱셈과 n번의 나눗셈 n번의 나머지 연산이 필요합니다.
n이 100억이라고 생각하면 어휴.. ㅋㅋ
위의 두가지 이유 때문에
여기서는 큰수를 저장하기 위해 다른 방식을 사용합니다.
unsigned long형 배열에 2진수로 숫자를 저장하는 겁니다.
그러면 1비트의 공간도 낭비하지 않고 알차게(?) 숫자를 저장할 수 있습니다.
쉽게 생각해서 2^32진법을 사용한다고 보시면 됩니다.
unsigned long blk[4];
다음과 같이 표현할 경우 나타내지는 수는
1 + ( 2 * 2^32 ) + ( 3 * ( 2^32 )^2 ) + ( 4 * ( 2^32 )^3 )
와 같이 어마어마한 숫자가 담아집니다.
또한, 배열 저장 방식에 리틀 에디안(Little Endian) 방식을 사용합니다.
즉, 배열의 앞 부분이 낮은 자릿수를 나타내는 것이지요.
우선, char형 배열을 만들어서 각자리를 십진수로 저장하는 방법이 있습니다.
char *result = "12345";예전에 PKU 1001번 문제를 풀 때, 위와 같은 방식을 사용하였습니다.
문제를 대략 설명드리면,
0.0 < R < 99.999 사이에, 소수점을 포함하여 6글자의 문자열을 입력받고
0 < n <= 25 사이의 숫자 n을 입력 받은 후,
R ^ n (R의 n승)을 구하는 문제였습니다.
R을 n번 곱하는 식으로 풀었는데,
char result[500];을 정의한 후, 문자열로 입력을 받아
두 십진수의 곱셈을 하는 식으로 하였습니다.
하지만 이런 방식에는 두가지의 문제점이 있습니다.
첫 번째, char형 배열로 숫자를 저장할 때는 공간이 낭비됩니다.
char a[3] = "10";
십진수 10을 저장하기 위해 '\n' 포함 3의 크기를 가지는 배열을 정의했습니다.
하지만 char형은 1바이트의 크기를 가집니다. 8비트이죠.
8비트로는 0부터 255(2^8-1)까지의 숫자를 저장할 수 있습니다.
하지만 이 거대한 공간에 단지 0부터 9까지의 숫자밖에 저장하지 않습니다.
0 ~ 9까지의 숫자를 입력 받는데는 4비트면 충분합니다.
숫자 한자리를 저장할 때마다 4비트씩이나!! 낭비되는 현상이 발생합니다.
작은 수라면 몰라도 만들려고 하는 BigInteger 클래스는 상당히 큰 수를 다루어야 하기 때문에
이런 방식은 고려 할 수 없습니다.
두 번째, 연산 과정이 느려집니다.
한자리한자리씩 연산하고 자릿수 올림,내림을 반복해야 하기 때문에 당연히 느릴 수 밖에 없습니다.
n자리의 두 정수의 곱셈을 한다고 가정해보겠습니다.
이 연산에서는 n^2번의 곱셈과 n번의 나눗셈 n번의 나머지 연산이 필요합니다.
n이 100억이라고 생각하면 어휴.. ㅋㅋ
위의 두가지 이유 때문에
여기서는 큰수를 저장하기 위해 다른 방식을 사용합니다.
unsigned long형 배열에 2진수로 숫자를 저장하는 겁니다.
그러면 1비트의 공간도 낭비하지 않고 알차게(?) 숫자를 저장할 수 있습니다.
쉽게 생각해서 2^32진법을 사용한다고 보시면 됩니다.
unsigned long blk[4];
blk[0] | blk[1] | blk[2] | blk[3] |
1 | 2 | 3 | 4 |
다음과 같이 표현할 경우 나타내지는 수는
1 + ( 2 * 2^32 ) + ( 3 * ( 2^32 )^2 ) + ( 4 * ( 2^32 )^3 )
와 같이 어마어마한 숫자가 담아집니다.
또한, 배열 저장 방식에 리틀 에디안(Little Endian) 방식을 사용합니다.
즉, 배열의 앞 부분이 낮은 자릿수를 나타내는 것이지요.
'프로젝트 > 큰수 클래스(Big Numerics)' 카테고리의 다른 글
[BigInteger - 5] 기본형으로부터의 생성 / 변환 (1) | 2011.06.29 |
---|---|
[BigInteger - 4] 초기화 (0) | 2011.06.28 |
[BigInteger - 3] 생성자 개요 (0) | 2011.06.28 |
[BigInteger - 2] 클래스 만들기 (1) | 2011.06.27 |
[BigInteger - 0] C++로 구현한, 큰 정수 클래스 만들기!!! (0) | 2011.06.27 |