[JavaScript] Number Precision (소수 연산, 계산 정밀도)
[JavaScript] Number Precision (소수 연산, 계산 정밀도)
소수 연산(Floating point arithmetic)은 때때로 정확하지 않다. 123var x = 0.2 + 0.1; alert(x); // alert 0.30000000000000004cs 위 문제를 해결하기 위해 정수형 연산으로 바꿔 계산한다. 123var x = (0.2 * 10 + 0.1 * 10) / 10; a
stroot.tistory.com
해결방안은?
1. toFixed() 메서드
이런 소수점 계산 오류를 해결하기 위한 방법들 중 첫 번째 방법은 toFixed(n) 메서드를 사용해 어림수를 만드는 것이다.
let a = 0.1;
let b = 0.2;
console.log((a + b).toFixed(1)); // '0.3'
toFixed 메서드는 파라미터로 0부터 20까지 숫자를 넘길 수 있는데 해당 값이 소수점 이후의 자릿수를 결정한다.
하지만 반환되는 값이 문자열이기 때문에 만일 숫자로 사용하고 싶다면 앞에 단항 연산자로 덧셈 연산자를 붙여주어야 한다.
let a = 0.1;
let b = 0.2;
console.log(+(a + b).toFixed(1)); // 0.3
2. Math 객체의 메서드 활용
Math 객체의 메서드를 이용하는 것도 하나의 방법이라고 할 수 있다. Math 객체에는 Math.floor, Math.ceil, Math.trunc, Math.round 같은 소수를 다루는 메서드들이 있는데 이를 통해 연산하고자 하는 의도에 따라 계산을 하는 방법도 있다.
let a = 0.1;
let b = 0.2;
console.log(Math.round((a + b) * 10) / 10); // 0.3
3. 라이브러리 활용
좀 더 편리한 방법은 자바스크립트용 수학 라이브러리를 사용하는 것이다.
Big.js, BigNumber.js, Decimal.js mathjs 등 라이브러리를 활용하면 좀 더 안전하게 수학계산을 할 수 있기도 하다만 개인적으로 이런 라이브러리를 활용하는 게 불편할 수 도 있으니.. 각자의 취향에 맡기는 것이 좋다.
(참고) 마냥 소수점에서만 계산 오류가 일어나지 않는다!?
console.log(9999999999999999); // 10000000000000000
위 코드를 보자. 분명히 9999999999999999를 출력했는데 10000000000000000이 출력되었다.
멍청한 자바스크립트.
(?)
아무튼, 계산 오류는 소수에서만 일어나는 것도 아니고, 언어를 개발하는 누군가의 실수에 의한 것도 아니다.
https://velog.io/@harimad/0.10.2-0.3-in-JS
자바스크립트에서 0.1+0.2는 왜 0.3이 아닐까?
자바스크립트에서 0.1 + 0.2 를 하면 0.3이 나올것 같지만, 0.30000000000000004이 나옵니다.왜 이런 문제가 발생하는 것일까요🤔?이번 시간에는 부동소수점을 구하는 방법을 알아보고0.1 + 0.2가 0.3이 나
velog.io
JavaScript에서 소수점 계산을 하다보면 아래와 같이 당혹스러운 경우가 종종 발생한다.

??? 숫자가 증식을 한다?!

아래처럼 더하면 더할 수록 소수점이 계속 변화하는것도 볼 수 있다.
순서 | 값 | 예상값 | 실제값 |
1 | 0.15 | 0.15 | 0.15 |
2 | 0.13 | 0.28 | 0.28 |
3 | 0.2 | 0.48 | 0.48000000000000004 |
4 | 0.14 | 0.62 | 0.6200000000000001 |
5 | 0.16 | 0.78 | 0.7800000000000001 |
6 | 0.08 | 0.86 | 0.8600000000000001 |
7 | 0.07 | 0.93 | 0.9300000000000002 |
8 | 0.07 | 1 | 1.0000000000000002 |
* 지금 바로 F12를 눌러서 콘솔창에 쳐보자. 계속적으로 숫자가 변화한다.

브라우저 디버그 모드에서 계산된 실제 결과

