ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] float과 double의 차이는 무엇일까?
    Language/Java 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의 차이를 알 수 있을 것입니다.

    반응형

    댓글

Designed by Tistory.