Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

Contents

이번장에서 다를 내용은 다음과 같다.
  1. 하나의 block 만을 가지는 if
  2. 산술연산에서의 Boolean(:12) 표현
  3. Picking the right relational symbol
  4. 여러개의 if 문 사용
문제 상가를 걷고 있는 당신은 지금 배가 고파진 상태다. 그러다가 빵가게 앞을 지나게 되었고, 고소한 쿠키냄새를 맡게 되었다. 어떻게 할 것인가?

단일 블럭을 가지는 if 문

하나의 블럭만을 가지는 if 문을 생각해볼 수 있을 것이다. 위의 문제의 경우 여러분은 배가 고파진 상태에서 쿠키를 살 것인지 말것인지를 고민하게 될 것이다. 배가 부르다면 쿠키를 사지 않을 것이다. 이 경우 여러분의 마음속에 다음과 같은 질문이 생겨날 것이다. 배가 고픈가 ? Are you hungry ?

대답은 true, false 둘중 하나일 것이다. 만약 (if) 답이 true 라면 "buy cookies"를 실행할 것이다. 그다음 "done"을 실행한다. 만약 답이 false 라면 아무것도 실행하지 않고 "done"를 실행한다. (가던 길을 그냥 간다)

문제 이번장이 이전장과 다른점이 무엇인가. ?

단일 문맥을 가지는 if

쿠키 문제를 살펴보자. 당신은 쿠키 구입할 것인가 ? 실제 여러분은 다양한 조건을 가지고 쿠키를 구입할 것이다. 배고픈 정도, 맛있어 보이는 정도, 냄새 등등에 영향을 받을 것이다. 그래서 조건을 좀 더 다양하게 하기로 했다. hunger, smell, look의 3가지 조건을 만들고 1에서 10까지의 값을 선택할 수 있도록 했다. 그래서 3가지 조건의 값이 15이상이 되면 쿠키를 구입하는 프로그램을 만들었다.
import java.util.Scanner ;
class CookieDecision
{
  public static void main (String[] args) 
  {
    Scanner scan = new Scanner( System.in );
    int hunger, look, smell ;

    System.out.print("How hungry are you?            (1-10): ");
    hunger = scan.nextInt();

    System.out.print("How nice do the cookies look?  (1-10): ");
    look   = scan.nextInt();

    System.out.print("How nice do the cookies smell? (1-10): ");
    smell  = scan.nextInt();

    if ( (hunger + look + smell ) > 15 )
      System.out.println("Buy cookies!"  );

    System.out.println("Continue down the Mall.");
  }
}
단일 문맥을 가진 다는 얘기는 오직 하나의 선택 즉 일 경우 (혹은 거짓일 경우)를 위한 코드가 준비되어 있음을 의미한다. 위의 경우는 다음과 같은 처리 과정을 거친다.
  • if 문으로 두 개의 숫자를 비교한다. 왼쪽은 변수들의 합이고, 오른쪽은 비교될 상수 값 15다.
  • 만약 15 보다 크다면 즉 참이라면, 쿠키를 구입하기 위한 문맥을 실행한다.
  • 만약 15 보다 작다면 즉 거짓이라면, 쿠키 구입을 위한 문맥을 건너뛴다.
  • 두 경우 모두에 대해서 다음 코드를 수행한다.
문제 hunger, look, smell 이 4, 6, 9 라면 쿠키를 구입하는가 ?

산술 연산과 논리 연산

3개의 값을 더한 19는 무턱 값인 상수 15보다 크기 때문에, 참 문맥이 실행된다. (hunger + look + smeel) > 15 는 참

먼저 hunger, look, smell의 값을 모두 더한다. 그리고 나서 문턱 값과 비교한다. 괄호는 3개의 숫자를 더하는 연산을 명확히 하기 위해서 사용한다. 만약 괄호를 사용하지 않으면 어떻게 될까 ? 그래도 동일한 결과를 보여준다. 왜냐하면 산술 연산은 논리 연산 보다 높은 우선순위를 가진다. 그러므로 더하기가 먼저 수행되고, 다음에 비교를 하기 때문이다.

문제 다음의 계산 결과가 참일지 거짓일지 예상해 보자.
12 + 4 > 16 5.2 - 1.2 <= 2.0+2 2*3-4 == 1+1

더블형 연산의 위험

다음의 표현이 맞을지 생각해 보자. 4.0/3.0 == 1.0 + 1.0/3.0 언뜻 생각해서 이라고 생각할 수 있을 것이다. 참이여야 맞을 것 같다. 그렇지만 그렇지 않다. Floating point 산술 연산은 정확하지 않다. 절대로 플로팅 포인트 값을 비교하는 일을 하지 말라. 컴퓨터는 데이터 형의 크기에 한계 때문에, 정확도에 제한이 있을 수 밖에 없다. 예를들어 64 비트 더블형이라고 해도 정확하지 않다.

