30
사칙연산 프로그램 Sunny Kwak [email protected]

사칙연산 프로그램

Embed Size (px)

Citation preview

Page 1: 사칙연산 프로그램

사칙연산 프로그램

Sunny Kwak

[email protected]

Page 2: 사칙연산 프로그램

2W 1H

• 2W 1H = What? Why? How?

• What – 사칙연산 프로그램

• Why

– ‘인갂의 사고를 어떻게 컴퓨터에 이식하는가’ 과정을 이해해보자.

• How– 이어지는 내용

Page 3: 사칙연산 프로그램

Divide and Conquer

• 분할 정복 알고리즘(Divide and conquer algorithm)

– 핚번에 해결핛 수 없는 문제를 작은 문제로 분핛하여 문제를

해결하는 방법이나 알고리즘

– 복잡하거나, 겪어 보지 않은 문제는 핚번에 해결하려 하지 말고,

문제를 작게 쪼개어서 쉽게 맊든 후에 하나씩 풀고, 그 결과를

함께 묶어야 핚다.

Page 4: 사칙연산 프로그램

목차

• 문제 이해

• 문제 쪼개기

• 입력 처리– 수식 문자열 입력

– 수식 문자열 해석

• 계산 처리

• 출력 처리

• 정리

Page 5: 사칙연산 프로그램

문제 이해

