WeniVooks

검색

JavaScript 에센셜

숫자형과 BigInt

1. 숫자 (Number)

숫자는 정수와 실수를 표현하기 위해 사용되는 자료형입니다.

let num1 = 2;
let num2 = -3.2;
let num1 = 2;
let num2 = -3.2;
1.1. 숫자형의 특징
1.1.1. 산술 연산

숫자는 다양한 산술 연산을 할 수 있습니다. 아래 예제를 실행해 보고 다양하게 숫자를 변경(양수, 음수, 0, 소수)하여 결과를 확인해 보세요. 앞서 배운 템플릿 리터럴을 사용하여 결과를 출력합니다.

// 산술 연산 console.log(`10 + 3 = ${10 + 3}`); console.log(`10 - 3 = ${10 - 3}`); console.log(`10 / 3 = ${10 / 3}`); console.log(`10 * 3 = ${10 * 3}`); console.log(`10 ** 3 = ${10 ** 3}`); // 10의 3승 console.log(`10 % 3 = ${10 % 3}`); // 나머지
1.1.2. 단항 연산

단항 연산자는 하나의 피연산자에 대해 연산을 수행합니다.

console.log(-2); // -2 (음수로 변환) console.log(-(-2)); // 2 (양수로 변환) console.log(+4); // 4 (양수로 유지) console.log(+'4'); // 4 (문자열 '4'를 숫자 4로 변환)

숫자형으로 변환
단항 연산을 사용하여 문자열을 숫자로 변환할 수 있습니다. 하지만 이 방법은 권장하지 않습니다. 대신 parseInt() 또는 parseFloat()를 사용하세요.

1.1.3. 증감 연산자

증감 연산자는 변수의 값을 1씩 증가 또는 감소시킵니다.

let num = 3; console.log(`증감연산 : ${++num}`); // 4 (num을 먼저 증가시키고 출력) console.log(`증감연산 : ${num++}`); // 4 (출력 후 num을 증가시킴, 결과적으로 num은 5) console.log(`증감연산 : ${--num}`); // 4 (num을 먼저 감소시키고 출력) console.log(`증감연산 : ${num--}`); // 4 (출력 후 num을 감소시킴, 결과적으로 num은 3)
1.1.4. 비교 연산

비교 연산자는 두 값을 비교하여 참(true) 또는 거짓(false) 값을 반환합니다. 이러한 참, 거짓을 불리언(boolean) 값이라고 합니다.

console.log(`비교연산 : ${2 > 3}`); // false (2는 3보다 크지 않음) console.log(`비교연산 : ${2 >= 3}`); // false (2는 3보다 크거나 같지 않음) console.log(`비교연산 : ${2 < 3}`); // true (2는 3보다 작음) console.log(`비교연산 : ${2 <= 3}`); // true (2는 3보다 작거나 같음)

비교 연산자는 값이 같은지, 다른지를 비교할 때도 사용합니다. =====은 차이가 있습니다. ==는 값만 비교하고, ===는 값과 타입까지 비교합니다. 따라서 ===를 사용하는 것이 더 안전합니다.

console.log(`비교연산 : ${2 == 3}`); // false (2는 3과 같지 않음) console.log(`비교연산 : ${2 == '2'}`); // true (2는 '2'와 같음) console.log(`비교연산 : ${2 != 3}`); // true (2는 3과 같지 않음) console.log(`비교연산 : ${2 === 3}`); // false (2는 3과 정확히 같지 않음, 타입까지 비교) console.log(`비교연산 : ${2 !== 3}`); // true (2는 3과 정확히 같지 않음, 타입까지 비교) console.log(`비교연산 : ${2 === '2'}`); // true (2는 '2'과 정확히 같지 않음, 타입까지 비교)
1.1.5 숫자 표기법

숫자를 표현할 때 정수, 소수뿐만 아니라 2진수, 8진수, 16진수로 표현할 수 있습니다. 각각 숫자의 앞에 0b, 0o, 0x를 붙여서 표현합니다. 주의할점은 자바스크립트 엔진은 숫자를 10진수로 변환합니다. 따라서 2진수, 8진수, 16진수로 표현했지만 10진수로 변환됩니다.

console.log(0b11111111); // 255 (2진수 11111111을 10진수로 변환) console.log(0o377); // 255 (8진수 377을 10진수로 변환) console.log(0xff); // 255 (16진수 ff를 10진수로 변환)

