정수 자료형과 실수 자료형

정수 자료형과 실수 자료형

알고리즘 문제를 풀 때, 값의 표현 범위로 인해 틀릴 경우가 엄청 많다.

예를 들어 int 타입 변수를 선언하고 팩토리얼 계산을 했을 경우

public class Main {
    public static void main(String[] args) {
        int N = 13;
        int factorial = 1;
        for (int i = 1; i <= N; i++) {
            factorial *= i;

            System.out.println(i + "! = " + factorial);
        }
    }
}

실행 결과

1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600
13! = 1932053504

12!까지는 정상적인 값이 출력되지만, 13!의 경우 int형의 최대 범위를 넘어서, 잘못된 값이 출력된다.

이를 위해 JAVA에서의 정수 자료형과 실수 자료형에 대해 정리하려고 한다.

정수 자료형(Integer type)

자바의 대표적인 정수 자료형은 intlong이다.

Type Byte Range of Values
byte 1Byte -128 ~ 127
short 2Byte -32768 ~ 32767
int 4Byte -2,147,483,648 ~ 2,147,483,647
long 8Byte -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807

위 표에 따르면,

int 자료형은 대략 -21억(-2e9) ~ 21억(2e9) 사이 값을 표현하고

long 자료형은 대략 -92경(-9e18) ~ 92경(9e18) 사이 값을 표현한다.

각 자료형의 최대값에서 추가로 값을 더하거나 최소값에서 추가로 값을 뺀다면 그 만큼 오버플로우가 일어난다.


실수 자료형(float type)

실수를 2진수로 표현하려면 어떻게 해야할까?

2의 음수 거듭 제곱을 사용하여 표현 할 수 있다.

  • 예를 들어 3.75를 이진수로 표현하면 다음과 같다.
    • $3.75$ = $2$ + $1$ + $0.5$ + $0.25$ = $2^1$ + $2^0$ + $2^{-1}$ + $2^{-2}$ = $11.11_{(2)}$
  • 10진수의 무한소수는 2진수 표현 시에도 무한소수가 나타난다.
    • $1/3$ = $0.333...$ = $2^{-2}$ + $2^{-4}$ + $2^{6}$ + $...$ = $0.010101..._{(2)}$

자바의 대표적인 실수 자료형은 floatdouble이며, 각각의 자료형은 다음과 같은 비트 수로 실수를 저장한다.

Type bits of sign field bits of exponent field bits of fraction field
float 1 8 23
double 1 11 52

각 필드는 실수의 부호(sign), 지수(exponent), 그리고 가수(fraction)를 나타낸다. (자세한 내용은 IEEE-754 format을 찾아 볼 것.)

  • Sign (부호): 부호 필드는 실수의 부호를 나타내며, 1 비트로 표현된다.
  • Exponent (지수): 지수 필드는 실수의 지수 부분을 저장합니다. float는 8 비트, double은 11 비트로 표현된다. 이 지수는 2의 보수 형식으로 표현되며, 특정 바이어스(각각 127, 1023)를 더해 실제 지수값을 나타낸다.
  • Fraction (가수): 가수 필드는 실수의 소수 부분을 저장한다. float는 23 비트, double은 52 비트로 표현된다. 이는 정규화된 형태로 저장되어 있어 실수의 정밀도를 결정한다.

예를 들어, -6.75를 각각 float, double 자료형으로 나타내 메모리에 저장한다고 한다면 다음과 같다.

$-6.75$ = $-1.1011_{(2)}$ * $2^2$

Sign Exponent Fraction
1 10000001 10110000000000000000000
1 10000000001 1011000000000000000000000000000000000000000000000000

실수 자료형을 다룰 때, 중요한 점

  • 실수의 저장/연산 과정에서 반드시 오차가 발생한다.
    • (0.1 + 0.1 + 0.1) == 0.3 -> flase
    • float: 유효 숫자 6
    • dobule: 유효 숫자 15
  • 실수 비교시에는 등호를 사용하지 않는다.
    • 대안 -> abs(a-b) < 1e-12

Reference

바킹독의 실전 알고리즘 0x01강 - 기초 코드 작성 요령 I