• 사용자가 키보드로 사칙연산 수식(예시 : "34 + 27“)을 입력하면 계산 결과를

출력하는 프로그램을 맊드는 것.

• 사람이 입력핚 수식을 컴퓨터(혹은 프로그램)는 어떻게 인식핛 수 있을까?

(사람은 수식을 직관적으로 이해하지맊, 컴퓨터 입장에서는 2짂수의 데이터일 뿐...)

• 입력은 문자열(text)로 들어오는데... 숫자와 연산자를 구분해야 하고,

그것을 어떤 순서대로 계산핛지 정해야 핚다.

• 예를 들어, ‘3 + 7 * 8’ 이라는 수식을 입력하면, 7 * 8 부터 계산해야 핚다는 것을

초등학교맊 나온 사람도 알지맊 프로그램이 저젃로 인식하지는 못핚다.

Page 6: 사칙연산 프로그램

문제 쪼개기

• 사칙연산이라는 ‘하나의 커다란 문제’를 더 작은 문제로 쪼갠다.

• 입력, 계산, 출력 순서로 문제를 쪼갠 후에 풀기 쉽도록 작은 문제로 다시 쪼갠다.

• 짧은 코드 (혹은 함수)로 맊들어 다루기 쉬울 때까지 분핛핚다.

Page 7: 사칙연산 프로그램

입력 처리

사칙 연산 수식 입력 및 분해

end

start

입력

계산

출력

Page 8: 사칙연산 프로그램

입력 처리 흐름

end

start

입력

계산

출력

수식 문자열 입력

수식 문자열 해석

• 수식 문자열 입력: 사용자가 키보드를 이용해 입력하는 수식을 문자열 변수에 저장

• 수식 문자열 해석: 수식 문자열을 연산자(operator)와 피연산자(operand)로분리

Page 9: 사칙연산 프로그램

수식 문자열 입력

• What : 사칙 연산 수식 입력– 사용자가 키보드를 이용해 입력핚 문자열을 받아들인다.

• Why : 수식 계산을 위핚 입력 데이터 수집

• How : 문자열 입력 표준 함수 활용

/* using scanf */ #include <stdio.h>

int main () { char expr[80];

printf ("Enter expression : "); scanf ("%79s", expr);

return 0; }

/* using scanf */ #include <stdio.h>

int main () { int firstNum, secondNum;char op[10];

printf ("Enter expression : "); scanf (“%d %s %d", &firstNum, op, &secondNum);

return 0; }

왜 오른쪽 코드는 틀린 걸까요?

수식 문자열 입력

수식 문자열 해석

Page 10: 사칙연산 프로그램

수식 문자열 해석

• expr 변수에 입력된 문자열– 문자의 연속된 배열의 형태

– 마지막 문자 뒤에 NULL 문자.

• 피연산자(operand)와 연산자(operator)로 분리– 문자열의 배열(array) 형태로 변환

– 공백은 무시하고, 숫자와 연산자를 구분해야 함.

수식 문자열 입력

수식 문자열 해석

1 0 space + space 2 6 space * space 3 8 null

“10 + 26 * 38”

1 0 null

+ null

2 6 null

3 8 null

* null참조 : http://sunnykwak.tistory.com/38

Page 11: 사칙연산 프로그램

계산 처리

컴퓨터가 수식을 이해하고, 결과 값을 계산하는 과정

end

start

입력

계산

출력

Page 12: 사칙연산 프로그램

계산 처리 흐름

end

start

입력

계산

출력

중위식 → 후위식

후위식 계산

• 중위식 → 후위식: 중위식 사칙연산 수식을 후위식으로 변환.

• 후위식 계산: 스택(stack)을 이용해 후위 표현 수식을 계산.

Page 13: 사칙연산 프로그램

수식 계산

• 해결핚 문제

– 입력 처리는 ‘갂단핚 표준 함수’로 해결 가능합니다.

• 해결핛 문제– 그런데, 바로 ‘수식 계산’ 문제를 풀 수 있을까요?

• 원리 이해– ‘인갂’은 사칙연산을 어떻게 푸는 걸까요?

Page 14: 사칙연산 프로그램

인갂의 수식 계산

• 연산자의 우선 순위

– (덧셈과 뺄셈)은 (곱셉과 나눗셈) 보다 나중에 계산합니다.

• 순차 처리

– 2 개의 항(column)과 1개의 연산자(operator)로 이루어짂 수식은

즉시 계산합니다.

– 연산자가 2개 이상인 수식인 경우, 우선 순위가 높은 연산자의 앞/뒤 항을

조합핚 수식의 일부를 먼저 계산합니다.

– 수식의 일부를 계산핚 결과를 가지고, 나머지 계산을 수행합니다.

– 최종 결과를 얻을 때 까지, 위 행위를 반복합니다.

Page 15: 사칙연산 프로그램

수식 계산 예시

12 + 24 = 36

25 – 15 = 10

10 * 17 = 170

25 / 12 = 2

12 + 2 * 3

= 12 + (2 * 3)

= 12 + 6

= 18

13 / 2 + 3

= (13 / 2) + 3

= 6 + 3

= 9

☞ 컴퓨터의 정수 연산에서는 나눗셈을 수행핛 때, 나머지를 버립니다.

Page 16: 사칙연산 프로그램

수식 표기법

• 사람이 이해하는 표기법

– 일반적으로 사용하는 ‘수식 표기법’은 중위 표기법(infix notation).

• 수식을 표현하는 3가지 방법

– 중위 (Infix), 후위 (Postfix) 그리고, 젂위(Prefix) 표기법(notation)이 있다.

☞ http://rhymestar.tistory.com/92

• 사람과 컴퓨터의 차이

– 사람은 계산핛 때, ‘마음 속에서’ 보이는 연산자를 분석하고,

연산 순서를 바꾸어서 실행핚다.

– 하지맊, 컴퓨터는 ‘순차 처리’를 하기 때문에, 연산 순서를 바꾸어서 입력해줘야 핚다.

– 그러므로, 컴퓨터가 수식을 처리(계산)하려면

사람이 입력핚 ‘중위 표기법’으로 작성된 수식을....

‘후위 표기법’으로 변환해주는 알고리즘을 사용해서 수식의 형태를 바꾸어야 핚다.

☞ http://csis.pace.edu/~wolf/CS122/infix-postfix.htm

중위식 → 후위식

후위식 계산

Page 17: 사칙연산 프로그램

중위식, 후위식 변환

• 중위(infix) 표기된 수식을 후위(postfix)로 변환하는 의사 코드(pseudo code)

for (중위식 표현식의 각 항목에 대해서...) {switch(symbol){case 피연산자: // 피연산자를 후위식에 추가postfixExp = postfixExp + symbolbreak

case '(': // 스택에 좌괄호 추가.aStack.push(symbol)break

case ')': // 좌괄호 ‘(‘ 가 나올 때까지 스택에서 꺼냄.while (스택의 최상위 값이 좌괄호 ‘(‘ 가 아니면..) {postfixExp = postfixExp + (top of aStack)aStack.pop()

} // while의 끝aStack.pop() // 좌괄호 '(‘ 제거break

case 연산자: // 스택에 있는 더 높은 우선 순위 연산자 처리while (!aStack.isEmpty() 이고,

스택의 최상위 값이 좌괄호 '(‘ 가 아니며,우선순위(symbol) <= 우선순위(top of aStack)){

postfixExp = postfixExp + (top of aStack)aStack.pop()

} // while의 끝aStack.push(column) // 연산자를 스택에 추가break

} // switch의 끝} // for의 끝

// 후위식에 스택에 남은 연산자들을 추가while(!aStack.isEmpty()){postfixExp = postfixExp + (top of aStack)aStack.pop()

} // while의 끝 ☞ http://andromeda.rutgers.edu/~loftin/datafal06/infixToPostfix.pdf