e를 사용해 숫자를 지수로 표현할 수 있습니다. e 뒤의 숫자는 10의 지수를 의미합니다. 예를 들어 1e3은 1과 3개의 0을 곱한 1000을 의미합니다. 지수 표기법을 이용하면 큰 숫자를 간단하게 표현할 수 있습니다.

console.log(1e9); // 1000000000 (1과 9개의 0) console.log(1e-6); // 0.000001 (0.000001)
1.1.6 특수값

숫자형에는 몇 가지 특수한 값이 존재합니다. 자바스크립트에서 표현할 수 있는 가장 큰 숫자보다 큰 숫자를 나타내는 Infinity가 있습니다.

console.log('무한대 : ', 1 / 0); // 콘솔에서 확인해야 Infinity라고 찍힙니다. 위니북스에서는 출력하지 않습니다. let num = 9999e10000; console.log(num === Infinity); // true (너무 큰 숫자는 Infinity로 취급됨)

NaN은 Not-a-Number의 약자로 숫자가 아님을 나타냅니다. 연산 과정에서 숫자로 표현할 수 없는 경우에 NaN이 반환됩니다.

console.log('숫자가 아님' / 2); // NaN (문자열을 숫자로 나눌 수 없어서 NaN 반환)
1.2. 숫자형 메서드
1.2.1. parseInt(), parseFloat()

이 함수들은 문자열을 숫자로 변환합니다. parseInt는 정수로, parseFloat는 실수로 변환합니다. 두 번째 인자로는 진수를 전달할 수 있습니다. 해당 진법에 맞게 문자열을 인식하여 숫자로 변환합니다.

console.log(`parseInt('hello') : ${parseInt('hello')}`); // NaN (문자열 'hello'는 숫자로 변환 불가) console.log(`pareInt('110', 2): ${parseInt('110', 2)}`); // 6 (2진수 110을 10진수로 변환) console.log(`parseInt('30b') : ${parseInt('30b')}`); // 30 (문자열 '30b'에서 숫자 부분만 변환) console.log(`parseFloat('45.4') : ${parseFloat('45.4')}`); // 45.4 (문자열 '45.4'를 실수로 변환)
1.2.2. toString()

이 메소드는 숫자를 문자열로 변환합니다. 원하는 진수로 표현할 수도 있습니다.

let num = 5; console.log(`num.toString() : ${typeof num.toString()}`); // string (숫자 5를 문자열 '5'로 변환) console.log(`num.toString() : ${(3).toString()}`); // '3' (숫자 3을 문자열 '3'로 변환) console.log(`num.toString(2) : ${(3).toString(2)}`); // '11' (숫자 3을 2진수로 변환하여 '11'로 표현)

3.toString()은 왜 에러가 발생할까요? 자바스크립트 엔진은 숫자 뒤의 점을 소수점으로 인식하기 때문입니다. 따라서 (3).toString()처럼 소괄호를 사용해 숫자를 감싸주어야 합니다.

// console.log(3.toString()); console.log((3).toString());
1.2.3. toFixed()

toFixed는 소수점 이하 자릿수를 지정하여 문자열로 반환합니다. 인자를 지정하지 않으면 소수점 이하를 제거하고 문자열로 반환합니다.

let num = 5.123456; console.log(`num.toFixed() : ${num.toFixed()}`); // 5 (소수점 이하 자릿수를 지정하지 않으면 정수로 반환) console.log(`num.toFixed(2) : ${num.toFixed(2)}`); // 5.12 (소수점 이하 2자리까지 반환) console.log(`num.toFixed(4) : ${num.toFixed(4)}`); // 5.1235 (소수점 이하 4자리까지 반환)
1.2.4. isNaN

이 함수는 값이 NaN인지 확인합니다. 전달받은 값을 숫자형으로 변환하여 NaN인지 판별합니다. Number.isNaN()이 조금 더 나중에 나온 메서드로 값을 숫자형으로 변환하지 않아 정확하게 NaN을 판별합니다. 실무에서는 Number.isNaN()을 사용하는 것을 권합니다. 다만 isNaN()도 여전히 사용되고 있으므로 알아두시는 것이 좋습니다.