플로팅 포인트 연산을 종이와 연필로 하는 산술연산처럼 생각해서는 안된다. 다음의 결과는 참 일까 ? 1.0/3.0 == 0.3333333 참이 아니다. 플로팅 포인팅 연산은 대략적일 뿐이다. 이것은 Java에서 뿐아니라. 다른 모든 언어들도 마찬가지며, 이것은 컴퓨터의 한계이기도 하다. 정밀도에 신경쓰지 않고 싶다면 integer 연산을 사용하자.

문제 다음의 결과는 ?
class DecimalFraction
{
  public static void main (String[] args)
  {
    float x = 1.0f;    // 1.0f means 1.0 float
    float y = 10.0f;
    
    if ( x/y == 0.1 )
      System.out.println("Buy the cookie!"  );
    else
      System.out.println("No cookie for you.");
  }
}

if문의 다양성

if 문은 다양한 방식으로 사용할 수 있다. 하나 혹은 두개의 문맥을 가지도록 할 수 있으며, 각 문맥에서 또다른 if 문을 사용하도록 할 수 있다. 다음 테이블은 if 문의 다양한 활용을 보여준다.
Varieties of if Statements
 
if ( booleanExpression )
  statement; 
 
if ( booleanExpression )
{
  one or more statements 
}
 
if ( booleanExpression )
  statement; 
else 
  statement; 
 
if ( booleanExpression )
{
  one or more statements 
}
else 
{
  one or more statements 
}
 
if ( booleanExpression )
  statement; 
else {
  one or more statements 
}
 
if ( booleanExpression )
{
  one or more statements 
}
else 
  statement; 
위의 형식에서는 몇 종류의 들여쓰기 방법 (identing)을 보여준다. 자바 컴파일러는 identing를 무시하지만, 사람이 코드를 보기에 좋기 때문에 자기에게 맞는 identing 방법을 선택한다.

어떤 스타일을 사용해도 문제 없지만, 보통은 tab이나 일정한 갯수의 white space 문자를 이용해서 identing을 한다. 논리 계산은 일반적으로 몇 단계의 깊이를 지니게 마련인데, identing은 그 자체가 논리의 깊으를 은유하는 측면이 있기 때문에 체계적인 identing는 프로그램의 논리적 흐름을 쉽게 따라가게 해주며, 에러도 쉽게 찾도록 해준다.

문제 다음의 if 문은 옳은가 ?
if ( booleanExpression ){
    one or more statements
}else{
    one or more statements }

논리적으로 위의 구문은 다음과 동일하다.
if ( booleanExpression )
{
    one or more statements
}
else 
{
    one or more statements 
}
위 두개의 방식 중 어떤 방식을 선호하는지는 프로그래머에 따라 다르다. 하나의 화면에 많은 코드를 보여주기를 원하는 프로그래머의 경우 if문의 첫 줄에 괄호를 사용하는 걸 선호하는 경우가 있다. 반면 블럭을 명확히 선택하기를 원하는 프로그래머의 경우 두번째 방식을 선호한다.

또다른 문제