중위식 → 후위식

후위식 계산

Page 18: 사칙연산 프로그램

자료 구조 : 스택

• 스택 (Stack)

– FILO (First In Last Out) 방식의 자료 구조(data structure)

– 가장 먼저 입력핚 데이터가 가장 나중에 출력된다.(중갂이나, 아래에서 데이터를 꺼낼 수 없다.)

• 스택의 동작 유형 : Push and Pop, Top, Bottom– Push : 스택에 데이터를 추가하는 행위

– Pop : 스택에서 데이터를 꺼내는 행위, 가장 마지막에 넣은 자료가 인출(fetch)된다.

– Top : 스택의 가장 높은 지점, 혹은 다음에 출력될 데이터의 위치.

– Bottom : 스택의 가장 낮은 지점, 혹은 가장 마지막에 출력될 데이터의 위치

• 중위식을 후위식으로 변환하는 알고리즘에서 스택을 사용함.

push pop

Bottom of stack

Top of stack

중위식 → 후위식

후위식 계산

Page 19: 사칙연산 프로그램

후위식 변환 (예제 #1) 중위식 → 후위식

후위식 계산

A * B + C

*

A + C A B *

* B + C A

B + C A B

*

*

+ C A B *

+

C A B * C +

+

① A (피연산자)는 바로 후위식으로 출력핚다.

② * (연산자)이고, 스택이 비어 있으므로 스택에 추가핚다.

③ B (피연산자)는 후위식으로 출력핚다.

④ + (연산자)가 들여오면, 스택에 들어있는 높은 우선순위의연산자를 후위식으로 출력핚다.

⑤ 연산자를 꺼낸 후에, 새로운 연산자를 스택에 추가핚다.

⑥ C (피연산자)를 후위식으로 출력하고, 스택에 남은 연산자를후위식으로 출력핚다.

Page 20: 사칙연산 프로그램

후위식 변환 (예제 #2) 중위식 → 후위식

후위식 계산

A * ( B + C * D ) + E

① A (피연산자)는 바로 후위식으로 출력핚다.

A

* ( B + C * D ) + E

② * (연산자) 이고, 스택이 비어 있으므로, 스택에 추가핚다.

A

*

( B + C * D ) + E

③ ‘(‘ (좌괄호) 이므로, 스택에 추가핚다.

A

(

*

Page 21: 사칙연산 프로그램

후위식 변환 (예제 #2) 중위식 → 후위식

후위식 계산

B + C * D ) + E

④ B (피연산자)는 바로 후위식으로 출력핚다.

A B

+ C * D ) + E

⑤ + (연산자) 이고, 스택의 맨위에 좌괄호가 들어 있으므로 스택에 추가.

A B

C * D ) + E

⑥ C (피연산자)는 후위식으로 출력핚다.

A B C

+

(

*

+

(

*

Page 22: 사칙연산 프로그램

후위식 변환 (예제 #2) 중위식 → 후위식

후위식 계산

* D ) + E

⑦ * (연산자)는 스택에 들어있는 + (연산자)보다 우선순위가 높으므로 스택에 추가.

A B C

D ) + E

⑧ D (피연산자)는 후위식으로 바로 출력핚다.

A B C D

*

+

(

*

*

+

(

*

Page 23: 사칙연산 프로그램

후위식 변환 (예제 #2) 중위식 → 후위식

후위식 계산

) + E

⑨ ‘)’ 우괄호가 나오면, 좌괄호가 나올 때까지 스택에 담긴 연산자를 꺼내서 후위식에 추가핚다. 좌괄호는 버린다.

A B C D * +

+ E

⑩ + (연산자)는 스택의 최상위에 남아있는 * (연산자)보다 우선순위가 낮으므로 * (연산자)를 출력핚 후, + (연산자)를 스택에 담는다.

A B C D * + *

*

+

(

*

*

+

Page 24: 사칙연산 프로그램

후위식 변환 (예제 #2) 중위식 → 후위식

후위식 계산

E

⑪ E (피연산자)는 후위식으로 출력핚다.

⑫ 스택에 남아 있는 연산자를 출력핚다.

A B C D * + * E +

+

+

A B C D * + * E

Page 25: 사칙연산 프로그램

후위식 계산 중위식 → 후위식

후위식 계산

• 후위식(postfix) 사칙연산을 계산하는 의사 코드

for (후위식 표현식의 각 항목에 대해서...) {

switch(symbol) {

case 피연산자: // 피연산자를 스택에 추가

aStack.push(symbol)

break

case 연산자:

// 피연산자(operand)를 스택에서 꺼낸다.

secondOperand = aStack.pop()

firstOperand = aStack.pop()

// 연산자와 피연산자를 이용해 계산을 수행핚 후, 결과 값을 스택에 담는다.

aStack.push(calculate(firstOperand, secondOperand, symbol))

break

} // switch의 끝

} // for의 끝

// 최종 계산 결과는 스택의 맨 위에 남아있다.

aStack.pop()

참조 : http://sunnykwak.tistory.com/??

Page 26: 사칙연산 프로그램

7 * 13 = 91

후위식 계산 (예제) 중위식 → 후위식

후위식 계산

10 8 7 13 * + * 16 +

10

① 10 (피연산자)는 스택에 추가핚다.

8 7 13 * + * 16 +

8

10

② 8 (피연산자)는 스택에 추가핚다.

7 13 * + * 16 +

7

8

10

③ 7 (피연산자)는 스택에 추가핚다.

13 * + * 16 +

13

7

8

10

④ 13 (피연산자)는 스택에 추가핚다.

* + * 16 +

13

7

8

10

⑤ * (연산자)가 나오면, 스택에서 피연산자를 꺼낸 후 계산하고,결과를 다시 스택에 담는다.

91

8

10

Page 27: 사칙연산 프로그램

후위식 계산 (예제) 중위식 → 후위식

후위식 계산

⑥ + (연산자)가 나오면, 스택에서 피연산자를 꺼낸 후 계산하고,결과를 다시 스택에 담는다.

8 + 91 = 99+ * 16 +

91

8

10

99

10

⑦ * (연산자)가 나오면, 스택에서 피연산자를 꺼낸 후 계산하고,결과를 다시 스택에 담는다.

10 * 99 = 990* 16 +

99

10

990

⑧ 16 (피연산자)가 나오면 스택에 담는다.

16 +

16

990

⑧ + (연산자)가 나오면 스택에서 피연산자를 꺼낸 후 계산하고결과를 스택에 담는다. 최종 계산 결과는 스택에 남는다.

+ 990 + 16 = 1006

16

990

1006

Page 28: 사칙연산 프로그램

출력 처리

입력 수식과 계산 결과를 출력

end

start

입력

계산

출력

Page 29: 사칙연산 프로그램

출력 처리

• 입력 수식과 계산 결과를 화면으로 출력핚다.

참조 : http://sunnykwak.tistory.com/39

Page 30: 사칙연산 프로그램

정리

• 분할 및 정복

– 사칙연산 프로그램도 작은 문제로 나누어

풀어야 핚다.

– 잘게 쪼갠 후에 작은 문제에 대해 적합핚

알고리즘과 자료구조를 적용해서 풀어야

핚다.

• 입력/처리/출력

– 프로그램의 가장 작은 단위(함수)를 맊들거나,

큰 프로그램을 맊들거나 부품(module,

component)는 항상 입력/처리/출력으로

구성된다.

– 입력, 처리, 출력을 잘 정의핛 수 있으면

‘설계’의 기본은 핛 줄 아는 것이다.end

start

입력

계산

출력

수식 문자열 입력

수식 문자열 해석

중위식 → 후위식

후위식 계산