WEB - PHP, JQuery, Bootstrap

JavaScript에서 부동소수점 연산 오류 해결 방법 (decimal.js)

초심으로 2024. 9. 23. 13:00

728x90

JavaScript에서 숫자 연산을 하다 보면 예상치 못한 결과를 얻는 경우가 자주 있습니다. 특히 소수점이 포함된 계산에서 이러한 문제가 더 자주 발생합니다. 예를 들어, 우리가 1689와 0.015를 곱한 후 반올림을 기대할 때 발생하는 부동소수점 연산 오류를 살펴보겠습니다.

1. 문제 발생: 소수점 연산 오류

다음과 같은 간단한 곱셈 연산을 해보면:

let result = 1689 * 0.015;
console.log(result);  // 예상 결과 25.335

예상한 결과는 25.335 이고, 이 값을 소수점 2자리까지 반올림한다면 25.34가 나와야 합니다.

하지만 실제 연산값은 25.334999999999997입니다. 이 숫자는 반올림 경계에 매우 가깝기 때문에 JavaScript의 기본 함수인 Math.round()toFixed()를 사용하면 원치 않는 결과가 나올 수 있습니다.

2. 기존 해결 방법: Math.round()toFixed()

1) Math.round()를 사용한 반올림

let rounded = Math.round(1689 * 0.015 * 100) / 100;
console.log(rounded);  // 25.33

Math.round()로 계산하면 결과는 25.33입니다. 우리가 기대했던 25.34와 다른 결과가 나왔습니다. 부동소수점 연산 때문에 25.334999999999997이 계산되었고, 이 값은 25.33으로 반올림됩니다.

2) toFixed()를 사용한 반올림

let fixed = (1689 * 0.015).toFixed(2);
console.log(fixed);  // "25.33"

toFixed()를 사용해도 결과는 25.33입니다. 이 역시 우리가 원하는 25.34가 아닙니다.

이처럼 부동소수점 연산 오류는 우리가 기대한 반올림 값을 출력하지 못하게 만듭니다. 특히, 반올림 경계에 있는 경우 더 심각한 오차가 발생합니다. 이로 인해 프로그램의 신뢰성이 떨어질 수 있습니다.

3. 해결책: 외부 라이브러리 사용

이런 부동소수점 문제를 근본적으로 해결하기 위해서는 외부 라이브러리를 사용하는 것이 가장 좋은 방법입니다. 다양한 실수 연산 라이브러리 중 decimal.js는 부동소수점 연산 오류를 해결하고, 소수점 연산에서 더 높은 정확도를 제공합니다.

4. decimal.js로 정확한 결과 얻기

decimal.js는 JavaScript의 기본 부동소수점 연산 방식을 벗어나 정밀한 고정 소수점 연산을 지원합니다. 이를 통해 소수점 계산에서 발생하는 모든 오차를 제거할 수 있습니다.

const Decimal = require('decimal.js');

let result = (new Decimal(1689)).times(0.015).toString();
console.log(result);  // "25.34"

이제 드디어 우리가 원하는 25.34라는 정확한 값을 얻을 수 있습니다. decimal.js는 부동소수점 오류 없이 계산을 처리해줍니다.

5. 자주 발생하는 부동소수점 문제: 0.1 + 0.2

소수점 계산에서 자주 발생하는 또 다른 문제는 0.1 + 0.2입니다. 아래 코드를 살펴보면:

let result = 0.1 + 0.2;
console.log(result);  // 0.30000000000000004

이 결과는 JavaScript에서 흔히 발생하는 부동소수점 오류입니다. 일반적으로 이 문제는 Math.round()toFixed()로 해결할 수 있지만, 반올림 경계에 가까운 값에서는 제대로 동작하지 않을 수 있습니다.

부동소수점 연산이 포함된 더 복잡한 계산에서는 이러한 방법들이 신뢰할 만한 결과를 제공하지 못할 수 있습니다. 이런 상황에서는 외부 라이브러리를 사용하는 것이 최선의 방법입니다.

6. 결론: decimal.js를 통한 정확한 실수 연산

JavaScript에서 소수점 연산을 할 때, 부동소수점 오류가 발생하여 기대한 값과 다른 결과가 나올 수 있습니다. 특히 이번 예시처럼 반올림 경계에 있는 값에서는 문제가 더 심각해질 수 있습니다. 이런 문제를 해결하기 위해 decimal.js와 같은 라이브러리를 사용하는 것이 매우 유용합니다. 이제는 꼼수 대신 정확한 계산을 위해 외부 라이브러리를 사용하는 것이 좋습니다.

 

반응형

 

decimal.js Cheat Sheet

다음은 decimal.js의 자주 사용하는 기능들을 정리한 Cheat Sheet입니다. 이를 통해 복잡한 실수 연산을 더 쉽게 처리할 수 있습니다.

기본 설정

// 라이브러리 설치
npm install decimal.js

사칙연산

//**곱셈:**
let result = (new Decimal(1689)).times(0.015); 
console.log(result.toString()); // "25.34"
//**덧셈:**
let sum = new Decimal(1689).plus(10); // 1689 + 10
//**뺄셈:**
let difference = new Decimal(1689).minus(10); // 1689 - 10
//**나눗셈:**
let quotient = new Decimal(1689).div(10); // 1689 / 10

반올림/내림/올림

//**소수점 이하 자리 반올림:**
result.toDecimalPlaces(2); // 소수점 2자리까지 반올림
//**내림:**
result.toDecimalPlaces(2, Decimal.ROUND_FLOOR);
//**올림:**
result.toDecimalPlaces(2, Decimal.ROUND_CEIL);

비교 연산

//**같은지 확인:**
new Decimal(1689).equals(new Decimal(1689)); // true
//**크거나 같은지 확인:**
new Decimal(1689).greaterThanOrEqualTo(1000); // true

형 변환

//**문자열로 변환:**
result.toString();
//**숫자로 변환:**
result.toNumber();

Cheat Sheet를 활용하면 decimal.js를 통해 복잡한 소수점 연산을 더욱 정확하게 처리할 수 있습니다.

반응형