JavaScript 입문 | 표준 객체 | Number 객체


자바스크립트에서의 수 표현

자바스크립트에서는 정수와 실수를 따로 구분하지 않고, 모든 수를 실수 하나로만 표현한다.
자바스크립트에서 모든 숫자는 IEEE 754 국제 표준에서 정의한 64비트 부동 소수점 수로 저장된다.

64비트 부동 소수점 수(double precision floating point numbers)는 메모리에 다음과 같은 형태로 저장된다.

0 ~ 51 비트 52 ~ 62 비트 63 비트
총 52비트의 가수 부분 총 11비트의 지수 부분 총 1비트의 부호 부분

이러한 64비트 부동 소수점 수의 정밀도는 정수부는 15자리까지, 소수부는 17자리까지만 유효한다.

다음 예제는 64비트 부동 소수점 수의 정밀도를 알아보는 예제이다.

var x = 999999999999999;  // 15자리의 정수부
var y = 9999999999999999; // 16자리의 정수부
var z = 0.1 + 0.2
x; // 999999999999999
y; // 10000000000000000
z; // 0.30000000000000004

위의 예제에서 변수 z의 값을 살펴보면 오차가 발생했음을 알 수 있다.
이렇게 부동 소수점 수를 가지고 수행하는 산술 연산의 결과 값은 언제나 오차가 발생할 가능성을 가지고 있다.
이것은 자바스크립트만의 문제가 아닌 부동 소수점 수를 가지고 실수를 표현하는 모든 프로그래밍 언어에서의 문제점이다.

자바스크립트에서는 이러한 오차를 없애기 위해 정수의 형태로 먼저 변환하여 계산을 수행하고, 다시 실수의 형태로 재변환하는 방법을 사용할 수도 있다.

var z = (0.2 * 10 + 0.1 * 10) / 10; // 0.3

진법 표현

자바스크립트에서는 기본적으로 10진법을 사용하여 수를 표현한다.
하지만 0x 접두사를 사용하여 16진법으로 수를 표현할 수도 있다.

var x = 0xAB; // 16진법으로 표현된 10진수 171
var y = 29;   // 10진법으로 표현된 10진수 29
x + y;        // 두 수 모두 10진법으로 자동으로 변환되어 계산됨. -> 200

위의 예제처럼 자바스크립트에서는 산술 연산 시 모든 수가 10진수로 자동 변환되어 계산된다.

또한, 숫자에 toString() 메소드를 사용하여 해당 숫자를 여러 진법의 형태로 변환할 수 있다.

var num = 256;
num.toString(2);       //  2진법으로 변환 : 100000000
num.toString(8);       //  8진법으로 변환 : 400
num.toString(10);      // 10진법으로 변환 : 256
num.toString(16);      // 16진법으로 변환 : 100
// 2진수로 변환한 결과 값을 문자열로 반환함.
num.toString(2);       // 100000000
// 문자열을 숫자로 나눴기 때문에 자동으로 10진수로 변환되어 산술 연산된 결과 값
(num.toString(2) / 2); // 50000000

toString() 메소드는 해당 숫자의 진법을 실제로 바꿔주는 것이 아닌, 전달된 진법으로 변환된 형태의 문자열을 반환해 주는 것이다.

Infinity

자바스크립트에서는 양의 무한대를 의미하는 Infinity 값과 음의 무한대를 의미하는 -Infinity 값을 사용할 수 있다.
Infinity 값은 사용자가 임의로 수정할 수 없는 읽기 전용 값이며, 자바스크립트의 어떤 수보다도 큰 수로 취급된다.

var x = 10 / 0;         // 숫자를 0으로 나누면 Infinity를 반환함.
var y = Infinity * 1000 // Infinity에 어떠한 수를 산술 연산해도 Infinity를 반환함.
var z = 1 / Infinity    // Infinity의 역수는 0을 반환함.
x;                      // Infinity
y;                      // Infinity
z;                      // 0