console.log(`isNaN('5') : ${isNaN('5')}`); // false (문자열 '5'는 숫자로 변환 가능) console.log(`isNaN(3) : ${isNaN(3)}`); // false (숫자 3은 숫자) console.log(`isNaN('b3') : ${isNaN('b3')}`); // true (문자열 'b3'는 숫자로 변환 불가) console.log(`isNaN('3b') : ${isNaN('3b')}`); // true (문자열 '3b'는 숫자로 변환 불가) console.log(isNaN(undefined)); // true (undefined는 숫자로 변환 불가) console.log(Number.isNaN(undefined)); // false (undefined는 NaN이 아님) console.log(Number.isNaN(null)); // false (null은 NaN이 아님) console.log(Number.isNaN(NaN)); // true (NaN은 NaN)

isNaN과 Number.isNaN의 차이
isNaN()은 값이 NaN인지 확인할 때, 전달받은 값을 숫자형으로 변환하여 NaN인지 판별합니다. Number.isNaN()은 값을 숫자형으로 변환하지 않아 정확하게 NaN을 판별합니다. 따라서 Number.isNaN()을 사용하는 것을 권합니다.

console.log(isNaN('5')); // false (문자열 '5'는 숫자로 변환 가능) console.log(Number.isNaN('5')); // false (문자열 '5'는 숫자로 변환 가능)
console.log(isNaN(undefined)); // true (undefined는 숫자형으로 변환하면 NaN) console.log(Number.isNaN(undefined)); // false (undefined는 NaN이 아님)
1.2.5. Math 객체를 이용한 연산

자바스크립트의 Math 객체는 수학적 연산을 위한 다양한 메소드를 제공합니다. 각 메소드는 특정한 수학적 기능을 수행합니다.

console.log(`Math.PI : ${Math.PI}`); // 3.141592653589793 (원주율) console.log(`Math.round(3.6): ${Math.round(3.6)}`); // 반올림, 3.6을 반올림하여 4 console.log(`Math.round(3.2): ${Math.round(3.2)}`); // 반올림, 3.2를 반올림하여 3 console.log(`Math.floor(4.7): ${Math.floor(-4.5)}`); // 내림 console.log(`Math.ceil(4.7): ${Math.ceil(3.2)}`); // 올림 console.log(`Math.pow(2, 8): ${Math.pow(2, 8)}`); // 2의 8승 console.log(`Math.sqrt(64): ${Math.sqrt(64)}`); // 제곱근 console.log(`Math.abs(-5): ${Math.abs(-5)}`); // 절대값 console.log(`Math.random(): ${Math.random()}`); // 0과 1 사이의 난수, 0 <= Math.random() < 1 console.log(`Math.max(10, 20, 30, 40): ${Math.max(10, 20, 30, 40)}`); // 최대값 40 console.log(`Math.min(10, 20, 30, 40): ${Math.min(10, 20, 30, 40)}`); // 최소값 10
1.3. 숫자 표현 방식

자바스크립트는 숫자를 표현하기 위해서 배정밀도 64비트 부동소수점 형식(double precision 64-bit binary format floating point number) 을 따릅니다.

  1. 배정밀도 64 비트란, 숫자 하나를 표현하는데 64비트의 용량을 사용할 수 있으며 이는 옛날에 사용하던 32비트 방식에 비해 ‘두 배 더 정밀하게’ 수를 표현 할 수 있다는 의미입니다.
  2. 부동소수점이란 부(떠서)+동(움직이다) 즉, 소수점을 이동시키면서 숫자를 표현하는 방식입니다.

이는 한정된 메모리 공간을 효율적으로 사용하기 위한 방법으로 정수 부분과 소수 부분을 따로 저장하여 실수를 표현하는 방식이 아닌, 유효숫자와 소수점의 위치 값으로 숫자를 나타냅니다.

S영역에는 음양의 값, E에는 소수점의 위치, F에는 유효숫자의 값이 저장됩니다

숫자 용어 정리

  1. 정수: 양의 정수, 음의 정수, 0
  2. 실수: 소수점을 포함하는 모든 수
  3. 유효숫자: 수의 정확도에 영향을 주는 수. 주로 소수점 첫째자리에서부터 늘어져있는 0들을 제외한 모든 수를 의미합니다. 소수점이 없는 경우 일의 자리부터 늘어져있는 0도 제외합니다.

0.075 ==> 75
2.430 ==> 2.430
82300 ==> 823
1200.0 ==> 12000

1.3.1. 부동소수점 오차
console.log(0.1 + 0.2 === 0.3); console.log(`0.1 + 0.2 = ${0.1 + 0.2}`);

