`Math` オブジェクト
この記事ではMath オブジェクトについて説明します。
基本的な使い方から実務でよく使うパターン、落とし穴と対策までステップバイステップで丁寧に説明します。
YouTube Video
Math オブジェクト
JavaScript の Math オブジェクトは数値計算のための組み込みユーティリティ群を提供します。
定数(Constants)
Math に定義された定数は高精度な値を扱うときに便利です。
以下のコードは代表的な定数を表示します。
1// Show common Math constants
2console.log("Math.PI:", Math.PI); // 3.141592653589793
3console.log("Math.E:", Math.E); // Euler's number
4console.log("Math.LN2:", Math.LN2); // Natural log of 2
5console.log("Math.SQRT2:", Math.SQRT2); // Square root of 2
- これらの定数は三角関数や対数変換、正規化などでそのまま利用できます。たとえば角度をラジアンに変換するのに
Math.PIが必要です。
基本的な丸め・絶対値(abs, floor, ceil, round, trunc)
数値の丸め処理や符号の取り扱いは多くの場面で使われるため、Math.floor・Math.ceil・Math.round の動作の違いを正しく理解しておくことが重要です。特に、負の数を扱うと結果が直感と異なる場合があるため、それぞれの丸め規則に注意して使い分ける必要があります。
次の例は丸め関数の違いを示します。
1// Examples of rounding and absolute value functions
2const pos = 3.7;
3const neg = -3.7;
4
5// --- floor ---
6console.log("Math.floor(3.7):", Math.floor(pos)); // 3
7console.log("Math.floor(-3.7):", Math.floor(neg)); // -4
8// (rounds toward smaller value)
9
10// --- ceil ---
11console.log("Math.ceil(3.7):", Math.ceil(pos)); // 4
12console.log("Math.ceil(-3.7):", Math.ceil(neg)); // -3
13// (rounds toward larger value)
14
15// --- round ---
16console.log("Math.round(3.5):", Math.round(3.5)); // 4
17// (.5 goes up for positive numbers)
18console.log("Math.round(-3.5):", Math.round(-3.5)); // -3
19// (.5 moves toward zero for negative numbers)
20
21// --- trunc ---
22console.log("Math.trunc(3.7):", Math.trunc(pos)); // 3
23console.log("Math.trunc(-3.7):", Math.trunc(neg)); // -3
24// (fraction removed toward zero)
25
26// --- abs ---
27console.log("Math.abs(-3.7):", Math.abs(neg)); // 3.7
Math.floorは、負の数では「小さい方向」へ丸めるため、-3.7は-4になります。Math.ceilは、負の数では「大きい方向」へ丸めるため、-3.7は-3になります。Math.roundの四捨五入は.5のとき正の数は上へ、負の数は絶対値が小さい方向へ丸められます。- 負の数は直感と違う結果になりやすいため、「どちらの方向へ丸められるか」を明確に理解して使う必要があります。
- 丸め関数は用途ごとに使い分けます。たとえばインデックス計算では
Math.floor、上限を取るときはMath.ceil、小数部分を切り落とすだけならMath.truncが使えます。
乗算・べき乗・平方根(pow, **, sqrt, cbrt, hypot)
べき乗や平方根は Math.pow または 2個の*演算子で可能です。Math.hypot は数値の二乗和の平方根(距離)を安全に計算します。
以下はべき乗と hypot の例です。Math.hypot はオーバーフロー/アンダーフローの影響を軽減します。
1// Power, root and hypot examples
2console.log("2 ** 10:", 2 ** 10); // 1024
3console.log("Math.pow(2, 10):", Math.pow(2, 10));// 1024
4console.log("Math.sqrt(16):", Math.sqrt(16)); // 4
5console.log("Math.cbrt(27):", Math.cbrt(27)); // 3
6console.log("Math.hypot(3, 4):", Math.hypot(3, 4));// 5 (3-4-5 triangle)
- 三角形の辺や多次元ベクトルの長さを扱う場面で
Math.hypotは便利です。
指数関数・対数(exp, log, log10, log2)
指数関数と対数は確率や指数減衰、スケーリングでよく使います。
次は基本的な exp と対数例です。ベースの違いに注意して使い分けてください。
1// Exponential and logarithm examples
2console.log("Math.exp(1):", Math.exp(1)); // e^1
3console.log("Math.log(Math.E):", Math.log(Math.E)); // natural log, 1
4console.log("Math.log10(100):", Math.log10(100)); // 2
5console.log("Math.log2(8):", Math.log2(8)); // 3
- 自然対数(
Math.log)は統計や微分方程式で標準的に使われます。常用対数や 2 を底にした対数も用途によって使い分けます。
三角関数(sin, cos, tan, asin, acos, atan2)
角度計算や回転、座標変換には三角関数が必須です。Math.atan2(y, x) は象限を正しく扱う角度算出に便利です。
以下は基本例と atan2 の使い方です。角度はラジアンで扱う必要があります。
1// Trigonometry examples (angles in radians)
2const degToRad = deg => deg * (Math.PI / 180);
3const radToDeg = rad => rad * (180 / Math.PI);
4
5console.log("Math.sin(PI/2):", Math.sin(Math.PI / 2)); // 1
6console.log("Math.cos(0):", Math.cos(0)); // 1
7console.log("Math.tan(Math.PI / 4):", Math.tan(Math.PI / 4)); // ~1
8
9// Using atan2 to compute angle of vector (x, y)
10const x = -1, y = 1;
11const angle = Math.atan2(y, x); // returns angle in radians taking quadrant into account
12console.log("atan2(1, -1) in degrees:", radToDeg(angle)); // 135
atan2はベクトルの角度を安全に求められるため、回転や方位計算で優先的に使えます。
乱数生成(Math.random と実用パターン)
Math.random() は [0, 1) の一様乱数を返します。整数範囲や正規分布など必要に応じて変換・拡張できます。
次は乱数のユーティリティ関数の例です。暗号的に安全な乱数が必要な場合は crypto.getRandomValues を使ってください。
1// Random utilities using Math.random
2
3// Get integer in [min, max] inclusive
4function randomInt(min, max) {
5 // Returns integer between min and max (inclusive)
6 return Math.floor(Math.random() * (max - min + 1)) + min;
7}
8console.log("randomInt(1, 6):", randomInt(1, 6)); // dice roll example
9
10// Get float in [min, max)
11function randomFloat(min, max) {
12 return Math.random() * (max - min) + min;
13}
14console.log("randomFloat(0, 5):", randomFloat(0, 5));
15
16// Fisher-Yates shuffle
17function shuffle(array) {
18 for (let i = array.length - 1; i > 0; i--) {
19 const j = Math.floor(Math.random() * (i + 1));
20 // swap array[i] and array[j]
21 [array[i], array[j]] = [array[j], array[i]];
22 }
23 return array;
24}
25console.log("shuffle([1,2,3,4,5]):", shuffle([1,2,3,4,5]));Math.randomは汎用で便利ですが、ゲームのリプレイや暗号用途では再現性や安全性に応じた対策が必要です。
実用ヘルパー(clamp, lerp, mapRange, angle normalization)
よく使う数学ユーティリティは自分で小さな関数にまとめておくと便利です。
以下はよく使うユーティリティの実装例です。
1// Utility functions: clamp, lerp, mapRange, normalizeAngle
2
3// Clamp value between min and max
4function clamp(v, min, max) {
5 return Math.max(min, Math.min(max, v));
6}
7console.log("clamp(10, 0, 5):", clamp(10, 0, 5)); // 5
8
9// Linear interpolation: t in [0,1]
10function lerp(a, b, t) {
11 return a + (b - a) * t;
12}
13console.log("lerp(0, 10, 0.25):", lerp(0, 10, 0.25)); // 2.5
14
15// Map value from one range to another
16function mapRange(v, inMin, inMax, outMin, outMax) {
17 const t = (v - inMin) / (inMax - inMin);
18 return lerp(outMin, outMax, t);
19}
20console.log("mapRange(5, 0, 10, 0, 100):", mapRange(5, 0, 10, 0, 100));
21// -> 50
22
23// Normalize angle to [-PI, PI)
24function normalizeAngle(rad) {
25 return Math.atan2(Math.sin(rad), Math.cos(rad));
26}
27console.log("normalizeAngle(3*PI):", normalizeAngle(3 * Math.PI));- このコードは、値の制限・補間・範囲変換・角度の正規化といった数値処理でよく使われる小さなユーティリティ関数をまとめたものです。
clampは値を指定範囲に収め、lerpとmapRangeは滑らかな値の補間や別の範囲への変換を行います。また、normalizeAngleは角度を常に[-π, π)の範囲に正規化し、回転計算を安定させます。 - これらのヘルパーはグラフィックス、ゲーム、インタラクションで頻繁に使います。
normalizeAngleは角度差の比較や補間で重要です。
浮動小数点・丸めの注意点(精度と比較)
JavaScript の数値は IEEE-754 の倍精度浮動小数点(64-bit)なので、比較や丸めで注意が必要です。たとえば 0.1 + 0.2 !== 0.3 となります。
以下は丸め誤差を扱う例です。誤差を許容する比較や適切な丸め関数を用いることがポイントです。
1// Floating point precision example and safe equality
2console.log("0.1 + 0.2 === 0.3 :", 0.1 + 0.2 === 0.3); // false
3
4function nearlyEqual(a, b, eps = 1e-12) {
5 return Math.abs(a - b) <= eps;
6}
7console.log("nearlyEqual(0.1+0.2, 0.3):", nearlyEqual(0.1 + 0.2, 0.3));
8// -> true
- 数値の等価判定には絶対誤差(
eps)や相対誤差を用いると堅牢です。
性能のヒント
Math の関数は組み込み最適化されており、手書きの同等ロジックより高速なことが多いです。ループ内で同じ計算(例:Math.PI / 180)を繰り返す場合は事前に変数へ代入しておくと小さなオーバーヘッドを抑えられます。
以下は、ラジアン変換をループ外で定数化する例です。
1// Cache conversion factor for performance
2const DEG_TO_RAD = Math.PI / 180;
3const RAD_TO_DEG = 180 / Math.PI;
4
5for (let deg = 0; deg < 360; deg += 10) {
6 // Use cached constant instead of computing each time
7 const rad = deg * DEG_TO_RAD;
8 // ... do work with rad
9}- 最適化はプロファイラで実際のホットスポットを確認してから行うのが安全です。
- 頻繁に使う定数はキャッシュすると、効率的です。
互換性・ポリフィル
Math 自体は古くから存在しますが、Math.cbrt, Math.log10, Math.log2, Math.hypot など一部の関数は古い環境で未サポートな場合があります。必要なら簡単なポリフィルを用意してください。
以下は、Math.log2 の簡易ポリフィルの例です。
1// Polyfill for Math.log2 if needed
2if (!Math.log2) {
3 Math.log2 = function(x) {
4 return Math.log(x) / Math.LN2;
5 };
6}
7console.log("Math.log2(8):", Math.log2(8));多くの環境では既にサポートされていますが、互換性が必要ならチェックします。
ブラウザのサポート状況はプロジェクトのターゲット環境に合わせて確認してください。
実用的な例:簡易物理シミュレーションの時間刻み更新
最後に Math を組み合わせた実用的サンプルを示します。位置・速度の更新と角度制御を行う非常に簡単な例です。
物理エンジンの極めて単純化したモデルです。
1// Clamp value between min and max
2function clamp(v, min, max) {
3 return Math.max(min, Math.min(max, v));
4}
5
6// Normalize angle to [-PI, PI)
7function normalizeAngle(rad) {
8 return Math.atan2(Math.sin(rad), Math.cos(rad));
9}
10
11// Simple physics step example using Math utilities
12function step(state, dt) {
13 // state: { x, y, vx, vy, angle, angularVelocity }
14 // dt: time delta in seconds
15 // Integrate linear motion
16 state.x += state.vx * dt;
17 state.y += state.vy * dt;
18
19 // Integrate angular motion and normalize angle
20 state.angle = normalizeAngle(state.angle + state.angularVelocity * dt);
21
22 // Keep position within bounds [0, width] x [0, height]
23 state.x = clamp(state.x, 0, state.width);
24 state.y = clamp(state.y, 0, state.height);
25 return state;
26}
27
28const state = { x: 10, y: 10, vx: 2, vy: 0.5, angle: 0, angularVelocity: 0.1, width: 100, height: 100 };
29console.log("before:", state);
30step(state, 0.016); // simulate ~1 frame at 60fps
31console.log("after:", state);- このように
Mathのヘルパーを組み合わせると、シミュレーションやアニメーションのロジックが簡潔になります。
まとめ
Mathは定数・基本関数から高度な関数まで幅広くカバーしており、数値処理の基礎を支えます。- 乱数や三角関数、指数対数、丸めの違いなど用途に合わせて関数を選び、
clampやlerpのような小さなユーティリティを作ると実務で役立ちます。 - 浮動小数点の精度や対象環境のサポート状況に注意し、必要なら誤差許容やポリフィルを用意します。
YouTubeチャンネルでは、Visual Studio Codeを用いて上記の記事を見ながら確認できます。 ぜひYouTubeチャンネルもご覧ください。