왜 이런 문제가 발생할까?
실수 표현 방법
- 고정 소수점 방식 (Fixed Point)
실수는 보통 정수부와 소수부로 나누어 표기한다.
따라서 실수를 표현하는 가장 간단한 방식은 소수부의 자릿수를 미리 정하여, 고정된 자릿수의 소수를 표현하는 것이다.
장점 : 단순하다.
단점 : 표현 범위가 적다.
- 부동 소수점 방식(Floating Point)
하나의 실수를 가수부와 지수부로 나누어 표현하는 방식이다. (不動이 아니라 浮動이다)
지수부 : 크기를 표현함. 가수의 어디쯤에 소수점이 있는지 나타냄
가수부 : 실수의 실제값 표현
지수의 값에 따라 소수점이 움직이는 방식을 활용한 실수 표현 방법이다.
장점 : 범위가 넓다(현재 대부분 시스템에서 사용 중)
단점 : 오차 발생 가능성
부동소수점의 오차
1보다 작은 수의 경우에는 십진법으로 간단히 표현되는 수도 이진법에서는 무한개의 유효숫자를 가질 수 있다. 예를 들어 0.1이라는 숫자는 십진수로는 간단히 표현되지만 이진수로 나타내면 다음과 같이 0011(2)이 무한히 반복되는 실수가 된다. 가수부를 이진법 소수점으로 표현하기 때문에 정확한 값을 저장할 수 없다. (0.5, 0.25, 0.125,... 로만 표현 가능)
0.1=0.00011001100110011001100110011001100110011001100110011001100110011⋯
그런데 컴퓨터에서는 하나의 숫자를 나타내기 위한 메모리 크기가 제한되어 있어서 특정 소수점 이하는 생략하고 가장 비슷한 숫자로 표현할 수 밖에 없다. 0.1은 실제로는 가장 비슷한 다음과 같은 숫자로 저장된다.
0.1≈0.1000000000000000055511151231257827021181583404541015625
(그런데 파이썬 콘솔이나 주피터 노트북에서 0.1을 입력하면 다음과 같이 그냥 0.1로 나타난다.)
그래서 돈 같은 예민한 값들은 실수형으로 저장하지 않는다. 달러와 센트 같이 소수점 이하는 따로 정수형 데이터로 저장해야 문제가 발생하지 않는다!
나는 알고리즘 풀 때 실수형 관련해서 문제도 있었다.
2023.04.30 - [TIL] - [C++] pow함수 double 형의 정확성 문제
자바에서 해결법
JAVA에서는 BigDecimal이라는 클래스가 존재한다. BigDecimal클래스의 메소드를 이용하여 사칙연산을 하게 되면 부동소수점이 발생하지 않는다.
BigDeciaml 객체 생성 시 String으로 형 변환하여 생성해야 한다는 것을 주의하자.
BigDecimal val1 = new BigDecimal("1.1");
BigDecimal val2 = new BigDecimal("0.1");
//더하기
System.out.println(val1.add(val2)); //1.2
//빼기
System.out.println(val1.subtract(val2)); //1.0
//곱하기
System.out.println(val1.multiply(val2)); //0.11
//나누기
System.out.println(val1.divide(val2)); //11
double beforeSum = 0;
BigDecimal afterSum = new BigDecimal("0");
for(int cnt = 0 ; cnt < 100 ; cnt++) {
beforeSum += 0.1;
afterSum = afterSum.add(new BigDecimal("0.1"));
}
System.out.println("beforeSum : " + beforeSum); //beforeSum : 9.99999999999998
System.out.println("afterSum : " + afterSum); //afterSum : 10.0
'Develop > etc' 카테고리의 다른 글
Adapter Pattern은 무엇인가 (0) | 2023.09.13 |
---|---|
Nginx 넌 도대체 뭐니 (0) | 2023.09.12 |
[C++] 람다식 (feat. 2887 행성 터널) (0) | 2023.05.20 |
RabbitMQ의 메시지 전달 방식 (Direct, Fanout, Topic, Headers Exchange) (0) | 2023.04.19 |
R Socket이란 무엇일까? (0) | 2023.03.20 |