{{ label!='' ? 'Label : ' : (q!='' ? '검색 : ' : '전체 게시글') }} {{ label }} {{ q }} {{ ('('+(pubs|date:'yyyy-MM')+')') }}

[Java] 자바로 프로그래밍 입문하기: 1.2. 내장 자료형(Built-in Type) (2)

정수(Integers)

  int는 -2147483648 (-2^31) 부터 2147483647 (2^31-1) 사이의 정수입니다. 이런 범위를 갖는 이유는, 정수를 표현할 때 32개의 이진수를 이용하기 때문입니다. 이진법이란 0과 1만을 사용하는, 컴퓨터과학에서 흔히 사용하는 수 체계입니다. 보통 이진수를 bit라고 말합니다. bit는 0 혹은 1의 값입니다.

  

  이 연산자들은 초등학교 때 배운 것들과 다르지 않습니다. 단, 모든 결과는 정수가 된다는 점에 유의하세요. 따라서 두 int 값 a와 b가 주어질 때, a / b 의 나머지는 버리며, a % b 의 값을 통해 a를 b로 나눈 나머지의 값을 얻을 수 있습니다. 예를 들어 17 / 3 = 5 이며, 17 % 3 = 2 입니다.

  int 연산 결과는 우리가 예상하는 그대로 수학적으로 도출되지만, 32비트의 표현을 넘어갈 때에는 예외입니다. 이 때에는 잘 정의된 규칙에 의해서 값이 변하게 될 것이며, 이를 오버플로우(overflow)라고 칭합니다.


프로그램 1.2.2: IntOps, 정수의 곱셈과 나눗셈

public class IntOps
{
	public static void main(String[] args)
	{
		int a = Integer.parseInt(args[0]);
		int b = Integer.parseInt(args[1]);
		int p = a * b;
		int q = a / b;
		int r = a % b;
		System.out.println(a + " * " + b + " = " + p);
		System.out.println(a + " / " + b + " = " + q);
		System.out.println(a + " % " + b + " = " + r);
		System.out.println(a + " = " + q + " * " + b + " + " + r);
	}
}
% javac IntOps.java
% java IntOps 1234 99
1234 * 99 = 122166
1234 / 99 = 12
1234 % 99 = 46
1234 = 12 * 99 + 46

  <프로그램 1.2.2>를 통해 정수의 기본 연산자들을 다루는 프로그램의 모습을 볼 수 있습니다.

  자바에서 세 개의 내장 자료형, long, short, byte 자료형은 int와 같이 정수를 표현하는 자료형입니다. 다만 그 범위가 64, 16, 8bit으로만 이루어져 있으므로, 허용 값의 범위만 다릅니다. 아주 큰 값을 다룰 때에는 long을 사용한다든가 하는 것입니다.


부동소수점 수(Floating-point numbers)

  double 자료형은 부동소수점 수를 표현하며, 과학 및 상업 응용 프로그램에서 자주 사용됩니다. 우리는 실수를 표현하기 위해서 부동소수점을 사용합니다. 하지만 완전히 실수와 같지는 않습니다.

  무한히 많은 실수들이 있겠지만, 우리는 어떤 컴퓨터라도 감당할 수 있는 유한한 숫자만 표현해야 합니다. '부동소수점 수'는 실수와 아주 비슷하게 동작하지만, 가끔은 정확하지 않다는 단점도 있습니다. 정확한 계산이 필요할 땐 신중하게 사용하도록 하세요. 컴퓨터가 부동소수점을 다루는 방식에 대해서는 이야기하지 않을 것이며, 궁금하다면 따로 찾아보기를 권합니다.

  다만 자바에서 리터럴 6.022e23은 부동소수점 수 6.022 * 10^23을 의미합니다. 즉, e뒤의 숫자는 그만큼 소수점을 우측으로 옮긴다는 의미입니다. 또한 2.0과 같이 그냥 소수를 직접 쓰는 것도 실수의 리터럴입니다.


