1619, 1/81 회원가입  로그인  
   sihun1113
   [참고] 분기 조건문 결정하기

http://www.hackerschool.org/HS_Boards/zboard.php?AllArticle=true&no=1745 [복사]


출저= 때릴꺼야
*----------------------------------------------------------------------------------------------------------*

이 카테고리는 그동안 배웠던것이라던가 공부하면서 알게된 내용들을 중심으로 혹여 참고가 될 수 있을까 싶은 내용들을

모아둔 곳입니다. 따라서 이 글들을 대상이 되는 분들은.. 프로그래밍을 갓 시작했거나 개념이 마구마구 흔들리시는 분들

정도가 되겠습니다. 그러니 너무 욕하지는 말아주세요 =_=;;;



혹시 제가 잘못 알고 있는 부분들이라던가 궁금한 것이 있으면 쪽지 남겨주시거나 리플을 달아주시면 감사하겠습니다.

*----------------------------------------------------------------------------------------------------------*



지난 스터디에서 약속한(?)대로 논리식(대학과정에서는 대수함수라고합니다)과 진리표를 이용해서 논리 조건문을 만드는 것을 공부 해 보겠습니다.





※ 앞에다 쓰는 후기(?)..

  - 설명을 한다고.. 쓰다보니 글이 엄청나게 조잡하고 제가봐도 이해하기 힘들게 쓰여졌습니다.

   글 중간에도 썼습니다만, 이 부분에 대한 제 자신의 이해도부터가 매우 부족한 것 같습니다.

   그래서 이 글은.. =_=;; 아예 건너 뛰시거나, 혹시 그래도 봐 보고자하신다면.. 제 개인적으론 아쉽

   지만 '이런게 있었나?'하고 넘어가는 정도로만 봐 주세요.

   공부하려 하신다면.. 오히려 복잡하게 만들 우려가 있는 듯 합니다 ㅠㅠ..

   글을 건너 뛰실 분들을 위해서 미리 말씀드리면, 다음 스터디 주제로는 함수에 대해서 알아볼까

   합니다. 함수에 대한 오해와 잘못된 사용법, 그리고 함수에서 포인터가 차지하는 비중등에 대해서

   알아보겠습니다. 그럼...





프로그래머들은 내가 원하는 결과를 내기 위해서 어떤 조건을 써야할까를 놓고 늘 고심합니다.

어떤 조건을 쓰느냐 따라서 코드가 단 몇줄짜리 간단한 코드로 줄어들 수도 있고, 반대로 조건문의 결정에 공을 들이지 않는다면.. 그만큼 손가락이 아파지겠지요. 최악의 경우 수배에서 수십배로 코드가 길어질 수도 있습니다. 전에 어떤 분이 피라미드 출력예제를 풀었는데 너무 코드가 길어서 좀 줄여달라는 글을 쓴것을 봤습니다. 엄청난 if문의 중복과 명확하지 않은 조건문들 때문에 매우 간단한 코드임에도 80 Line 가까이 되는 코드가 나왔습니다. 제가 그 코드를 정리해보니(알고리즘은 바꾸지 않고) 14 Line로 끝나는 간단한 코드였습니다. 거의 80% 가까이 Line수가 줄어들었습니다.



코드의 길이는 단순히 타자를 많이 치고 적게 치고의 문제로만 끝나지 않습니다. 긴 코드는 전체 흐름을 파악하는데 어려움을 준다는 치명적인 문제점이 있습니다. 반면, 짧은 코드는 가독성을 높여주지요. 때문에 불필요한 압축을 하지 않는 선에서 코드를 간결히 해 주는 것이 중요합니다.



조건문을 결정할때에는 첫째, 하나의 실행블럭에 대한 조건의 갯수를 확인해 두셔야 합니다.



예로, 내게 돈이 1000원 있는가?라는 문장과 가게에 1000원 이하의 아이스크림이 있는가?라는 두개의 문장에 대해서 나는 '아이스크림을 산다'라는 동작을 수행하고자 한다고 해봅시다.

여기서 우리는 두개의 조건을 얻을 수 있습니다.



쉽게 풀자면 위 조건에 대해서 이런 조건식을 뽑아 낼 수 있게 되지요.



