[JAVA] 정수형과 실수형 - 정밀도를 주의하자!

2023. 11. 11. 19:34프로그래밍 언어/Java

1. 정수형 - byte, short, int, long

정수형 변수의 자료형은 4개가 있으며 차례로 1byte, 2byte, 4byte, 8byte이다. 

 

모든 정수형은 n개의 비트에 대해 가장 왼쪽의 비트를 부호 비트로 사용하고 나머지는 값을 표현하는 데 사용한다. 따라서 n비트로 표현할 수 있는 부호 있는 정수의 범위는 -2^(n-1) ~ 2^(n-1) - 1이다. 


2. 실수형 - float, double

실수형은 차례로 4byte, 8byte이다. 실수형 변수는 비트를 부호, 지수, 가수 부분으로 나누어 사용한다. 실수는 2의 제곱을 곱한 형태, 즉 +-M * 2^E의 형태로 저장한다. 여기서 M이 가수 부분, E가 지수 부분이다. float타입은 부호를 1비트, 지수를 8비트, 가수를 23비트로 나누어 사용한다.

 

실수형은 정수형과 달리 오차가 발생할 수 있다. 정밀도와 관련된 요소인데 float 타입의 정밀도는 7자리이다. 이는 a * 10^n의 형태로 표현된 7자리 숫자를 오차 없이 저장할 수 있다는 뜻이다. 왜 정밀도가 7이 되냐면 float는 가수 부분을 최대 2^23까지 저장할 수 있다. 2^23은 10진수로 7자리의 숫자이므로 2^23이 넘어가는 숫자를 오차 없이 저장할 수 없다. 따라서 정밀도가 7자리가 되는 것이다. 예를 들어 float타입의 1234.567은 오차 없이 저장할 수 있고 0.0001234567도 오차 없이 저장할 수 있지만 123456789.0은 저장할 때 오차가 생긴다. 이러한 이유에서 double타입은 더 큰 수를 저장하기보단, 보다 높은 정밀도를 위해서 사용한다. 정밀도를 위반한 예시를 보자.

class FloatEx1{
  public static void main(String[] args){
      float f = 9.12345678901234567890f;
      double d = 9.12345678901234567890d;

      System.out.printf("f : %24.20f\n", f);
      System.out.printf("f : %24.20f\n", d);
  }
}

 

위 예제의 결과는 어떻게 될까? 출력 결과는 해당 타입의 정밀도만큼 오차없이 출력하고 정밀도 후의 자리는 오차가 생긴다.

f : 9.1234569549560550000
d : 9.1234567890123460000

 

실수형의 저장 방식도 알아두자. 

  1. 10진수에서 2진수로 변환
  2. 2진수를 1.xxx * 2^n 형태로 변환. 이 과정을 정규화라 한다.
  3. 지수 부분 계산
  4. 부호 비트, 지수 부분, 가수 부분으로 나누어 저장

실수형 변수를 다룰 때 항상 정밀도를 염두해두자!


3. 정수형을 실수형으로 변환

다른 타입들 간의 형변환은 데이터 타입의 크기만 신경 쓰면 되지만 int -> float로 변환할 때는 정밀도를 주의해야 한다.

8자리 이상의 값을 실수형으로 변환할 때는 오차가 생길 수 있다.

 

91234567-> float로 변환 : 91234568.0 -> 다시 int로 변환 : 91234568

91234567-> doube로 변환 : 91234567.0 -> 다시 int로 변환 : 91234567

 

이처럼 정밀도를 신경 써서 double로 변환할지 float로 변환할지 판단하자.

 

실수형을 정수형으로 변환할 때는 간단하게 실수형의 소수점이하 값은 버려진다는 것만 기억하면 된다.