숫자를 비교할 때는 염두에 두어야 할 것이 있습니다.
먼저, 특별한 숫자형 값 NaN은 그 자신을 포함하여 무엇과도 같지 않습니다.
즉, NaN === NaN
과 NaN == NaN
은 모두 false입니다.
숫자가 NaN인지 알아보려면 내장된 isNaN 함수를 사용하십시오.
isNaN(x) 은 x가 NaN일 때 true를 반환하고 그렇지 않다면 false를 반환합니다.
자주 얘기하지만, 자바스크립트의 숫자는 모두 더블 형식입니다.
그리고 더블 형식은 근사치이므로, 자바스크립트에서 숫자를 비교하다 보면 경악스러운 결과를 볼 때가 있습니다.
자바스크립트에서 정수를 비교할 때, 그 정수가 안전한 범위라면(Number.MIN_SAFE_INTEGER 이상, Number.MAX_SAFE_INTEGER 이하) 안심하고 일치 연산자를 사용할 수 있습니다.
하지만 소수점이 있는 숫자를 비교할 때는 관계 연산자를 써서 테스트하는 숫자가 대상 숫자에 ‘충분히 가까운지’ 확인하는 편이 좋습니다.
충분히 가깝다는 게 무슨 말이냐고요?
때에 따라 다릅니다.
자바스크립트에는 특별히 숫자형 상수 Number.EPSILOW이 있습니다.
이것은 매우 작은 값(약 2.22e-16)이며, 일반적으로 숫자 두 개를 구별하는 기준으로 사용합니다.
다음 예제를 보십시오.
let n = 0;
while(true) {
n += 0.1;
if (n === 0.3) break;
}
console.log(`Stopped at ${n}`);
이 코드를 실행하면 예상 외의 결과에 놀랄 겁니다.
이 루프는 0.3에서 멈추지 않고 그 값을 살짝 피한 다음 영원히 실행됩니다.
이 결과는 0.1이 더블 형식으로 저확히 나타낼 수 없는 값이기 때문입니다.
0.1은 이진 표현으로나타낼 수 있는 숫자들 사이에 걸쳐 있습니다.
따라서 이 루프를 세 번째 반복할 때 n의 값은 0.30000000000000004이므로 테스트는 false이고, 유일한 종료 조건이 실패하게 됩니다.
Number.EPSILON과 관계 연산자를 사용해서 ‘느슨하게’ 비교하고 성공적으로 루프를 빠져나갈 수 있습니다.
let n = 0;
while(true) {
n += 0.1;
if (Math.abs(n - 0.3) < Number.EPSILON) break;
}
console.log(`Stopped at ${n}`);
테스트하는 숫자(n)에서 비교 대상(0.3)을 뺀 다음 절댓값을 취하는 방식을 썼습니다(Math.abs는 16장에서 설명합니다).
그냥 n이 0.3보다 큰지 확인하는 간단한 방법도 있지만, 여기서 사용한 방법은 두 개의 더블 형식이 같다고 할 수 있을 만큼 가까운 숫자인지 판단할 때 일반적으로 사용하는 방법입니다.