JavaScript Number와 Math 완벽 가이드 - 숫자 처리의 모든 것
JavaScript의 Number 타입과 Math 객체를 마스터하세요. 반올림, 난수 생성, 소수점 처리, 숫자 포맷팅 등 실무에서 바로 쓸 수 있는 모든 것을 다룹니다.
JavaScript Number와 Math 완벽 가이드 - 숫자 처리의 모든 것
Number 타입 기본
JavaScript에서 숫자는 64비트 부동소수점 형식으로 저장됩니다. 정수와 실수를 구분하지 않습니다.
1
2
3
4
5
6
7
const integer = 42; // 정수
const float = 3.14; // 실수
const negative = -10; // 음수
const exponential = 2e3; // 지수 표기법 (2000)
console.log(typeof integer); // "number"
console.log(typeof float); // "number"
Math 객체 완벽 가이드
Math 객체는 수학 계산을 위한 내장 객체입니다. 생성자가 없어 new Math()처럼 사용할 수 없습니다.
1. 반올림 메서드
Math.round() - 반올림
1
2
3
4
5
console.log(Math.round(2.5)); // 3
console.log(Math.round(2.49)); // 2
console.log(Math.round(2)); // 2
console.log(Math.round(2.82)); // 3
console.log(Math.round(-2.5)); // -2 (음수는 0에 가깝게)
Math.ceil() - 올림
1
2
3
4
console.log(Math.ceil(2.1)); // 3
console.log(Math.ceil(2.9)); // 3
console.log(Math.ceil(2)); // 2
console.log(Math.ceil(-2.1)); // -2 (음수는 0 방향으로)
Math.floor() - 내림
1
2
3
4
console.log(Math.floor(2.1)); // 2
console.log(Math.floor(2.9)); // 2
console.log(Math.floor(2)); // 2
console.log(Math.floor(-2.1)); // -3 (음수는 더 작은 정수로)
Math.trunc() - 소수점 제거 (ES6)
1
2
3
4
5
6
console.log(Math.trunc(2.9)); // 2
console.log(Math.trunc(-2.9)); // -2 (부호 유지, 소수만 제거)
// floor와의 차이
console.log(Math.floor(-2.9)); // -3
console.log(Math.trunc(-2.9)); // -2
2. 최대/최소값
Math.max() / Math.min()
1
2
3
4
5
6
7
8
9
10
console.log(Math.max(1, 5, 3, 9, 2)); // 9
console.log(Math.min(1, 5, 3, 9, 2)); // 1
// 배열의 최대/최소값
const numbers = [1, 5, 3, 9, 2];
console.log(Math.max(...numbers)); // 9 (스프레드 연산자)
console.log(Math.min(...numbers)); // 1
// apply 사용 (ES5)
console.log(Math.max.apply(null, numbers)); // 9
3. 절댓값과 부호
Math.abs() - 절댓값
1
2
3
console.log(Math.abs(-5)); // 5
console.log(Math.abs(5)); // 5
console.log(Math.abs(-3.14)); // 3.14
Math.sign() - 부호 확인 (ES6)
1
2
3
4
5
console.log(Math.sign(5)); // 1 (양수)
console.log(Math.sign(-5)); // -1 (음수)
console.log(Math.sign(0)); // 0
console.log(Math.sign(-0)); // -0
console.log(Math.sign(NaN)); // NaN
4. 제곱과 제곱근
Math.pow() - 거듭제곱
1
2
3
4
5
6
7
console.log(Math.pow(2, 3)); // 8 (2^3)
console.log(Math.pow(5, 2)); // 25 (5^2)
console.log(Math.pow(4, 0.5)); // 2 (√4)
// ES7 지수 연산자 (**)
console.log(2 ** 3); // 8
console.log(5 ** 2); // 25
Math.sqrt() - 제곱근
1
2
3
4
console.log(Math.sqrt(4)); // 2
console.log(Math.sqrt(9)); // 3
console.log(Math.sqrt(2)); // 1.4142135623730951
console.log(Math.sqrt(-1)); // NaN (음수는 불가능)
Math.cbrt() - 세제곱근 (ES6)
1
2
3
console.log(Math.cbrt(8)); // 2 (∛8)
console.log(Math.cbrt(27)); // 3 (∛27)
console.log(Math.cbrt(-8)); // -2 (음수 가능)
5. 랜덤 함수
Math.random() - 난수 생성
0 이상 1 미만의 부동소수점 난수를 반환합니다.
1
2
console.log(Math.random());
// 0.697009826327621 (매번 다른 값)
실용적인 랜덤 숫자 생성 패턴
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 1. 0~9 사이의 정수
const random0to9 = Math.floor(Math.random() * 10);
// 2. 1~10 사이의 정수
const random1to10 = Math.floor(Math.random() * 10) + 1;
// 3. 최소값~최대값 사이의 정수 (범용 함수)
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(getRandomInt(1, 6)); // 주사위: 1~6
console.log(getRandomInt(1, 100)); // 1~100
// 4. 배열에서 랜덤 요소 선택
function getRandomElement(array) {
return array[Math.floor(Math.random() * array.length)];
}
const fruits = ['🍎', '🍌', '🍇', '🍊'];
console.log(getRandomElement(fruits)); // 랜덤 과일
// 5. 배열 셔플 (Fisher-Yates)
function shuffle(array) {
const shuffled = [...array];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled;
}
console.log(shuffle([1, 2, 3, 4, 5]));
// [3, 1, 5, 2, 4] (매번 다른 순서)
6. 삼각함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 라디안 단위 사용
console.log(Math.sin(Math.PI / 2)); // 1 (sin 90°)
console.log(Math.cos(0)); // 1 (cos 0°)
console.log(Math.tan(Math.PI / 4)); // 1 (tan 45°)
// 도 → 라디안 변환
function toRadians(degrees) {
return degrees * (Math.PI / 180);
}
console.log(Math.sin(toRadians(90))); // 1
// 역삼각함수
console.log(Math.asin(1)); // π/2
console.log(Math.acos(1)); // 0
console.log(Math.atan(1)); // π/4
console.log(Math.atan2(1, 1)); // π/4 (2인자 버전)
Math 상수
1
2
3
4
5
6
7
8
console.log(Math.PI); // 3.141592653589793 (원주율)
console.log(Math.E); // 2.718281828459045 (자연로그 밑)
console.log(Math.LN2); // 0.6931471805599453 (ln 2)
console.log(Math.LN10); // 2.302585092994046 (ln 10)
console.log(Math.LOG2E); // 1.4426950408889634 (log₂ e)
console.log(Math.LOG10E); // 0.4342944819032518 (log₁₀ e)
console.log(Math.SQRT2); // 1.4142135623730951 (√2)
console.log(Math.SQRT1_2); // 0.7071067811865476 (√½)
Number 객체와 메서드
1. 숫자 변환
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Number() - 타입 변환
console.log(Number('123')); // 123
console.log(Number('12.34')); // 12.34
console.log(Number('')); // 0
console.log(Number('hello')); // NaN
console.log(Number(true)); // 1
console.log(Number(false)); // 0
// parseInt() - 정수 파싱
console.log(parseInt('123')); // 123
console.log(parseInt('123.99')); // 123 (소수점 버림)
console.log(parseInt('123px')); // 123 (숫자 부분만)
console.log(parseInt('px123')); // NaN
// 진법 지정
console.log(parseInt('1010', 2)); // 10 (2진수)
console.log(parseInt('FF', 16)); // 255 (16진수)
// parseFloat() - 실수 파싱
console.log(parseFloat('3.14')); // 3.14
console.log(parseFloat('3.14.15')); // 3.14
console.log(parseFloat('3.14px')); // 3.14
2. 소수점 처리
toFixed() - 고정 소수점
1
2
3
4
5
6
7
8
9
10
const num = 3.14159;
console.log(num.toFixed(2)); // "3.14" (문자열!)
console.log(num.toFixed(0)); // "3"
console.log(num.toFixed(5)); // "3.14159"
// 숫자로 변환하려면
console.log(Number(num.toFixed(2))); // 3.14
console.log(parseFloat(num.toFixed(2))); // 3.14
console.log(+num.toFixed(2)); // 3.14
toPrecision() - 전체 자릿수 지정
1
2
3
4
5
const num = 123.456;
console.log(num.toPrecision(4)); // "123.5" (전체 4자리)
console.log(num.toPrecision(2)); // "1.2e+2" (지수 표기법)
console.log(num.toPrecision(7)); // "123.4560"
toExponential() - 지수 표기법
1
2
3
4
const num = 123456;
console.log(num.toExponential()); // "1.23456e+5"
console.log(num.toExponential(2)); // "1.23e+5"
3. Number 상수
1
2
3
4
5
6
7
8
console.log(Number.MAX_VALUE); // 1.7976931348623157e+308
console.log(Number.MIN_VALUE); // 5e-324
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991 (2^53 - 1)
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991
console.log(Number.POSITIVE_INFINITY); // Infinity
console.log(Number.NEGATIVE_INFINITY); // -Infinity
console.log(Number.NaN); // NaN
console.log(Number.EPSILON); // 2.220446049250313e-16 (부동소수점 오차)
4. Number 검증 메서드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Number.isNaN() - NaN 확인
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN('hello')); // false (타입 변환 안 함)
console.log(isNaN('hello')); // true (전역 isNaN은 타입 변환)
// Number.isFinite() - 유한수 확인
console.log(Number.isFinite(42)); // true
console.log(Number.isFinite(Infinity)); // false
console.log(Number.isFinite('42')); // false (타입 변환 안 함)
// Number.isInteger() - 정수 확인
console.log(Number.isInteger(42)); // true
console.log(Number.isInteger(42.0)); // true
console.log(Number.isInteger(42.1)); // false
// Number.isSafeInteger() - 안전한 정수 확인
console.log(Number.isSafeInteger(42)); // true
console.log(Number.isSafeInteger(9007199254740991)); // true
console.log(Number.isSafeInteger(9007199254740992)); // false
NaN 처리
NaN이 발생하는 경우
1
2
3
4
5
console.log(0 / 0); // NaN
console.log(Math.sqrt(-1)); // NaN
console.log(parseInt('hello')); // NaN
console.log(Number('abc')); // NaN
console.log(NaN + 5); // NaN (NaN과의 연산은 항상 NaN)
NaN 확인하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const value = NaN;
// ❌ 직접 비교는 불가능
console.log(value === NaN); // false (NaN은 자기 자신과도 다름!)
// ✅ Number.isNaN() 사용 (권장)
console.log(Number.isNaN(value)); // true
// ✅ Object.is() 사용
console.log(Object.is(value, NaN)); // true
// ⚠️ 전역 isNaN()은 타입 변환함
console.log(isNaN('hello')); // true
console.log(Number.isNaN('hello')); // false
부동소수점 오차 처리
JavaScript는 IEEE 754 표준을 따르므로 부동소수점 오차가 발생합니다.
문제
1
2
3
console.log(0.1 + 0.2); // 0.30000000000000004 😱
console.log(0.1 + 0.2 === 0.3); // false
console.log(0.3 - 0.1); // 0.19999999999999998
해결 방법
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1. toFixed() 사용
const result = (0.1 + 0.2).toFixed(1); // "0.3"
console.log(parseFloat(result) === 0.3); // true
// 2. Number.EPSILON 활용
function isEqual(a, b) {
return Math.abs(a - b) < Number.EPSILON;
}
console.log(isEqual(0.1 + 0.2, 0.3)); // true
// 3. 정수로 변환 후 계산
function addDecimals(a, b) {
const multiplier = 10;
return (a * multiplier + b * multiplier) / multiplier;
}
console.log(addDecimals(0.1, 0.2)); // 0.3
// 4. 라이브러리 사용 (큰 프로젝트)
// - decimal.js
// - big.js
// - bignumber.js
실무 활용 예제
1. 가격 포맷팅
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function formatPrice(price) {
return price.toLocaleString('ko-KR') + '원';
}
console.log(formatPrice(1234567)); // "1,234,567원"
// 소수점 포함
function formatCurrency(price) {
return new Intl.NumberFormat('ko-KR', {
style: 'currency',
currency: 'KRW'
}).format(price);
}
console.log(formatCurrency(1234567.89)); // "₩1,234,568"
2. 퍼센트 계산
1
2
3
4
5
6
7
8
9
10
11
12
function calculatePercentage(value, total) {
return ((value / total) * 100).toFixed(2) + '%';
}
console.log(calculatePercentage(75, 200)); // "37.50%"
// 할인율 계산
function getDiscountRate(original, discounted) {
return Math.round(((original - discounted) / original) * 100);
}
console.log(getDiscountRate(10000, 7000)); // 30
3. 평점 계산
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function calculateRating(ratings) {
const sum = ratings.reduce((acc, rating) => acc + rating, 0);
const avg = sum / ratings.length;
return Math.round(avg * 10) / 10; // 소수점 1자리 반올림
}
const appRatings = [4.5, 5, 3.8, 4.2, 4.7];
console.log(calculateRating(appRatings)); // 4.4
// 별점 표시
function getStarRating(rating) {
const fullStars = Math.floor(rating);
const hasHalfStar = rating % 1 >= 0.5;
const emptyStars = 5 - fullStars - (hasHalfStar ? 1 : 0);
return '★'.repeat(fullStars) +
(hasHalfStar ? '☆' : '') +
'☆'.repeat(emptyStars);
}
console.log(getStarRating(4.4)); // "★★★★☆"
console.log(getStarRating(3.7)); // "★★★☆☆"
4. 랜덤 이벤트 (로또, 추첨)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 로또 번호 생성 (1~45 중 6개)
function generateLotto() {
const numbers = [];
while (numbers.length < 6) {
const num = Math.floor(Math.random() * 45) + 1;
if (!numbers.includes(num)) {
numbers.push(num);
}
}
return numbers.sort((a, b) => a - b);
}
console.log(generateLotto()); // [3, 12, 23, 28, 35, 42]
// 가중치 랜덤 선택
function weightedRandom(items, weights) {
const totalWeight = weights.reduce((sum, w) => sum + w, 0);
let random = Math.random() * totalWeight;
for (let i = 0; i < items.length; i++) {
random -= weights[i];
if (random <= 0) {
return items[i];
}
}
}
const prizes = ['1등', '2등', '3등', '꽝'];
const chances = [1, 5, 10, 84]; // 1%, 5%, 10%, 84%
console.log(weightedRandom(prizes, chances)); // 대부분 '꽝'
5. 통계 계산
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 평균
function average(numbers) {
return numbers.reduce((sum, num) => sum + num, 0) / numbers.length;
}
// 중앙값
function median(numbers) {
const sorted = [...numbers].sort((a, b) => a - b);
const mid = Math.floor(sorted.length / 2);
if (sorted.length % 2 === 0) {
return (sorted[mid - 1] + sorted[mid]) / 2;
}
return sorted[mid];
}
// 표준편차
function standardDeviation(numbers) {
const avg = average(numbers);
const squaredDiffs = numbers.map(num => Math.pow(num - avg, 2));
const variance = average(squaredDiffs);
return Math.sqrt(variance);
}
const scores = [85, 90, 78, 92, 88];
console.log('평균:', average(scores)); // 86.6
console.log('중앙값:', median(scores)); // 88
console.log('표준편차:', standardDeviation(scores)); // 5.02
6. 범위 제한 (Clamp)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
console.log(clamp(50, 0, 100)); // 50
console.log(clamp(-10, 0, 100)); // 0
console.log(clamp(150, 0, 100)); // 100
// 볼륨 조절 예제
function setVolume(volume) {
return clamp(volume, 0, 100);
}
console.log(setVolume(120)); // 100
console.log(setVolume(-5)); // 0
7. 거리 계산 (좌표)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 두 점 사이의 거리 (피타고라스 정리)
function getDistance(x1, y1, x2, y2) {
const dx = x2 - x1;
const dy = y2 - y1;
return Math.sqrt(dx * dx + dy * dy);
}
console.log(getDistance(0, 0, 3, 4)); // 5
// 위도/경도 거리 (Haversine 공식)
function getGeoDistance(lat1, lon1, lat2, lon2) {
const R = 6371; // 지구 반지름 (km)
const dLat = toRadians(lat2 - lat1);
const dLon = toRadians(lon2 - lon1);
const a = Math.sin(dLat / 2) ** 2 +
Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
Math.sin(dLon / 2) ** 2;
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
function toRadians(degrees) {
return degrees * (Math.PI / 180);
}
// 서울 → 부산
console.log(getGeoDistance(37.5665, 126.9780, 35.1796, 129.0756));
// 약 325km
비교 정리표
| 메서드 | 기능 | 예시 | 결과 |
|---|---|---|---|
Math.round() | 반올림 | Math.round(2.5) | 3 |
Math.ceil() | 올림 | Math.ceil(2.1) | 3 |
Math.floor() | 내림 | Math.floor(2.9) | 2 |
Math.trunc() | 소수점 제거 | Math.trunc(2.9) | 2 |
Math.random() | 난수 생성 | Math.random() | 0~1 |
toFixed(n) | 소수점 n자리 | (3.14).toFixed(1) | "3.1" |
parseInt() | 정수 변환 | parseInt("42px") | 42 |
parseFloat() | 실수 변환 | parseFloat("3.14") | 3.14 |
Best Practices
✅ 권장 사항
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 1. 타입 안전한 검증 사용
if (Number.isNaN(value)) { } // ✅
if (isNaN(value)) { } // ⚠️ 타입 변환 발생
// 2. 부동소수점 비교 시 epsilon 사용
if (Math.abs(a - b) < Number.EPSILON) { } // ✅
// 3. 안전한 정수 범위 확인
if (Number.isSafeInteger(bigNumber)) { } // ✅
// 4. 범위 제한 함수 사용
const volume = Math.min(Math.max(value, 0), 100); // ✅
// 5. 소수점 처리 후 숫자로 변환
const price = +value.toFixed(2); // ✅
❌ 피해야 할 사항
1
2
3
4
5
6
7
8
9
10
11
12
13
// 1. NaN 직접 비교
if (value === NaN) { } // ❌ 항상 false
// 2. 부동소수점 직접 비교
if (0.1 + 0.2 === 0.3) { } // ❌ false
// 3. parseInt 진법 생략
parseInt('08'); // ❌ 엣날 환경에서 8진수로 해석될 수 있음
parseInt('08', 10); // ✅
// 4. toFixed 결과를 숫자로 착각
const result = num.toFixed(2); // ❌ 문자열!
console.log(result + 1); // "3.141" (문자열 연결)
핵심 정리
Math 객체 주요 메서드
- 반올림:
round(),ceil(),floor(),trunc() - 최대/최소:
max(),min() - 제곱/제곱근:
pow(),sqrt(),cbrt() - 랜덤:
random() - 절댓값:
abs() - 삼각함수:
sin(),cos(),tan()
Number 객체 주요 메서드
- 변환:
Number(),parseInt(),parseFloat() - 소수점:
toFixed(),toPrecision() - 검증:
isNaN(),isFinite(),isInteger()
주의사항
- 부동소수점 오차 항상 고려
- NaN은 자기 자신과 같지 않음
- toFixed() 결과는 문자열
- 안전한 정수 범위 확인 (
Number.MAX_SAFE_INTEGER)
참고 자료
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.