← 글 목록

notes

29장. Math

모던 JS Deep Dive — Math 객체·수학 함수와 반올림 처리 핵심 정리.

참고: 이웅모 《모던 자바스크립트 Deep Dive》 29장 · [MDN Math](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math)

Math는 생성자가 아니다. new Math() 불가. 수학 함수·상수의 네임스페이스 객체다(21). 난수·반올림·삼각·min/max를 한곳에 모아 둔 공구함.

flowchart LR
  MATH[Math] --> CONST[PI E LN2 …]
  MATH --> ROUND[round floor ceil trunc]
  MATH --> RAND[random]
  MATH --> TRIG[sin cos atan2]
  MATH --> AGG[min max abs hypot]

상수

Math.PI, Math.E, Math.LN2, Math.SQRT2 … 원주율·자연상수 필요할 때 하드코딩 대신.

const area = Math.PI * r * r;

반올림 계열

Math.round(1.5); // 2
Math.floor(1.5); // 1
Math.ceil(1.1);  // 2
Math.trunc(1.9); // 1 — 소수점 버림
Math.floor(-1.1); // -2
Math.trunc(-1.1); // -1

음수에서 floor/trunc 차이를 꼭 한 번 찍어 볼 것.

난수

Math.random() → [0, 1).

function randInt(min, max) {
  // min..max 정수 균등 (max 포함)
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
function pick(arr) {
  return arr[randInt(0, arr.length - 1)];
}

암호용 난수는 crypto.getRandomValues. Math.random은 게임·셔플·샘플용.

min / max / abs / sign

Math.min(1, 2, -3); // -3
Math.max(...[1, 2, 3]);
Math.abs(-2);
Math.sign(-0); // -0 구분되는 환경

빈 Math.min()은 Infinity, Math.max()는 -Infinity — 초기값 실수 주의.

삼각·로그·지수

sin/cos/tan/atan2, log/log2/log10, exp, sqrt, cbrt, hypot. 각도는 라디안.

function degToRad(d) { return (d * Math.PI) / 180; }
Math.hypot(3, 4); // 5

예제

function clamp(n, min, max) {
  return Math.min(max, Math.max(min, n));
}
function lerp(a, b, t) {
  return a + (b - a) * t;
}
// 피셔-예이츠 셔플
function shuffle(arr) {
  const a = [...arr];
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

헷갈리던 장면 / 함정

  • 각도 도/라디안
  • random 상한 포함 여부 off-by-one
  • min/max 스프레드 너무 큰 배열 → 스택/인자 한도 — reduce로
  • 암호에 Math.random

표

질문 → 자답

Q. Math를 확장해도 되나? A. 가능하나 비추. 유틸 모듈로.

Q. pow vs ? A. `가 가독성. Math.pow`도 동일 계열.

웹 보강 메모

MDN Math 목록과 crypto.getRandomValues 대비. 애니메이션 lerp/clamp 유틸을 공통 모듈로 뺐다.

실무로 바로

  • UI 게이지: clamp
  • 샘플링: random + 테스트 시 시드 주입 가능한 래퍼
  • 기하: hypot, atan2
  • 돈 반올림: 정수 스케일 후 round

시드 가능한 난수 (테스트)

function mulberry32(a) {
  return function () {
    let t = (a += 0x6d2b79f5);
    t = Math.imul(t ^ (t >>> 15), t | 1);
    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}
const rnd = mulberry32(42);
console.log(rnd(), rnd());

프로덕션 셔플과 테스트 픽스처를 분리할 때 유용.

각도 유틸

const TAU = Math.PI * 2;
const toRad = (d) => (d * Math.PI) / 180;
const toDeg = (r) => (r * 180) / Math.PI;
function normalizeAngle(r) {
  const x = r % TAU;
  return x < 0 ? x + TAU : x;
}

통계 한 줄

const mean = (xs) => xs.reduce((a, b) => a + b, 0) / xs.length;
const sumSq = (xs, m = mean(xs)) => xs.reduce((a, x) => a + (x - m) ** 2, 0);

여기서 잠깐 💁‍♂️

30 Date — 시간대·파싱·타임스탬프의 지뢰밭.

보강 — 정밀도

삼각함수·로그도 부동소수. 기하 비교는 EPSILON. 금융·정확한 소수점은 Math 밖(Decimal).

보강 — imul / clz32

32비트 정수 곱·선행 제로 비트. 저수준·해시·그래픽. 필요할 때 MDN.

실무 체크리스트 (Math)

  • [ ] 각도 단위 문서화 (rad/deg)
  • [ ] random 상·하한 inclusive 테스트
  • [ ] min/max 빈 배열 가드
  • [ ] 암호/토큰에 Math.random 금지
  • [ ] 애니메이션은 lerp+clamp

예제 — 이지 아웃

function easeOutCubic(t) {
  return 1 - (1 - t) ** 3;
}
function animate(from, to, t) {
  return lerp(from, to, easeOutCubic(clamp(t, 0, 1)));
}
function lerp(a, b, t) { return a + (b - a) * t; }
function clamp(n, min, max) { return Math.min(max, Math.max(min, n)); }

오늘 지운 미신

“Math.random은 보안 난수” → 아니오. “floor만 알면 반올림 끝” → 음수·trunc·표시용 round 구분. “min(...거대배열) OK” → 인자 한도 — reduce.

추가 예제 — 가중 랜덤

function weightedPick(items, weights, rnd = Math.random) {
  const total = weights.reduce((a, b) => a + b, 0);
  let r = rnd() * total;
  for (let i = 0; i < items.length; i++) {
    r -= weights[i];
    if (r <= 0) return items[i];
  }
  return items.at(-1);
}

추가 — 근사 비교와 기하

function pointsEqual(a, b, eps = 1e-9) {
  return Math.hypot(a.x - b.x, a.y - b.y) < eps;
}

추가 — log1p / expm1

작은 값에서 Math.log(1+x) 대신 log1p, exp-1 대신 expm1이 정밀도에 유리.

추가 — 원형 레이아웃

function pointOnCircle(cx, cy, r, angleRad) {
  return { x: cx + r * Math.cos(angleRad), y: cy + r * Math.sin(angleRad) };
}

캔버스·SVG 아이콘 배치에 사용. y축 방향(화면 vs 수학)만 확인.

마무리

Math는 작은 장이지만 매일 만진다. 반올림·난수·클램프만 팀 유틸로 모아도 버그가 줄어든다.

한 줄 유틸 모음

const clamp = (n, a, b) => Math.min(b, Math.max(a, n));
const lerp = (a, b, t) => a + (b - a) * t;
const rand = (a, b) => Math.random() * (b - a) + a;
const randInt = (a, b) => Math.floor(rand(a, b + 1));

이 네 개만 모듈로 빼도 장 사용의 80%를 덮는다.