1000원 있냐?

있다 -> 싼 아이스크림 있냐?

           있다 -> 산다.

           없다 -> X

없다 -> 싼 아이스크림 있냐?

           있다 -> X

           없다 -> X



여기서 눈치가 빠르신 분들은.. 이미 1000원 있냐는 조건에대해 없다 부분은 필요 없다는 것을 따로 나눌 필요가 없다는 것을 짐작하셨을겁니다. 그렇다면 이런 조건식이 되겠지요.



1000원 있냐?

있다 -> 싼 아이스크림 있냐?

           있다 -> 산다.

           없다 -> X

없다 -> X



여기서.. 조금 더 생각해 보면.. 더 줄일 수 있을거란 느낌이 팍팍! 오죠?



1000원 있냐?

있다 -> 싼 아이스크림 있냐?

           있다 -> 산다.



아니면 X



그래서 이걸 코드로 바꾸면



if( 1000 < 돈 )

    if( 1000 > 가격 )

        산다.



간단한 코드가 나왔습니다. 와~~..

하지만.. 여기서 생각해 볼 것이 하나 더 있습니다.



중학교때던가요? 고등학교때던가요?.. 진리표라는것을 배웠던 것으로 기억합니다.

만약, 1000원이 있다라는 조건을 A, 싼 아이스크림이 있다는 조건을 B라하고, 산다라는 행위를 R이라는 결과로 정의한다면 이 조건식을 아래와 같은 진리표로 만들 수 있습니다.



   A   |   B   ||   R

-------------------

   T    |   T   ||   T

   T    |   F   ||   F

   F    |   T   ||   F

   F    |   F   ||   F



진리표란 일련의 명제들에 대해 참과 거짓을 나타내어 연관 관계를 나타내는 표를 나타냅니다.

위의 진리표의 첫 줄을 보면 A가 참이고 B가 참일때 R은 참이다라는 연관 관계를 나타낸 것을 알 수 있습니다.



이러한 일련의 관계들을 수식화 한것을 대수함수라고 부르는데 대수함수의 표기는 아래와 같은 과정을 거칩니다.

첫째, 진리표에서 결과를 뜻하는 R에 대해서 T와 F로 구분합니다.



(그러나 이번 스터디 이후로는 T,F 구분보다 보기 편한 O,X 로 표기하겠습니다.)



예를들어 다음과 같은 진리표가 있다고 했을때



   A   |   B   |   C   ||   R

--------------------------

   O   |   O   |   O   ||   O

   O   |   O   |   X   ||   O

   O   |   X   |   O   ||   X

   O   |   X   |   X   ||   O

   X   |   O   |   O   ||   X

   X   |   O   |   X   ||   X

   X   |   X   |   O   ||   X

   X   |   X   |   X   ||   O



