float 과 double은 실수를 표현하기 위해 사용하는 자료형!
float은 4byte, double은 8byte다. 실수형 데이터 타입을 다룰때 중요한것은 정밀도(precision)입니다.
정수형보다 실수형을 쓰면 훨씬 더 큰 값을 표현할수 있다. 하지만 오차가 발생할 수 있다는 단점이 있다고 합니다.
유효 자리수가 뜻하는 것은 정밀도를 뜻합니다. 즉, 몇자리까지 오차없이 표현할 수 있는가를 말입니다. float은 7자리, double은 15~16자리까지 표현할수 있다고 합니다.
따라서 float의 정밀도보다 더 높은 정밀도가 필요하다면 double을 사용해야 합니다.
위와같이 실수형 범위에서 표현할 수 없는 범위가 있는것을 볼 수 있습니다.
실수형은 "얼마나 큰 값을 표현할 수 있는가" 뿐만 아니라 "얼마나 0에 가깝게 표현할 수 있는가?" 도 중요합니다. (얼마나 정밀도 있게 표현 할 수 있는가라고도 할 수 있습니다.)
실수형의 저장방식
4byte의 정수로는 약 +-2x10^9의 값밖에 표현할 수 없는데, 어떻게 같은 4byte로 +-3.4x10^38과 같이 큰 값을 표현할수 있는걸까?
그 이유는 바로 '값을 저장하는 형식' 이 다르기 때문이라고 합니다.
int형은 32비트중 1비트 = 부호비트, 31비트는 값을 표현하는데 사용합니다.
따라서 실제로 위와 같은 형태로 저장이 됩니다. (자세히 설명하면 엄청 복잡하지만,, 일단은 이정도에서 마무리..)
- 가수(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의 차이를 알 수 있을 것입니다.