Language/Java

[Java] float과 double의 차이는 무엇일까?

백엔드 규니 2021. 1. 25. 17:43
728x90
반응형

float vs double의 차이는?

float과 double 모두 실수를 표현하기 위해 사용하는 자료형이라는 것은 알고 있을 것 입니다. 하지만 정확한 차이가 무엇이냐고 물어본다면 대답하기가 쉽지 않습니다...(애매하게 float은 4byte, double은 8byte다 이정도..)

 

type

 

위에서 볼 수 있듯이 float은 4Byte, double은 8byte 입니다. 실수형 데이터 타입을 다룰 때 중요한 것은 정밀도(precision)입니다.

정수형보다 실수형을 쓰면 훨씬 더 큰 값을 표현할 수 있지만, 오차가 발생할 수 있다는 단점이 있습니다.

 

float-double

 

유효자릿수가 뜻하는 것은 정밀도를 뜻합니다. 즉, 몇자리 까지 오차없이 표현할 수 있는가입니다. float은 7자리, double은 15~16자리 까지 표현할 수 있습니다.

 

따라서 float의 정밀도보다 더 높은 정밀도가 필요하다면 double을 사용해야 합니다.

 

스크린샷 2021-01-10 오후 6 43 00

 

위의 그림을 보시면 실수형 범위에서 표현할 수 없는 범위가 있는 것을 볼 수 있습니다. 실수형은 얼마나 큰 값을 표현할 수 있는가 뿐만 아니라 얼마나 0에 가깝게 표현할 수 있는가도 중요합니다.(얼마나 정밀도 있게 표현할 수 있는가라고도 할 수 있습니다.)

 

 

실수형의 저장 방식

4 byte의 정수로는 약 +-2x10^9의 값밖에 표현할 수 없는데, 어떻게 같은 4 byte로 +-3.4x10^38과 같이 큰 값을 표현할 수 있는 걸까요?
그 이유는 바로 값을 저장하는 형식이 다르기 때문입니다.

 

int형은 32비트 중 1비트=부호비트, 31비트는 값을 표현하는데 사용합니다.

 

스크린샷 2021-01-10 오후 6 44 41

 

floatdouble은 위와 같이 부호(S),지수(E), 가수(M)로 나눠서 표현하게 됩니다.

 

단일-정밀도(single-precision number) 형식: 32비트로 표현된 부동소수점 수 (float)

복수-정밀도(double-precision number) 형식: 64비트로 표현된 부동소수점 수 (double)

 

즉, +-M x 2^E 형태로 저장하기 때문에 이렇게 큰 범위의 값을 저장하는 것이 가능한 것입니다.

예시를 들어서 어떻게 표현하는지 한번 알아보겠습니다.

 

274,000,000,000,0002.74 x 10^14으로, 0.000000000002742.74 x 10^-12로 표현할 수 있습니다.
여기서 소수점의 위치를 지수(exponent)로 표현할 수 있습니다. 예시의 경우는 14와 -12가 지수입니다.

이와 같이 소수점의 위치를 필요에 따라 이동시키는 표현 방법을 부동소수점 표현(floating-point representation)이라고 하며, 그와 같이 표현된 수를 부동소수점 수(floationg-point number)라고 부릅니다.

 

그래서 다시 2.74 x 10^14의 경우에는 가수(M) = 2.74, 지수(E) = 14, 부호는 양수면 1, 음수면 0 입니다.
(다만, 디지털 컴퓨터에서는 2진수 체계가 사용되기 때문에 2진 부동소수점 수로 사용되고 지수(E)의 밑이 10이 아니라 2로 바뀌게 됩니다.)

  • 가수(Mantissa): 실제 값을 저장하는 부분
  • 지수(Exponent): 부호있는 정수
  • 부호(Sign bit): 0이면 양수, 1이면 음수


0.1101 x 2^5

11.01 x 2^3

0.001101 x 2^7

위와 같이 통일되지 않아 혼란이 일어나기 때문에 아래와 같이 정규화된 표현이 있습니다.

소수점의 바로 오른 편에 있는 비트가 반드시 '1'이 되도록 위치를 조정하는 것을 말합니다.

1.101 x 2^4

0.1101 x 2^9

위와 같이 변경할 수 있습니다.

 

 

스크린샷 2021-01-10 오후 6 59 02

 

따라서 실제로 위와 같은 형태로 저장이 됩니다. (자세히 설명하면 엄청 복잡하지만,, 일단은 이정도에서 마무리..)

  • 가수(M) = 1.101101 이기 때문에 가수를 저장할 수 있는 비트가 많은 수록 정밀도는 높아질 것입니다.
  • 지수(E) = 지수는 3이기 때문에 지수를 지정할 수 있는 비트가 많을 수록 값을 표현할 수 있는 범위가 커질 것입니다.

따라서 가수, 지수를 적절하게 분배해야 정밀도, 값의 크기를 효율적으로 표현할 수 있습니다.

 

 

부동 소수점 오차

실수 중에는 파이(3.141592...)와 같이 무한소수가 존재하므로, 정수와 달리 실수를 저장할 때는 오차가 발생할 수 있습니다.

게다가 10진수가 아닌 2진수로 저장하기 때문에 10진수로는 유한소수이더라도, 2진수로 변환하면 무한소수가 되는 경우도 있습니다.

10진수: 9.1234567 
2진수: 1001.000111111001101011011011...
정규화: 1.001000111111001101011011011...

위와 같이 10진수일 때 유한소수인 것을 2진수로 바꾸면 무한소수가 됩니다. 이제 위에서 실수형의 저장하는 형식을 보았던 것을 대입해보겠습니다.

  • float 자료형을 사용 = 32비트 (부호(1비트), 지수(8비트), 가수(23비트))
  • 여기서 1.001000111111001101011011011... 이러한 무한소수를 모두 저장할 수 없기 때문에 이 중에서 23비트만을 저장합니다.
  • 이렇게 짤리는 부분 때문에 오차가 생기게 됩니다. (코드로 확인을 해보겠습니다.)
public class Test {
    public static void main(String[] args) {
        float f = 9.1234567f;
        System.out.println(f); // 9.123457
    }
}

위의 결과를 보면 알 수 있듯이 마지막 7이 짤리고 6은 반올림 된 것을 확인할 수 있습니다. 이제 다시 어느정도 float, double의 차이를 알 수 있을 것입니다.

반응형