native math operator와 mathjs의 performance 비교
자바스크립트의 기본 수학기호와 mathjs의 함수, fraction 연산의 성능을 비교해보자
Github
본 포스팅에 작성된 소스코드와 예시 데이터는 깃허브에 공개되었습니다.
mathjs란?
mathjs는 JS에서 수학 관련 기능만 전문적으로 다루는 라이브러리이다. 수학식을 파싱하며 실행하거나 분수표현, 행렬 등도 지원하고 있어서 널리 사용중이다.
사칙연산 성능 비교
제일 기본적인 주제로 "사칙연산"의 성능을 비교해보자.
import {add} from "mathjs";
console.log('========== Add ==========');
const start = new Date();
let result = 0;
for (let i = 1; i <= 10000000; i++) {
// JS 기본 문법
result += i;
}
const end = new Date();
const start2 = new Date();
let result2 = 0;
for (let i = 1; i <= 10000000; i++) {
// mathjs의 add()
result2 = add(result2, i);
}
const end2 = new Date();
console.log("Loop : ", 10000000)
console.log("Native operator + : ", end.getTime() - start.getTime(), 'ms');
console.log("mathjs add() : ", end2.getTime() - start2.getTime(), 'ms');
더하기 연산을 비교하는 소스코드다. 각각 JS 기본 + 연산과 mathjs의 add() 연산을 10000000회 반복하였다.
========== Add ==========
Loop : 10000000
Native operator + : 12 ms
mathjs add() : 96 ms
각각 12ms와 96ms라는 시간이 경과되었다. 여러번 시도해도 비슷한 결과가 나왔다.
mathjs의 add()가 약 8~9배 정도 느린것인데 그래도 천만번 연산한 것에 비하면 나쁘진 않은 것 같다.
비슷한 소스코드로 빼기, 곱하기, 나누기 연산도 비교해보았다.
========== Subtract ==========
Loop : 10000000
Native operator - : 11 ms
mathjs subtract() : 87 ms
========== Multiply ==========
Loop : 10000000
Native operator * : 10 ms
mathjs multiply() : 68 ms
========== Divide ==========
Loop : 10000000
Native operator / : 39 ms
mathjs divide() : 99 ms
빼기 연산은 더하기 연산과 비슷한 약 8~9배 차이가 났고, 곱하기 연산은 약 7배, 나누기 연산은 약 2.5배 차이가 났다.
오차보정 Fraction 사칙연산 비교
mathjs를 사용하는 핵심 이유는 분수표현인 fraction 기능을 사용하면 부동소수점 정확도 문제를 일부 해결할 수 있어서이기도 하다.
JS에서 0.1 + 0.2는 0.30000000000000004라는 결과를 반환하지만, mathjs에서 add(fraction(0.1), fraction(0.2))는 무려 0.3이라는 제대로 된 결과를 반환한다!
핵심 기능인 만큼 이 또한 성능 비교를 진행했다.
import {add, fraction} from "mathjs";
console.log('========== Add ==========');
const start = new Date();
let result = 0;
for (let i = 1; i <= 10000000; i++) {
// JS 기본 문법
result += i;
}
const end = new Date();
const start2 = new Date();
let result2 = 0;
for (let i = 1; i <= 10000000; i++) {
// mathjs의 add()
result2 = add(result2, i);
}
const end2 = new Date();
const start3 = new Date();
let result3 = fraction(1);
for (let i = 1; i <= 10000000; i++) {
// mathjs의 분수표현 add()
result3 = add(result3, fraction(i));
}
const end3 = new Date();
console.log("Loop : ", 10000000)
console.log("Native operator + : ", end.getTime() - start.getTime(), 'ms');
console.log("mathjs add() : ", end2.getTime() - start2.getTime(), 'ms');
console.log("mathjs fraction add() : ", end3.getTime() - start3.getTime(), 'ms');
변수를 fraction으로 랩핑 후 연산하는 과정을 추가해보았다.
========== Add ==========
Loop : 10000000
Native operator + : 11 ms
mathjs add() : 87 ms
mathjs fraction add() : 1648 ms
========== Subtract ==========
Loop : 10000000
Native operator - : 12 ms
mathjs subtract() : 98 ms
mathjs fraction subtract() : 1523 ms
========== Multiply ==========
Loop : 10000000
Native operator * : 11 ms
mathjs multiply() : 69 ms
mathjs fraction multiply() : 2429 ms
========== Divide ==========
Loop : 10000000
Native operator / : 39 ms
mathjs divide() : 96 ms
mathjs fraction divide() : 1697 ms
연산에 fraction을 적용했을 때 성능 저하가 크게 차이나는 현상을 확인했다. 더하기와 빼기 연산은 약 125~150배 정도 차이를 보였고, 곱하기 약 220배, 나누기는 약 43배 차이가 났다.
아무래도 fraction을 이용한 연산은 오버헤드가 좀 더 큰 모양이다.
(추가로, 별도 연산 없이 fraction 객체 생성만 10000000회 반복하는데 약 300ms가 소요됐다.)
비교 결과
각 케이스마다 연산에 걸린 경과시간을 시각화 해보았다. fraction을 적용했을 때의 결과가 압도적으로 차이나는 것을 볼 수 있다.
관련 문서
'Programming > Javascript' 카테고리의 다른 글
[Javascript] V8 Engine이 string과 number 값을 다루는 방법 (0) | 2024.06.28 |
---|---|
[Javascript] Javascript 라이브러리 패키지를 Github Actions를 이용하여 npm에 배포하는 방법 (0) | 2023.12.08 |
[Javascript] 세미콜론 자동 삽입과 중괄호 위치 버그 (0) | 2019.11.10 |
[Javascript] 문자열 replace와 replaceAll (0) | 2019.10.20 |
댓글