프로그램 1.2.3: Quadratic formula, 근의 공식

public class Quadratic
{
	public static void main(String[] args)
	{
		double b = Double.parseDouble(args[0]);
		double c = Double.parseDouble(args[1]);
		double discriminant = b*b - 4.0*c;
		double d = Math.sqrt(discriminant);
		System.out.println((-b + d) / 2.0);
		System.out.println((-b - d) / 2.0);
	}
}

% javac Quadratic.java
% java Quadratic -3.0 2.0
2.0
1.0

% java Quadratic -1.0 -1.0
1.618033988749895
-0.6180339887498949

% java Quadratic 1.0 1.0
NaN
NaN

  <프로그램 1.2.3>은 x^2 + bx + c 의 해를 계산합니다. 자바 Math 라이브러리에는 기본적인 연산 말고도 제곱근, 삼각함수, 로그/지수 함수 등 다양한 함수들을 지원합니다. 이런 수식들을 사용하고 싶다면, 함수의 이름과 괄호 안에 인자를 넣으면 됩니다. 예를 들어, 2의 양의 제곱근을 얻고 싶다면 Math.sqrt(2.0) 을 사용할 수 있습니다.

  부동소수점 수를 다루다보면, 무한소수의 문제에 부딪힐 수 있는데, 이 역시 1.5절에서 출력의 자릿수를 제한할 수 있는 방법에 대해 배워볼 것입니다.

  또한 계산 값이 실수가 아닌 경우(NaN)에도 문제가 발생할 수 있습니다. 이런 경우들에 전부 대비하는 것도 좋겠지만, 입문자 단계에선 신경 쓰지 않고 자연스럽게 double을 사용해도 프로그램에 문제가 생기지 않으며 <프로그램 1.2.3>은 그 예를 보여줍니다.


불리언(Booleans)



  boolean 자료형은 두 값만을 가집니다. 참(true)과 거짓(false). 모든 boolean 값은 참과 거짓 중 하나이며, 연산자 역시 참과 거짓 중 하나를 반환합니다.

  boolean 을 위해 정의된 중요한 연산자들은 and(&&), or(||), not(!) 입니다.

  1. a && b 는 두 피연산자가 둘 다 참일 때만 참입니다. 그 외의 경우에는 거짓입니다.
  2. a || b 는 두 피연산자가 둘 다 거짓일 때만 거짓입니다. 그 외의 경우에는 참입니다.
  3. !a 는 a가 참이면 거짓, 거짓이면 참입니다.



  우리는 프로그램의 동작을 제어하는데 boolean을 사용할 것이기 때문에, boolean은 아주 중요합니다. 특정한 상태에서만 프로그램이 동작하게 만들고 싶을 때, boolean을 적극적으로 활용하게 될 것입니다. 이는 1.3절에서 다루겠습니다.


비교

  혼합형 연산자(Mixed-type operator)는 특정 자료형의 피연산자를 취해, 그와 다른 자료형의 결과를 내놓는 연산자입니다. 이런 연산자들 중 가장 중요한 연산자들은 비교 연산자(Comparison operators)들입니다. ==, !=, <, <=, >, >=와 같은 것들이죠. 이것들은 전부 기본 숫자 자료형에 대해 잘 정의되어 있고, boolean 값을 내놓습니다. 

  다음은 전형적인 비교 연산에 대한 그림이며, 각각 판별식이 음수가 아닌지, 세기의 시작년도인지, 올바른 달(월)의 숫자인지를 판단하는 수식입니다.



프로그램 1.2.4: Leap year, 윤년