각 조건에 대해서 참일때는 A,B,C,R이라고 그대로 쓰고, 거짓일때는 A',B',C',R' 라고 표시합니다.(A'는 A 컴플리먼트:complement라고 읽습니다.)



R이 T가 되는 조건을 모두 찾습니다.

우선 A, B, C일때와 A, B, C'일때, A, B', C'일때, A', B', C'일때가 있습니다.

이를 표시할때는 아래와 같이 표시합니다.



R = ABC + ABC' + A'B'C'



즉, R을 참으로 만드는 요소들은 모두 곱하기로 연결하고, 조건간은 더하기로 연결합니다. 동일한 방법으로 R'를 찾으면



R' = AB'C' + A'BC + A'BC' + A'B'C



가 되겠습니다.

그나저나, 이때 사용되는 곱하기나 더하기는 도대체 무슨뜻인가?



곱하기는 다 아시죠? 앞에 있던 수가 10이됐건 100이 됐건, 수억이 있다 하더라도 뒤에 곱하는 수가 0 이면 어쨌든 결과는 0 입니다.

논리식에서는 1이나 0밖에 없습니다. 참이면 1, 거짓이면 0이지요. 따라서 A 나 B 둘중 어느 하나라도 0이면 결과인 R은 0이 됩니다. 반드시 둘다 1 일때만 R은 1이 됩니다. 그걸 표현한 식입니다.

여기에 논리 연산자 && 가 등장합니다. 이 '곱하기'에 해당하는 것이 && 연산자입니다.

우리 말로 표현하자면 '~가 참이고 ~도 참이면' 정도일까요?



그러면 더하기는? 이건 약간 다르게 봐야합니다. 거짓(False)는 0일때가 맞지만, 참(True)일때는 0이 아닌 것을 의미하기 때문이지요. 따라서 더하기로 연결된 수식에서는 해당 요소 중 어느것 하나라도 0이 아닌 참값이 있으면 결과는 참이 됩니다. 모두가 거짓일때만 거짓이 나오는 것으로 어찌보면 곱셈 연산의 정반대 의미를 가진 연산이라고 할까요? 더하기 연산에서 사용되는 논리 연산자는 || 가 사용되는데 우리 말로 표현하자면 '~가 참이거나 ~가 참이면' 정도가 될것 같군요.





이야기가.. 복잡해지고 정신산만해지기 시작합니다 @_@;;;

(진리표와 대수함수를 하기로)약속을 했기에 하기는 해야겠지만 막상하려니 제대로 정리가 되질 않네요. 제 머릿속에서 틀이 제대로 잡히지 않은 까닭인것 같습니다.







위 논리식을 if 를 사용한 식으로 뽑아내면



R = AB;

R' = AB' + A'B + A'B';



그러나 R'의 경우는 고려하지 않기 때문에 (else로 대체가능하기 때문에)



if( A && B )

    R;



이 됩니다. 즉,



if( 1000원이 있다 && 싼 아이스크림이 있다 )

    아이스크림을 산다;



라는 코드가 완성된다는 뜻입니다.





두번째로, 내가 만화방에서 만화책을 빌리려고 하는데, 만화방에서 만화를 빌리기 위해 대금을 지불하는 방법은 대체적으로 두가지정도 되죠? 하나는 직접 돈을 내고 빌리는 경우와 미리 예치해둔 선불금으로 빌리는 경우. 두가지를 놓고 만화책을 빌리는 것을 생각해 보겠습니다.



역시 '빌린다'라는 수행문 하나에 대해서 '돈이 있으면'와 '선불금이 있으면'라는 두가지 조건이 따라붙었습니다. 이에 대해서는, 돈이 있어도 빌릴 수 있고, 선불금이 있어도 빌릴 수 있겠지요?



돈이 있냐?

있다 -> 선불금이 있냐?

            있다 -> 빌린다.

            없다 -> 빌린다.

없다 -> 선불금이 있냐?

            있다 -> 빌린다.

            없다 -> 못빌린다.



이 조건문은 요약 과정을 거치지 않고 바로 진리표로 작성 해 봅시다.

돈이 있는가를 묻는 조건을 A, 선불금이 있는가를 묻는 조건을 B라고 하고, 빌린다라고 하는 행위를 R이라고 정의 했을때,



   A   |   B   ||   R

-------------------

   O   |   O   ||   O

   O   |   X   ||   O

   X   |   O   ||   O

   X   |   X   ||   X





라는 진리표를 그릴 수 있겠지요. 이제 앞서 언급하였던 논리식으로 뽑아보겠습니다.



R = AB + AB' + A'B;

R' = A'B';



자 여기서.. 알아 보고 넘어갈 것이 있습니다. 논리회로라는 대학과정 강의를 들어보신분은 아시겠지만, 대수식에서는 수학 사칙연산에 있는 '분배법칙'과 '교환법칙'이 성립합니다. 그리고 대수식만의 특징도 따로 가지고 있지요. 무슨 특징이냐? 논리합으로 연결된 요소들은 요소의 중복 사용이 가능하다는 것 입니다. 그렇다면 논리합의 중복사용이란 무엇이냐?



R = AB + AB'; 라는 식이 있을때 이 식에서 합으로 연결된 요소인 AB나 AB'를 여러번 중복해도 결과에는 변함이 없다는 것이지요. 즉,



R = AB + AB + AB + AB + AB + AB + AB' + AB' + AB' + AB' + AB' + AB' + ...; 이렇게 해도 결과는 같습니다. 다만, 불필요한 중복이라는게 문제겠지요 =_=;;



이런걸 어따가 쓸라고 놔두느냐?? 위의 진리표를 간단히 만드는데 필요한 것이라서 그렇습니다.



R = AB + AB' + A'B = AB + AB + AB' + A'B = AB + AB' + AB + A'B

                    논리합 중복                   교환법칙



   = (AB + AB') + (AB + A'B) = A(B+B') + (A+A')B = A + B;

                                   분배법칙



따라서 위 과정을 거치면 R = A+B로 간단히 정리가 됩니다.



사실 위 진리표는 A+B 즉, A||B 의 대표적인 진리표입니다.



아무리 많은 조건이 주어지더라도 진리표를 이용한 대수식을 잘 활용하면 나누어지는 분기 조건을 적절히 활용 할 수 있습니다.





이어서 분기 가지수가 많을 때는 어떻게 해야할까??

위에서 주어진 예들은 결과가 T/F로만 한정 된 예 였습니다. 그렇다면 3개 혹은 그 이상의 분기 가지가 있을때는 어떻게 할 것인가?



그때 역시 진리표를 활용 할 수 있습니다. 아래와 같은 방법으로 말이지요.



  A  |  B  |  C  |  D  ||  R1  |  R2

---------------------------------

  O  |  O  |  O  |  O  ||   O  |  O

  O  |  O  |  O  |  X  ||   X  |  O

  O  |  O  |  X  |  O  ||   O  |  O

  O  |  O  |  X  |  X  ||   X  |  O

  O  |  X  |  O  |  O  ||   O  |  O

  O  |  X  |  O  |  X  ||   O  |  X

  O  |  X  |  X  |  O  ||   X  |  X

  O  |  X  |  X  |  X  ||   O  |  X

  X  |  O  |  O  |  O  ||   O  |  O

  X  |  O  |  O  |  X  ||   X  |  O

  X  |  O  |  X  |  O  ||   X  |  X

  X  |  O  |  X  |  X  ||   X  |  O

  X  |  X  |  O  |  O  ||   O  |  O

  X  |  X  |  O  |  X  ||   O  |  X

  X  |  X  |  X  |  O  ||   X  |  X

  X  |  X  |  X  |  X  ||   O  |  X



R1R2 = ABCD + ABC'D + AB'CD + A'BCD + A'B'CD;

R1R2' = AB'CD' + AB'C'D' +  A'B'CD' + A'B'C'D';

R1'R2 = ABCD' + ABC'D' + A'BCD' + A'BC'D';

R1'R2' = AB'C'D + A'BC'D + A'B'C'D;



후아 복잡하죠?? 이 식들을 정리 해야합니다. 아무튼 이런 저런 식을 써 가면서 정리하게되면



R1R2 = ABD + CD;

R1R2' = B'D';

R1'R2 = BD';

R1'R2' = A'C'D + B'C'D;



어라?? 엄청나게 간단해 졌군요? 이런 방법을 통해서 분기문을 조절 할 수 있게 된답니다.

물론, 아예 대놓고 직접 조건을 다 쓰는 방법도 있지만 간단할 수록 좋은 코드라는 건 누구나 알 수 있으니까요.

위 코드는 이런 if문으로 전환이 가능합니다.



if( ( A&&B&&D ) || (C&&D) )

    R1R2;



if( !B && !D )

    R1R2';



if( B && !D )

    R1'R2;



if( (!A && !C && D ) || ( !B && !C && D ) )

    R1'R2';



아직도 복잡하기는 하지만 엄청나게 복잡한것은 아니죠??

여담인데요 참고로.. if/else if/else 문으로 구성할때는 더 간단히 만들 수도 있답니다 +_+

실례를 보여드리자면.. 위와 똑같은 조건을 놓고 사용할때..



if( B && !D )
    R1'R2;

else if ( !D )

    R1R2;

else if ( (C && D) || (A && B) )

    R1R2;

else

    R1'R2';



감이 오실지 모르겠군요.. 이 부분을 좀 더 자세히 알아보고 싶으신 분은.. 논리회로 과정중에 있는 카르노 맵이라는 항목을 참고해 보시면 도움이 될 것 같습니다.

  Hit : 8687     Date : 2011/05/01 11:32