본문 바로가기

programmer/C

두 자리 이상인 수의 연산이 가능한 계산기 구현 - 2 (postfix 계산)

복잡한 연산이 가능한 계산기



6.



저번 글에 이어서, 이번에는 postfix로 변환된 수식을 계산하는 코드를 알아보겠습니다. 저번 글에서 한 내용으로 다음까지의 연산이 가능해졌습니다.



infix : 5*(15+(2*5-3)*(54/2))*123-30*50/1500
postfix : 5 15 2 5 * 3 – 54 2 / * + * 123 * 30 50 * 1500 / -



설명을 드렸던 것처럼 postfix 배열에 공백을 넣음으로써 두 자리 이상의 수들도 혼란없이 연산이 가능하게 되었는데요. 그 공백을 이용해서 이제 계산을 해보도록 하겠습니다.


.



7.



int eval(char *postfix)
{
    words temp; 
    int value, op1, op2;
    int i;
    StackType s;
    init(&s);
    for(i=0; postfix[i] != '\0'; i++){
        if(postfix[i] == ' ')
            i++;
        temp = classification(&postfix[i]);
        if(temp==operand){
            value = change_value(&postfix[i], &i);
            push(&s, value);
        }
        else{
            op2 = pop(&s);
            op1 = pop(&s);
            switch(temp){
                case plus : push(&s, op1+op2); break;
                case minus : push(&s, op1-op2); break;
                case multiply : push(&s, op1*op2); break;
                case divide : push(&s, op1/op2); break;
            }
        }
    }
    return pop(&s);
}


postfix로 표기된 식을 계산하는 eval함수입니다. 먼저 words라는 열거형 자료형 코드를 봅시다.



typedef enum{
    leftparen, rightparen, plus, minus, multiply, divide, eos, operand
}words;


eval 함수에서 열거형 자료형을 가지는 변수 temp를 선언하고, int형 자료형을 가지는 value, op1, op2, i 를 선언했습니다. Stack도 선언하고 초기화했습니다. 코드를 보면 다 알 수 있는 내용이죠.






그리고 반복문이 시작됩니다. postfix 배열이 null을 만날 때까지 반복합니다. 그 안에 조건으로 공백을 만날 경우 바로 다음칸으로 이동하는 조건을 볼 수 있습니다.

classification함수는 연산자인지 피연산자인지를 구분하는 함수입니다.



words classification(char *point){
    switch(*point){
        case '(': return leftparen;
        case ')': return rightparen;
        case '+': return plus;
        case '-': return minus;
        case '*': return multiply;
        case '/': return divide;
        case '\': return eos;
        default : return operand;
    }
}


그리고 다시 조건문이 시작됩니다. temp값이 피연산자라면 문자형으로 표현된 숫자이므로 int형으로 바꾸어야 계산할 수 있습니다. change_value함수는 다음과 같습니다.



int change_value(char *num, int *index){
    int value;
    char temp[100];
    int i, k;
    for(i=0; num[i]!=' '; i++)
        temp[i] = num[i];
    temp[i]='\0';
    value = atoi(temp);
    k = *index;
    *index = k+i;
    return value;
}


change_value 함수는 단순히 문자형을 숫자로 바꾸어주는 것 뿐만 아니라 피연산자의 자리수만큼 인덱스의 위치도 바꿔주고 있습니다. 햇갈리지 않게 주의해서 봐야합니다. atoi함수는 문자형을 int형으로 바꾸어주는 함수입니다.






다시 eval함수로 돌아와서 다음 조건입니다. 피연산자가 아닌 연산자를 만난 경우 stack에 들어가있던 값을 꺼내어 계산을 해야겠죠? 먼저 꺼낸 값을 op2, 나중에 꺼낸 값을 op1에 대입합니다. 순서는 빼기나 나누기때문에 중요합니다.

switch문은 각 연산자에 알맞은 계산을 하고 다시 stack에 넣어주는 코드까지 포함하고 있습니다.



8.



이러한 조건을 바탕으로 postfix 배열에서 null을 만날 때까지 반복이 되고 반복이 완료되면 stack에는 최종적으로 계산된 값만 남게 됩니다.

결과적으로 우리는 infix_to_postfix함수와 eval함수를 이용하여 복잡한 수식을 계산할 수 있게 됩니다. 최종 결과는 다음과 같습니다.



수식 입력 : 5*(15+(2*5-3)*(54/2))*123-30*50/1500
postfix : 5 15 2 5 * 3 – 54 2 / * + * 123 * 30 50 * 1500 / -
결과 : 125459