NaN

NaN(Not A Number)는 숫자가 아니라는 의미로, 정의되지 않은 값이나 표현할 수 없는 값을 가리킨다.
0을 0으로 나누거나, 숫자로 변환할 수 없는 피연산자로 산술 연산을 시도하는 경우에 반환되는 읽기 전용 값이다.

var x = 100 - "10";     // "10"은 자동으로 숫자로 변환되어 계산됨.
var y = 100 - "문자열"; // "문자열"은 숫자로 변환할 수 없기 때문에 NaN을 반환함.
var z = 0 / 0;          // 0을 0으로 나눌 수 없기 때문에 NaN을 반환함.
x;                      // 90
y;                      // NaN
z;                      // NaN

자바스크립트의 전역 함수 중 하나인 isNaN() 함수를 사용하면, 전달받은 값이 숫자인지 아닌지를 판단해 준다.

var x = 100 * "문자열";
if(isNaN(x)) { // 전달된 값이 숫자인지 아닌지를 검사함.
    document.write("변수 x의 값은 숫자가 아니다.");
} else {
    document.write("변수 x의 값은 숫자이다.");
}

null, undefined, NaN, Infinity에 대한 비교

자바스크립트에서는 약간은 비슷한 것 같으면서도 전혀 다른 4가지 값을 제공하고 있다.

  • null은 object 타입이며, 아직 ‘값’이 정해지지 않은 것을 의미하는 값이다.
  • undefined는 null과는 달리 하나의 타입이며, ‘타입’이 정해지지 않은 것을 의미하는 값이기도 한다.
  • NaN은 number 타입이며, ‘숫자가 아님’을 의미하는 숫자이다.
  • Infinity는 number 타입이며, ‘무한대’를 의미하는 숫자이다.

자바스크립트는 타입 검사가 매우 유연한 언어이다.
따라서 위의 값들 또한 문맥에 따라 다음과 같이 자동으로 타입 변환이 이루어진다.

Boolean 문맥 Number 문맥 String 문맥
null false 0 “null”
undefined false NaN “undefined”
NaN false NaN “NaN”
Infinity true Infinity “Infinity”
typeof null;        // object
typeof undefined;   // undefined
typeof NaN;         // number
typeof Infinity;    // number
 
Boolean(null);      // false
Boolean(undefined); // false
Boolean(NaN);       // false
Boolean(Infinity);  // true
 
Number(null);       // 0
Number(undefined);  // NaN
Number(NaN);        // NaN
Number(Infinity);   // Infinity
 
String(null);       // null
String(undefined);  // undefined
String(NaN);        // NaN
String(Infinity);   // Infinity

Number 객체

자바스크립트에서 숫자는 보통 숫자 리터럴을 사용하여 표현한다.

하지만 수를 나타낼 때 new 연산자를 사용하여 명시적으로 Number 객체를 생성할 수도 있다.
이러한 Number 객체는 숫자 값을 감싸고 있는 래퍼(wrapper) 객체이다.

var x = 100;             // 숫자 리터럴
var y = new Number(100); // Number 객체
x;                       // 100
y;                       // 100
typeof x;                // number 타입
typeof y;                // object 타입

동등 연산자(==)는 리터럴 값과 객체의 값이 같으면 true를 반환한다.
하지만 일치 연산자(===)는 숫자 리터럴과 Number 객체의 타입이 다르므로, 언제나 false를 반환한다.

var x = 100;             // 숫자 리터럴 100
var y = new Number(100); // Number 객체 100
x == y;                  // 값이 같으므로 true
x === y;                 // 서로 다른 객체이므로 false

new 연산자를 사용하여 객체를 생성할 때에는 매우 많은 추가 연산을 해야만 한다.
따라서 가능한 숫자 리터럴을 사용하여 수를 표현하고, Number 객체는 래퍼 객체로만 활용하는 것이 좋다.