0.1+0.2는 0.3이 아니다.

정다소·2024년 12월 25일
post-thumbnail

부동 소수점 연산은 근사치를 저장한다!

위 사실을 모르고 컴퓨터를 무조건적으로 믿으면 예상치 못한 오류를 마주한다. 컴퓨터는 0.1 + 0.2 가 0.3이 아니라고 말한다. 실제로 답은 0.30000000001이 나올 수 있다.

부동 소수점 연산은 컴퓨터 메모리 한계 때문에 근사값으로 저장된다. 하지만 넓은 범위의 수를 표현할 수 있는 장점이 있다.

마트 계산기 프로그램을 만들어보자. 물품 정가에 할인율 40%를 적용하는 함수를 작성해야한다. 어떻게 작성할 것 인가?

int getDiscountFee(int fee,int percent){
	return (1- percent*0.01)*fee
}

이 코드가 정답이라고 생각하는가? 그러면 당신은 부동소수점의 오류에 뒤통수를 맞았다. 한 85점 짜리 정답이다. 그러면 어떻게 일관되게 정답을 낼 수 있을까? 부동 소수점 오류를 해결하기 위해서 기억해야할 것은 실수끼리 곱하고 나누는 것을 최소해야한다. 실수 계산과 정수 계산의 매커니즘이 다르기 때문인데, 기본적으로 정수 계산이 더 정확하다.

 return (1 - percent*0.01)*100*fee/100;

위 코드는 아까 코드에서 100을 먼저 곱하고 다시 100을 나누는 의미 없는 짓을 하는 것 같지만 반복해서 계산해도 정확한 값을 낸다. 이유는 실수인 (1 - percent*0.01)의 값을 정수화해서 연산하기 때문에 실수 계산의 오차가 줄어드는 것이다.

return (int)(1 - percent*0.01)*fee; 

그렇다면 정수 캐스팅을하는 위 코드는 어떨까? 위 코드는 0점 짜리 코드이다. 정수 캐스팅에서 주의할 것은 (int)(0.7) = 0 이라는 것이다. 정수 캐스팅은 정수로 만들어주지만 정확한 값을 보장하지는 않는다. 추가로 캐스팅이 괄호 부분에만 적용되어 결과값은 모두 0이다.

return (int)((1 - percent*0.01)*fee); 

위 코드는 캐스팅을 전체 적용했지만 가장 처음 나온 코드와 동일하게 부동소수점의 오류를 해결하진 못한다. 2.999999로 값이 나온다면 2의 값을 출력하기 때문이다. 그렇다면 다른 방법이 없을까? round 함수를 사용하는 방법이 있다.

return round((1 - percent*0.01)*fee); 

이 방법으로는 2.9999의 값을 3으로 변환하기 때문에 근사값의 정확도가 올라간다!

코딩 테스트를 풀든 실무를 진행하든 부동 소수점 연산에는 주의를 기울이고 실수 연산시 근사값이 계산되기 때문에 주의하고 해결법을 꼭 숙지하고 있으면 좋겠다.

1. 실수에 10의 제곱수를 곱해 정수로 만들어 계산하자
2. Round 함수를 사용하자

도움이 됐다면 좋아요 부탁드립니다!
내용 중 틀린게 있다면 언제든지 댓글 부탁드립니다.

profile
슬기로운 코딩 생활

0개의 댓글