public class LeapYear
{
	public static void main(String[] args)
	{
		int year = Integer.parseInt(args[0]);
		boolean isLeapYear;
		isLeapYear = (year % 4 == 0);
		isLeapYear = isLeapYear && (year % 100 != 0);
		isLeapYear = isLeapYear || (year % 400 == 0);
		System.out.println(isLeapYear);
	}
}
% javac LeapYear.java
% java LeapYear 2004
true
% java LeapYear 1900
false
% java LeapYear 2000
true

  <프로그램 1.2.4>는 주어진 연도가 윤년인지 아닌지를 판단합니다.

  비교 연산자들은 앞서 언급한 자료형들에만 정의가 되어 있습니다. 같은 형태의 연산자여도 각 자료형에 따라 정의가 다릅니다. 예를 들어 정수끼리의 비교인지 실수끼리의 비교인지에 따라서 그 세부적인 사항들은 서로 다르게 정의되어 있습니다. 그러므로 양쪽의 피연산자는 반드시 같은 자료형이어야 합니다.

  숫자 표현의 세부적인 사항을 들춰볼 필요도 없이, 다양한 자료형들에 대한 같은 형태의 비교연산자들이 서로 다르다는 것은 쉽게 알 수 있습니다. 예를 들어, 두 int를 비교하는 (2  <= 2)는 명료하게 참입니다. 하지만 두 double을 비교하는 (2.0 <= 0.002e3)은 참일까요, 거짓일까요? 이는 int와는 확실히 다른 비교 방법이 필요함이 느껴집니다. 즉 같은 '<=' 연산자여도 자료형마다 그 연산 방식은 서로 다를 수 있으므로, 양쪽의 피연산자는 반드시 같은 자료형이어야 합니다.



  이제껏 해온 것처럼 많은 프로그램들은, 자료형 간의 내장형 연산자 및 수많은 자바 라이브러리 메소드를 사용하고 있습니다. 라이브러리 메소드의 수는 굉장히 많습니다. 프로그래밍을 배우는 것처럼 라이브러리 메소드를 더 많이 사용하는 방법에 대해서도 배울 것이지만, 입문자에게 좋은 방법은 몇 가지 메소드에만 집중하는 것입니다.

  이 챕터에서 여러분은 이미 출력을 하는 자바의 메소드를 사용했고, 자료형을 다른 자료형으로 바꾸는 것, 그리고 여러 수학 함수들을 계산해주는 메소드들도 사용해봤습니다. 이후에는 다른 메소드들을 어떻게 사용하는지 뿐만 아니라, 나만의 메소드를 만드는 방법에 대해서도 배울 것입니다.

  편의를 위해, 다음 표를 통해 몇가지 메소드들을 소개합니다.


  이런 표를 Application Programming Interface, 즉 API라고 칭합니다. API는 응용프로그램을 만드는 데 필요한 메소드들의 정보를 제공합니다. 다음은 자바의 Math 라이브러리의 API입니다.


  random()을 제외하고 이 메소드들은 전부 수학 함수입니다. 수학 함수란, 인자를 이용해 특정 자료형의 값을 계산해내는 것입니다. 각 메소드는 API의 각 줄에 설명이 되어있으며, 메소드를 사용하는 방법에 대해 기술되어 있습니다. 


  앞서 표에 기술된 API들은 사실 코드라고 말하기엔 거리가 멀고, 여러분이 메소드를 사용하기 위해 입력해야 하는 것입니다. 메소드의 시그니처(signature)라고 합니다. 시그니처는 인자, 메소드 이름, 메소드가 반환하는 값의 자료형 3가지를 포함합니다. 프로그램이 실행될 때 우리가 어떤 메소드를 사용해서 어떤 값을 받아내는 행위를, 시스템 라이브러리 코드를 '호출한다(call)'고 합니다.

  random()은 인자를 받지 않기 때문에, 수학의 함수와는 다르다는 점을 참고하세요. 비슷하게, System.out.print()와 System.out.println()은 아무것도 반환하지 않으므로 수학적 함수가 아닙니다. 이렇게 아무것도 반환하지 않는 경우 시그니처에서 void로 명시가 되어있습니다.

  여러분의 코드에서 메소드의 이름을 쓰고, 명시된 타입의 인자를 괄호 안에 (인자가 여러개라면 쉼표로 분리해서) 넣으면, 라이브러리 메소드를 이용할 수 있습니다.

  다음은 자바의 변환 메소드의 API이며, 명령행 인자를 받을 때 사용합니다.





  현대 프로그래밍에서 API는 보통 온라인 문서에 기술되어 있습니다. 숙련된 프로그래머들이 사용하기 위한 자바의 API들도 전부 기술되어 있으며, 여러분들 역시 흥미가 있다면 사용할 수 있습니다. 챕터 2와 3에서는 나만의 API를 만들고 함수를 구현하는 방법에 대해서 배울 것입니다.


