Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

부스 곱셈 알고리즘(Booth's Multiplication Algorithm) C++ 구현 완벽 가이드

부스 곱셈 알고리즘(Booth's Multiplication Algorithm)은 2의 보수(2's complement) 표기법으로 표현된 두 개의 부호 있는 이진수를 곱하기 위한 효율적인 알고리즘입니다. 앤드류 도널드 부스(Andrew Donald Booth)는 덧셈보다 시프트 연산이 더 빨랐던 탁상용 계산기의 특성을 활용하여 연산 속도를 향상시키고자 이 알고리즘을 고안했습니다.

알고리즘 핵심 원리

부스 알고리즘은 곱셈기(Multiplier)의 비트 쌍(Qn, Qn+1)을 검사하여 연산을 결정합니다. 피승수(Multiplicand)는 BR 레지스터에, 곱셈기는 QR 레지스터에 저장하며, 누산기(AC)는 0으로 초기화합니다.

알고리즘 단계:
1. 피승수(Multiplicand)를 BR에, 곱셈기(Multiplier)를 QR에 저장한다.
2. Qn(현재 비트)과 Qn+1(이전 비트)을 비교하여 다음을 수행한다:
   - 00 또는 11 (동일): 산술 오른쪽 시프트(Arithmetic Right Shift) 1비트 수행.
   - 10 (1 → 0 변화): AC = AC - BR (피승수 뺄셈) 후 산술 오른쪽 시프트 수행.
   - 01 (0 → 1 변화): AC = AC + BR (피승수 덧셈) 후 산술 오른쪽 시프트 수행.
3. 모든 비트 처리 시까지 반복한다.

C++ 구현 예제

다음은 부스 알고리즘을 구현한 완전한 C++ 코드입니다. 사용자로부터 비트 수와 2의 보수 형태의 이진수를 입력받아 단계별 연산 과정과 최종 결과를 출력합니다.

#include <iostream>
using namespace std;

// 함수 선언
void add(int ac[], int x[], int q);
void complement(int a[], int n);
void ashr(int ac[], int qr[], int &qn, int q);
void display(int ac[], int qr[], int qrn);

// 2의 보수 구하기 (1의 보수 + 1)
void complement(int a[], int n) {
    int x[10] = {0};
    x[0] = 1; // +1을 위한 배열
    for (int i = 0; i < n; i++) {
        a[i] = (a[i] + 1) % 2; // 1의 보수 (비트 반전)
    }
    add(a, x, n); // 1 더하기
}

// 이진수 덧셈 (AC = AC + X)
void add(int ac[], int x[], int q) {
    int c = 0; // 캐리
    for (int i = 0; i < q; i++) {
        ac[i] = ac[i] + x[i] + c;
        if (ac[i] > 1) {
            ac[i] %= 2;
            c = 1;
        } else {
            c = 0;
        }
    }
}

// 산술 오른쪽 시프트 (ASHR)
void ashr(int ac[], int qr[], int &qn, int q) {
    int temp = ac[0]; // AC의 LSB 저장
    qn = qr[0];       // QR의 LSB를 Qn+1로 저장
    
    cout << "\t\tashr\t\t";
    
    // AC 시프트
    for (int i = 0; i < q - 1; i++) {
        ac[i] = ac[i + 1];
    }
    // QR 시프트
    for (int i = 0; i < q - 1; i++) {
        qr[i] = qr[i + 1];
    }
    qr[q - 1] = temp; // AC의 LSB가 QR의 MSB로 이동
}

// 레지스터 상태 출력 (MSB부터 출력)
void display(int ac[], int qr[], int qrn) {
    for (int i = qrn - 1; i >= 0; i--) cout << ac[i];
    cout << " ";
    for (int i = qrn - 1; i >= 0; i--) cout << qr[i];
}

int main() {
    int mt[10], br[10], qr[10], sc;
    int ac[10] = {0}; // 누산기 초기화
    int brn, qrn, i, qn = 0, temp = 0;

    cout << "-- 부호 있는 2의 보수 형태로 입력하세요 (음수인 경우) --\n";
    cout << "피승수 비트 수: ";
    cin >> brn;
    cout << "피승수 (LSB부터 입력): ";
    for (i = brn - 1; i >= 0; i--) cin >> br[i];
    
    // 피승수의 음수 값(MT) 미리 계산 (뺄셈용)
    for (i = brn - 1; i >= 0; i--) mt[i] = br[i];
    complement(mt, brn);

    cout << "곱셈기 비트 수: ";
    cin >> qrn;
    sc = qrn; // 시프트 카운터
    cout << "곱셈기 (LSB부터 입력): ";
    for (i = qrn - 1; i >= 0; i--) cin >> qr[i];

    cout << "\nqn\tq[n+1]\t\tBR\t\tAC\tQR\t\tsc\n";
    cout << "\t\t\tinitial\t\t";
    display(ac, qr, qrn);
    cout << "\t\t" << sc << "\n";

    // 메인 루프
    while (sc != 0) {
        cout << qr[0] << "\t" << qn;
        
        // Qn과 Qn+1 비교 (qr[0]이 Qn, qn이 Qn+1)
        if ((qn + qr[0]) == 1) { // 01 또는 10인 경우
            if (temp == 0) { // 01: 덧셈 (AC + BR) -> 코드상 MT(음수) 더하기 = 뺄셈
                add(ac, mt, qrn);
                cout << "\t\tsubtracting BR\t";
                temp = 1;
            } else { // 10: 뺄셈 (AC - BR) -> 코드상 BR(양수) 더하기 = 덧셈
                add(ac, br, qrn);
                cout << "\t\tadding BR\t";
                temp = 0;
            }
            for (i = qrn - 1; i >= 0; i--) cout << ac[i];
            cout << "\n\t";
            ashr(ac, qr, qn, qrn);
        } 
        else if (qn - qr[0] == 0) { // 00 또는 11인 경우
            ashr(ac, qr, qn, qrn);
        }
        
        display(ac, qr, qrn);
        cout << "\t";
        sc--;
        cout << "\t" << sc << "\n";
    }

    cout << "Result= ";
    display(ac, qr, qrn);
    cout << endl;
    
    return 0;
}

실행 결과 예시

피승수 5비트(01111, +15), 곱셈기 5비트(10111, -9) 입력 시 결과입니다. 최종 결과 11011 11001은 2의 보수 형태의 -135를 나타냅니다.

-- 부호 있는 2의 보수 형태로 입력하세요 (음수인 경우) --
피승수 비트 수: 5
피승수 (LSB부터 입력): 0 1 1 1 1
곱셈기 비트 수: 5
곱셈기 (LSB부터 입력): 1 0 1 1 1

qn	q[n+1]		BR		AC	QR		sc
			initial		00000 10111		5
1	0	subtracting BR	10001
	ashr		11000 11011	4
1	1	ashr		11100 01101	3
1	1	ashr		11110 00110	2
0	1	adding BR	01101
	ashr		00110 10011	1
1	0	subtracting BR	10111
	ashr		11011 11001	0
Result= 11011 11001

코드 주요 포인트 정리

  • 입력 순서: 코드 편의상 LSB(최하위 비트)부터 입력받아 배열 인덱스 0에 저장합니다.
  • MT 배열: 피승수(BR)의 2의 보수(음수 값)를 미리 계산해 두어, 뺄셈이 필요할 때 덧셈 연산으로 대체합니다.
  • Temp 변수: 부스 알고리즘의 부호 비트 전환(0→1, 1→0)을 추적하여 덧셈/뺄셈을 번갈아 수행하도록 제어합니다.
  • ASHR: 부호 비트(MSB)를 유지하며 오른쪽으로 시프트하는 산술 시프트를 구현했습니다.