0.1과 0.2를 더한 값이 0.3이 아닌 0.30000000000000004가 나오는 이유는 부동소수점 오차 때문입니다. 이는 컴퓨터가 2진수로 숫자를 표현하는 방식 때문에 발생합니다. 이를 이해하기 위해서는 우선 10진수를 2진수로 바꾸는 방법을 알아야 합니다. 자바스크립트는 기본적으로 사람이 사용하기 편리하도록 10진수를 기반으로 수를 표현하지만 컴파일 과정에서 2진수로 전환됩니다.

예를 들어 0.375를 2진수로 바꾸는 방법은 다음과 같습니다. 소수부에 2를 곱하며 1이 나올 때까지 반복합니다. 곱의 결과의 정수부를 순서대로 나열하면 0.375의 2진수 표현이 됩니다.

이번에는 0.1을 이진수로 바꿔보겠습니다.

0.1 * 2 = 0.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
0.2 * 2 = 0.4 // 여기서부터 같은 결과가 반복되기 시작합니다.
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
.
.
.
정부수와 합치면 결과는 0.000110011001100110011...
0.1 * 2 = 0.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
0.2 * 2 = 0.4 // 여기서부터 같은 결과가 반복되기 시작합니다.
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
.
.
.
정부수와 합치면 결과는 0.000110011001100110011...

0.1을 2진수로 변환하면 무한소수가 됩니다. 컴퓨터는 메모리의 한계로 무한한 값을 저장할 수 없기 때문에 표현할 수 있는 범위내에서 가장 가까운 수로 근사화하여 계산을 종료합니다. 이때 실제 값과 약간의 오차가 발생합니다.

0.2도 2진수로 변환하면 무한소수가 되는 것을 확인할 수 있습니다.

.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.
.
.
정부수와 합치면 결과는 0.00110011001100110011...
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.
.
.
정부수와 합치면 결과는 0.00110011001100110011...

따라서 0.1과 0.2를 더한 값은 근사화 과정에서 발생한 오차로 인해 0.3이 아닌 0.30000000000000004가 나오게 됩니다.

부동 소수점 오차

정확한 소수 계산이 필요하다면 Decimal.js, math.js 등의 라이브러리로 해결할 수 있습니다.

1.3.2. 정수 범위

자바스크립트는 2의 53승(9,007,199,254,740,992) 이상이거나 -2의 53승 이하의 숫자는 안전하게 표현할 수 없습니다. Number.MIN_SAFE_INTEGER 혹은 Number.MAX_SAFE_INTEGER 프로퍼티를 통해 확인할 수 있습니다. 이 범위를 벗어나는 숫자는 정확성을 보장할 수 없습니다.

console.log(9999999999999999999); // 10000000000000000000 console.log(9007199254740991 + 1); // 9007199254740992 console.log(9007199254740991 + 2); // 9007199254740992 console.log(9007199254740991 + 3); // 9007199254740994 console.log(9007199254740991 + 4); // 9007199254740996

2. BigInt

아주 큰 숫자를 취급할 때에는 bigint를 사용하는 것을 권장합니다. bigint는 일반적인 숫자형을 넘어서는 큰 정수를 표현할 수 있는 데이터 타입입니다. Number.MAX_SAFE_INTEGER보다 큰 정수를 표현할 수 있습니다. 숫자에 n을 붙여 bigint로 표현합니다.

let num = 12345678901234567890; console.log(num + 1); // 숫자가 잘못 표시됩니다. let bigint = 12345678901234567890n; console.log(bigint + 1n);

BigInt와 숫자형은 다른 자료형이므로 연산을 할 때에는 주의해야 합니다.

console.log(5n / 2n); // 2n console.log(5n / 2); // TypeError

BigInt 함수로 값을 변환할 때 주의할 점은 범위를 벗어나는 숫자형에 대해서는 정확성을 보장하지 않는다는 점입니다. 따라서 숫자형으로 안전하게 표현할 수 없는 크기의 값을 BigInt로 표현할 때는 문자열로 입력해주어야 합니다.

console.log(`숫자 변환: ${BigInt(9007199254740993)}`) console.log(`문자열 변환: ${BigInt('9007199254740993')}`)

BigInt는 ES2020(ES11)에서 추가된 새로운 자료형입니다. IE에서는 지원하지 않으므로 사용에 주의해야 합니다.

3.2 원시타입과 문자열3.4 논리형, undefined, null, 심볼