형변환(Type conversion)

  프로그래밍을 하면서 기본적으로 지켜야 할 것 중 하나는 프로그램이 처리하고 있는 자료들의 자료형에 대해 항상 알고 있어야 한다는 점입니다. 해당 변수의 자료형을 알아야만, 그 변수가 어떤 값을 가질 수 있는지, 어떤 리터럴을 사용할 수 있는지, 어떤 연산을 적용할 수 있는지 정확히 알 수 있기 때문입니다.

  요즈음에는 자료형을 깊게 신경쓰지 않아도 되는 언어들이 늘어나고 있습니다. 하지만 여전히 자료형에 대한 이해가 중요하다는 점은 변하지 않으며, 자바에서는 더더욱 그렇습니다.


명시적 형변환(Explicit type conversion)

  여러분은 형변환을 위해 인자로 한 자료형을 받아 다른 자료형으로 변환해주는 메소드를 사용할 수 있습니다. 우리가 이전에 사용해봤던 Integer.parseInt() 와 Double.parseDouble()과 같은 것들이 그 예입니다.


명시적 형변환(Explicit cast)

  한국어로는 둘 다 같은 용어이지만, 개념적으로 약간 다릅니다. Cast는 일부 정보를 잃는 것을 감수할 수 있을 때 사용하는 자료형 변환입니다. 리터럴 앞에 형변환 하고 싶은 자료형을 괄호로 둘러싸서 표현합니다. 예를 들어, (int) 2.71828은 double형에서 int형으로 바뀌며, 소수점 이하의 값이 버려져 2가 됩니다. 


자동 프로모션(Automatic promotion for numbers)

  자바에서 더 큰 범위의 자료형은 자동으로 변환해줍니다. 더 큰 범위의 숫자 자료형이 들어갈 수 있는 자리에는 어떤 기본 숫자 자료형이든 들어갈 수 있습니다. 이런 자료형 변환을 프로모션(Promotion)이라고 합니다. 

  예를 들어, <프로그램 1.2.3>에서 우리는 모든 숫자들을 double형으로 사용했으므로, 형변환이 이루어지지 않았습니다. 만약 우리가 b나 c를 int형으로 선언했다면, 자동 프로모션이 적용되어 b*b - 4.0*c를 계산했을 것입니다. b와 c가 int형일 때 프로모션의 순서는 다음과 같습니다.

  1. b는 int형이고, b*b는 문제 없이 int형으로 계산이 수행됩니다.
  2. 4.0 * c에서 4.0은 double형이므로, int형인 c를 double형으로 프로모션 하여 계산을 수행합니다.
  3. (b*b) - (4.0*c)에서 (4.0*c)는 double형이므로, int형인 (b*b)를 double형으로 프로모션 하여 계산합니다.
  4. 결국 double형의 결과가 생성됩니다.

다음은 형변환들의 예이며, 형변환의 우선순위에 유의하세요. 이것으로 이번 글을 마칩니다.


1.2. 내장 자료형 끝.

댓글

이 블로그의 인기 게시물

[코딩의탑] 4층: 툰 쉐이딩

[코딩의탑] 3층: 바다 렌더링

[코딩의탑] 5층: 포탈(Portal), 더 나아가기