내가 입력도 하지 않은 소수점 10자리도 밑에 저 잉여값은 도대체 어디서 온걸까?
1. 컴퓨터는 10진수를 2진수로 계산한다.
2. 소수중의 일부는 10진수를 2진수로 변환시에 무한소수가 된다.
3. 무한소수를 유한한 범위(메모리의 한계) 내에서 표현하게되면 근사값으로 표시 할 수 밖에 없다.
4. 근사값으로 표시되므로 미세하게 증감이 발생한다.
5. 계산오류로 나타난다.
한마디로 정리하자면 10진수를 2진수로 변환해서 계산하는 과정에서 메모리의 한계 때문에 근사값을 사용하고
그로 인해 계산 오류가 발생하게 된다.
해결방안은?
1. toFixed() 메서드 사용
- toFixed( 자리수 ) : 자리수는 0~20 까지 가능 , 입력한 자리수에 맞춰 반올림
- ex ) toFixed(1) : 소수점 첫째자리 까지 표기
var a = 0.1;
var b = 0.2;
a+b;
// 0.30000000000000004
// toFixed 메서드 사용 ( 파라메터는 0~20 까지 가능 )
// ex1) toFixed(1) : 소수점 첫째 짜리까지 ( 소수점 두째자리에서 반올림)
(a+b).toFixed(1)); // '0.3'
// ex1) toFixed(0) : 소수점 첫째자리에서 반올림
(a+b).toFixed(0)); // '0'

문제발생!!
toFixed 메서드 사용시 리턴 결과는 문자열
리턴결과가 문자열임을 고려하지 않고 이런 코딩을 한다면...
var a = [0.1,0.2,0.3];
var sum = 0;
for(var i=0; i < a.length ; i++ ){
sum += a[i].toFixed(1);
}
// '00.10.20.3'
for(var i=0; i < a.length ; i++ ){
sum += a[i].toFixed(1);
}
//Uncaught TypeError: (sum + a[i]).toFixed is not a function at <anonymous>:5:21


이상한 문자열이나 타입에러를 만나게 된다.
그렇다면 숫자형태로 쓰고 싶다면 어떻게 해야 할까?

1.1 toFixed() 메서드 사용( 단항연산자를 같이 넣어주자 )
var a = [0.1,0.2,0.3];
var sum = 0;
for(var i=0; i < a.length ; i++ ){
sum = +(((sum + a[i])).toFixed(1));
}
// 0.6
최종 결과 값에 단항연산자 +를 넣어주면 다시 숫자로 변환되어 원하는 숫자를 얻을 수 있다.

드디어 원하는 값! 이게 이렇게 어려울 일인가?

이 이외에도 다양한 방식으로 원하는 결과를 도출 할 수 도 있다.
2. 소수점n자리 X 10^n / 10^n
가장 간단한 해결책이 아닐까?

var a = [0.1,0.2,0.3];
var sum = 0;
for(var i=0; i < a.length ; i++ ){
sum += (a[i]*10);
}
sum = sum/10;
// 0.6
소수점 최대 길이만 안다면, 자리수만큼 곱해 정수로 계산했다가 마지막에 다시 자리수만큼 나누면 깔끔 & Easy
3. Math 객체 사용
- 정수형으로 반환
1. 올림 : Math.ceil()
2. 내림 : Math.floor()
3. 반올림 : Math.round()
4. 버림 : Math.trunc()
정수형으로 반환하므로 결과값에 2. 와 같이 자리수에 대한 보정이 필요하다.

참고
4. 라이브러리 활용
자바스크립트에는 다양한 라이브러리가 존재한다. 그 중에서 수학적 계산관련한 라이브러리를 활용하는 방법이 있다.
하지만 단순히 소수점 계산을 하는데 있어서 라이브러리를 가져다 쓰는것이 오히려 불편하고 번거로울 수 있다.

1. Big.js - Download / Site
2. BigNumber.js - Download / Site
3. Decimal.js - Download / Site
4. math.js - Download / Site
5. 기타 등등
문제를 해결하는 방법은 다양하게 있으니, 사용 하기에 편리한 방법으로 해결 하면 되겠다.
제일 단순한 방법이 가장 쉽고 빠른 해결책일 때도 있다.
https://gongnamnam.tistory.com/47
[JavaScript] 소수점 계산 오류 및 처리방법
JavaScript에서 소수점 계산을 하다보면 아래와 같이 당혹스러운 경우가 종종 발생한다. 아래처럼 더하면 더할 수록 소수점이 계속 변화하는것도 볼 수 있다. 순서 값 예상값 실제값 1 0.15 0.15 0.15 2
gongnamnam.tistory.com
'coding > js' 카테고리의 다른 글
자바스크립트 for loop 속도 비교 (0) | 2023.02.07 |
---|---|
JavaScript에서 9999999999999999가 10000000000000000으로 변환되는 이유는 무엇입니까? (정밀도 오류, 64비트 부동소수점) (0) | 2023.02.06 |
video.js 설명을 잘 한 블로그 링크 (0) | 2023.02.03 |
[jQuery] $(document).ready() 와 $(window).on("load") (0) | 2023.02.03 |
[javascript] new 키워드에 대하여 (0) | 2023.02.03 |