`Math` 物件

`Math` 物件

本文介紹 Math 物件。

本文將從基本用法到常見實用範例,並說明常見陷阱與對策,逐步進行解說。

YouTube Video

Math 物件

JavaScript 的 Math 物件提供一組用於數值運算的內建工具函式。

常數

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.floorMath.ceilMath.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 或是 ** 運算子來完成。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)在統計與微分方程領域是標準選擇。常用對數與二進對數也根據應用類型來選用。

三角函數(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、角度正規化)

常用的數學操作建議自行寫些小型輔助函式方便重複使用。

以下是常用輔助函式的實作範例。

 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 用於將數值限制在指定範圍,lerpmapRange 則可做平滑插值或範圍轉換。此外,normalizeAngle 會將角度正規化到 [-π, π) 範圍,穩定旋轉運算。
  • 這些輔助函式在圖形處理、遊戲設計及互動程式中經常用到。normalizeAngle 對於角度差異比較與插值操作非常重要。

浮點數與取整注意事項(精度與比較)

JavaScript 的數字採用 IEEE-754 雙精度浮點(64 位元),因此在比較或取整時要特別小心。例如,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}
  • 在優化前最好先用效能分析工具找出程式熱點。
  • 經常使用的常數最佳做法是快取起來。

相容性與 polyfill 方案

Math 物件已存在很久,但如 Math.cbrtMath.log10Math.log2Math.hypot 等某些函式,在舊環境中可能不支援。如有需要請自行準備簡單的 polyfill。

以下是 Math.log2 的簡易 polyfill 範例。

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 等小工具輔助實作。
  • 請注意浮點數精度與目標環境的支援情形,必要時準備誤差容忍或 polyfill。

您可以在我們的 YouTube 頻道上使用 Visual Studio Code 來跟隨上述文章一起學習。 請也查看我們的 YouTube 頻道。

YouTube Video