계산기를 출시한 후 문제가 발생했다. 부동 소수점 문제를 거듭 제곱 연산으로만 해결하려고 했지만, 반올림 오차라는 문제를 고려하지 못했던 것이다. 부동 소수점 문제를 깊게 고민하지 못한 점을 반성하며, 이번 경험을 통해 부동 소수점에 대해 확실히 알고, 버그를 수정하려고 한다. ✏️
자바스크립트 부동소수점 문제 발생
자바스크립트에서 소수점 숫자 연산을 하면, 생각지도 못한 오류가 발생한다. 아래처럼 콘솔창에 0.1 + 0.2를 입력하면, 0.3이 아니라 0.30000000000000004 가 나오는 걸 확인해볼 수 있다.


원인
왜 이런 오류가 생기는걸까? 우리는 보통 계산을 할 때 '10진법'을 사용하지만, 우리와 다르게 컴퓨터는 계산을 할 때 0과 1만 사용하는 '2진법'을 사용한다. 그래서 10진법을 2진법으로 바꾸는 변환과정이 필요한데, 소수 중 일부는 이 과정에서 무한소수가 되어버린다. 하지만 컴퓨터 메모리에는 한계가 있어서 무한 소수를 다 담지 못하고 중간에 잘라서 유한 소수로 저장해버린다. 바로 이 과정에서 미세한 오차가 발생하는 것이다.
해결방법
1. toFixed() ,Math.round() 메서드
Number((0.2 + 0.4).toFixed(1));
// 0.6
Math.round((0.2 + 0.4) * 10) / 10;
// 0.6
- Number.toFixed(n) → 소수점 n자리까지 반올림
- toFixed() 메서드는 문자열로 반환되기에 Number로 감싸서 숫자형으로 바꿔준다.
- Math.round((a + b) * 10) / 10 → 소수점 첫째 자리까지 반올림
2. 10의 거듭제곱을 곱하기
(0.2 * 10 + 0.4 * 10) / 10;
// 0.6
10의 거듭제곱을 곱해서 소수를 정수로 만들어 계산 후, 다시 나눠주는 방법이다. 소수점 연산에 문제가 있으니 정수로 만들어 계산해 주는 방법이다.
3. 기타 라이브러리
Javascript의 수학 라이브러리를 이용하면 좀 더 쉽게 계산을 할 수도 있다.
Math.round() 와 10의 거듭제곱을 활용한 함수 구현
const formatResult = (result) => {
//에러 처리
if (
result === "E" ||
result === Infinity ||
result === -Infinity ||
isNaN(result)
) {
return "E";
}
// 소수점 자릿수 제한을 설정 (5자리)
const decimalPlaces = 5;
const multiplier = Math.pow(10, decimalPlaces); //10의 5승
const roundedResult = Math.round(result * multiplier) / multiplier;
return roundedResult.toString();
};
//operation 식
const calcResult = eval("1.2 - 1");
const formattedResult = formatResult(calcResult);
Math.pow?
-
Math.pow는 2^3 = 8 과 같은 거듭 제곱을 나타낼 때 자바스크립트에서는
Math.pow(2, 3)
와 같은 객체및 메서드를 사용한다. 앞 자리 숫자는 밑, 뒷 자리 숫자는 지수를 의미한다.// 간단한 예 Math.pow(2, 3); // 8
Math.round ?
- Javascript에서 숫자를 반올림 처리할 때는 주로 Math.round() 함수를 사용한다.
Reference
https://joooing.tistory.com/entry/Javascript-소수점floating-point-계산-오류