본격적으로 쉬프트 연산을 만들어 보겠습니다.
숫자들은 blk라는 unsigned long형 배열에 저장되있습니다.
하.. 배열의 시작번지를 인수로 주면 배열 전체를 n비트 쉬프트 시켜주는 함수가
있었으면 아주 편했을텐데 말인데.. 그런건 없더라구요..
결국, blk의 블럭 하나하나를 쉬프트 해야만 했습니다.
(..
memmove함수를 생각해봤지만 이동단위가 byte여서
bit를 쉬프트 해야 하는 이번 경우에는 적용시킬 수 없었습니다.)
우선 몇 블럭, 몇 비트를 쉬프트 해야 하는지 구합니다.
만약 blk를 40비트 왼쪽으로 쉬프트 한다면
(blocktype은 32비트이므로, 한 블록은 32비트입니다.)
32 + 8이므로
1블럭 + 8비트 쉬프트입니다.
이제, Get_LShiftedBlock함수를 호출하여
젤 낮은 자리부터 8비트 쉬프트 한것을 1블럭 옆에 대입합니다.
일반화 시킨다면
x크기의 blk를
(blk[0],blk[1], blk[2]...blk[x-2]...blk[x-1])
n비트 쉬프트시
blk[i]블럭을
n%32만큼 쉬프트 시켜서
blk[n/32 + i]블럭에 대입합니다.
이것을 i가 0부터 x-1까지, x번 반복하는 것이지요.
이해가 되셨나요?
그럼 이제 코드를 보겠습니다.
위에서 설명하여서 비교적 이해가 되시리라 생각됩니다.
그런데
temp를 재할당 하는 함수에서 +1을 하였습니다.
왜 그랬을까요?
shiftbits가 0이면 그냥 shiftblocks만큼 배열의 원소들을 옮겨주면 됩니다.
하지만 shiftbits가 0이 아니라면 배열의 최고차항도 shiftbits만큼 쉬프트 해주어 합니다.
그런데 만약 배열의 최고차항 배열의 원소가
다음을 만족한다면..
( blk[len - 1] >> ( 32 - shiftbits) ) != 0
배열의 길이가 len + shiftblocks보다 1칸 더 많아져야 합니다.
( blk[len - 1] >> ( 32 - shiftbits) ) 이것을 저장한 1블럭이 필요하기 때문입니다.
무슨 소린야?? 라고 하실지도 모르겠습니다.
근데.. 곰곰히 생각해보시면.. 아 그렇구나 하실겁니다.
블럭을 쉬프트 대입 후,
temp.blk[temp.len - 1] 가 0인지 비교합니다.
이건 다음과 뜻이 같습니다.
== this->Get_LShiftedBlock(len - 1, shiftbits)가 0인가?
== ( *this.blk[len - 1] >> ( 32 - shiftbits) )가 0인가?
0이라면 temp.len을 한칸 줄입니다.
그 후, 부호를 대입하면 끝입니다..!!
글이 많이 길어졌네요..
다음글에서 >>연산에 대해 쓰겠습니다.
숫자들은 blk라는 unsigned long형 배열에 저장되있습니다.
하.. 배열의 시작번지를 인수로 주면 배열 전체를 n비트 쉬프트 시켜주는 함수가
blocktype *blk; blk = blk << n;
있었으면 아주 편했을텐데 말인데.. 그런건 없더라구요..
결국, blk의 블럭 하나하나를 쉬프트 해야만 했습니다.
(..
memmove함수를 생각해봤지만 이동단위가 byte여서
bit를 쉬프트 해야 하는 이번 경우에는 적용시킬 수 없었습니다.)
우선 몇 블럭, 몇 비트를 쉬프트 해야 하는지 구합니다.
만약 blk를 40비트 왼쪽으로 쉬프트 한다면
(blocktype은 32비트이므로, 한 블록은 32비트입니다.)
32 + 8이므로
1블럭 + 8비트 쉬프트입니다.
이제, Get_LShiftedBlock함수를 호출하여
젤 낮은 자리부터 8비트 쉬프트 한것을 1블럭 옆에 대입합니다.
일반화 시킨다면
x크기의 blk를
(blk[0],blk[1], blk[2]...blk[x-2]...blk[x-1])
n비트 쉬프트시
blk[i]블럭을
n%32만큼 쉬프트 시켜서
blk[n/32 + i]블럭에 대입합니다.
이것을 i가 0부터 x-1까지, x번 반복하는 것이지요.
이해가 되셨나요?
그럼 이제 코드를 보겠습니다.
const BigInteger BigInteger::operator <<(const int leftmove) const { // (*this) * 2^(leftmove)를 연산 BigInteger temp; // 결과값 리턴용 /* * 특수 경우를 제외합니다. * 1. *this가 0이면, 0 리턴 * 2. leftmove가 0이면, *this 리턴 * 3. leftmove가 음수면, >> 쉬프트로 연산 */ if (sign == Zero) return temp; if (leftmove == 0) return *this; else if (leftmove < 0) return *this >> (-leftmove); length shiftblocks = leftmove / N; length shiftbits = leftmove % N; // +1은 shitfbits때문에 생기는 추가되는 블록 저장용 temp.Reallocate(len + shiftblocks + 1); // 한블럭씩 shiftbits만큼 쉬프트 시켜 대입해줍니다. index i, j; for (i = 0, j = shiftblocks; i <= len; i++, j++) temp.blk[j] = Get_LShiftedBlock(i, shiftbits); // Get_LShiftedBlock(len - 1, shiftbits)가 0일 경우... if (temp.blk[temp.len - 1] == 0) temp.len--; temp.sign = sign; return temp; }
위에서 설명하여서 비교적 이해가 되시리라 생각됩니다.
그런데
temp를 재할당 하는 함수에서 +1을 하였습니다.
왜 그랬을까요?
shiftbits가 0이면 그냥 shiftblocks만큼 배열의 원소들을 옮겨주면 됩니다.
하지만 shiftbits가 0이 아니라면 배열의 최고차항도 shiftbits만큼 쉬프트 해주어 합니다.
그런데 만약 배열의 최고차항 배열의 원소가
다음을 만족한다면..
( blk[len - 1] >> ( 32 - shiftbits) ) != 0
배열의 길이가 len + shiftblocks보다 1칸 더 많아져야 합니다.
( blk[len - 1] >> ( 32 - shiftbits) ) 이것을 저장한 1블럭이 필요하기 때문입니다.
무슨 소린야?? 라고 하실지도 모르겠습니다.
근데.. 곰곰히 생각해보시면.. 아 그렇구나 하실겁니다.
블럭을 쉬프트 대입 후,
temp.blk[temp.len - 1] 가 0인지 비교합니다.
이건 다음과 뜻이 같습니다.
== this->Get_LShiftedBlock(len - 1, shiftbits)가 0인가?
== ( *this.blk[len - 1] >> ( 32 - shiftbits) )가 0인가?
0이라면 temp.len을 한칸 줄입니다.
그 후, 부호를 대입하면 끝입니다..!!
글이 많이 길어졌네요..
다음글에서 >>연산에 대해 쓰겠습니다.
'프로젝트 > 큰수 클래스(Big Numerics)' 카테고리의 다른 글
[BigInteger - 11] 덧셈 (0) | 2011.07.07 |
---|---|
[BigInteger - 10] 쉬프트 연산(Part3) (0) | 2011.07.06 |
[BigInteger - 8] 쉬프트 연산(Part1) (0) | 2011.07.01 |
[BigInteger - 7] 비트연산 (0) | 2011.07.01 |
[BigInteger - 6] 비교연산 (1) | 2011.06.30 |