당신은 쇼핑 중이다. 44.95달러의 멋진 스웨터를 보게 되고 지름신의 강림한다. 그러나 쿠키를 사는데 돈을 소비했기 때문에, 충분한 돈이 있을지를 모르겠다. 이 프로그램은 당신이 가진 돈으로 스웨터를 구입할 수 있을 지를 알려준다.
import java.util.Scanner;
class SweaterPurchase
{
  public static void main (String[] args)
  { 
    final int price = 4495;    // price in cents

    Scanner scan = new Scanner( System.in );
 
    int cash;                       

    System.out.println("How much do you have, in pennies?");
    cash   = scan.nextInt();     
    
    if (_______________________)   // 여기를 완성하자.
      System.out.println("You can buy the sweater." );
    else
    {
      System.out.println("You can't buy the sweater." );
      System.out.println("You need " + (price-cash) + " more cents." );
    }

  }
이 프로그램은 아직 컴파일 되지 않는다. 15 줄을 아직 채우지 않았기 때문이다. 이 프로그램이 제대로 컴파일되고 작동되기 위해서 15줄을 완성해 보도록 하자.

Reverse Logic

위 프로그램을 실행 시킨 결과다.
How much do you have, in pennies?
5000
You can buy the sweater.
5000은 스웨터의 가격보다 크기 때문에 참이고, 참과 관련된 블럭의 코드가 실행됐다. 다시 한번 실행시켜 보았다.
How much do you have, in pennies?
2000
You can't buy the sweater.
You need 2495 more cents.
스웨터를 구입하기엔 2495달러가 부족하다. 때문에 거짓 블럭이 실행됐다.

논리 연산은 항상 아니면 거짓중 하나의 값을 가진다. 이를 위해서 사용할 수 있는 연산자로는 ==, >, <, >=, <=, != 등이 있다. 참이면 참 블럭을 실행하고 거짓이면 거짓 블럭을 실행한다. 이는 반대가 될 수 있다. 다음의 코드를 완성해 보자.
import java.util.Scanner;
class SweaterPurchase
{
  public static void main (String[] args)
  { 
    final int price = 4495;    // price in cents

    Scanner scan = new Scanner( System.in );
 
    int cash;                       

    System.out.println("How much do you have, in pennies?");
    cash   = scan.nextInt();     
    
    if (____________________)  // 여기를 완성해 보자.
    {
      System.out.println("You can't buy the sweater." );
      System.out.println("You need " + (price-cash) + " more cents." );
    }
    else
      System.out.println("You can buy the sweater." );

  }
}
참과 거짓에서 실행할 블럭이 반대가 되었다. 이를 만족하도록 빈 줄을 채워보자.

Opposites

첫번째 프로그램에서 논리 연산의 표현식은 다음과 같았다.
if (cash >= price)
두번째 프로그램은 블럭이 서로 반대가 되었으므로 표현식 역시 다음과 같이 반대가 되어야 한다.
if (cash < price)

>=와 <는 서로가 반대되는 평가를 하게 된다.

여러가지 선택

때때로 여러번의 선택이 필요할 경우도 있다. 자가용을 사러갔다. 자가용의 가격은 20000달러다. 그러나 이걸로 끝이 아니라는 것은 다들 알 것이다. 옵션 선택에 따른 가격 추가 요인이 있기 때문이다. 다음과 같은 옵션을 선택할 수 있다고 가정해 보자.
  1. pin strips - 250
  2. anti-lock brakes - 800
최종 자동차 가격은 자동차 본체 가격에 위의 옵션 중 선택한 것의 가격을 합한 것이 될 것이다.

다음은 자동차 구입가격을 산출하는 프로그램이다. 빈칸을 채워서 완전한 프로그램을 만들어 보자.
import java.util.Scanner;
class CarPurchase
{
  public static void main (String[] args) 
  { 
    final int basePrice  = 20000;   // base price in dollars
    final int pinPrice   =   250;   // pin stripe price
    final int brakePrice =   800;   // anti-lock brake price

    Scanner scan = new Scanner( System.in );
 
    int answer;
    int totalCost = basePrice;

    System.out.print("Do you want pin stripes (0 or 1)? ");
     
    answer = scan.nextInt();        
    if (_____________________)   // 빈칸
    {
      totalCost = totalCost + pinPrice;
    }

    System.out.print("Do you want anti-lock brakes (0 or 1)? ");
    answer = scan.nextInt(); 
    if (_____________________)   // 빈칸
    {
      totalCost = totalCost + brakePrice;
    }

    System.out.println("Total cost is: $" + totalCost ); 
  }
}

if(answer == 1)
if(answer == 1)

프로그램의 실행 다음은 이 프로그램을 실행한 결과다.
Do you want pin stripes (0 or 1)? 0
Do you want anti-lock brakes (0 or 1)? 1
Total cost is: $20800

플로우 차트

프로그램에서 선택은 참, 아니면 거짓의 형태로 이루어진다. 그러므로 논리 선택이 일어나는 곳에서 프로그램이 참 블럭, 혹은 거짓 블럭을 수행하는 방식으로 분기하게 된다. 이 논리적인 흐름을 한눈에 조망하기 쉽게 그림으로 나타낸 것을 플로우 차트라고 한다. 위의 자동차 가격 산정 프로그램의 플로우 차트를 그려보자.

0,1대신에 2를 입력하면 어떻게 될까 ?

위 코드의 논리 연산은 단지 answer이 1인 경우만을 참으로 한다. 그러므로 0을 포함한 1이 아닌 모든 숫자에 대해서 0을 입력한 것과 마찬가지의 결과를 보인다. 즉 0과 1대신 다른 값을 집어 넣어도 프로그램은 문제 없이 작동한다. 그러나 이러한 프로그램은 사용자의 예측할 수 없는 입력에 대응할 수 없기 때문에, 논리적인 문제를 일으킬 수 있다. 그러므로 제대로된 프로그램을 개발하기 원한다면, 입력 값을 검사해야 한다. 위 코드의 경우 0과 1이외에 값을 넣으면 에러 메시지를 출력하도록 해야 할 것이다.