วัตถุ `Math`

วัตถุ `Math`

บทความนี้อธิบายเกี่ยวกับวัตถุ Math

คำอธิบายทีละขั้นตอน ตั้งแต่การใช้งานพื้นฐานถึงรูปแบบที่ใช้บ่อย รวมถึงข้อควรระวังและวิธีป้องกัน

YouTube Video

วัตถุ Math

วัตถุ Math ของ JavaScript มีฟังก์ชันพื้นฐานที่ใช้ในการคำนวณตัวเลขให้พร้อมใช้งาน

ค่าคงที่

ค่าคงที่ใน 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 หรือด้วยโอเปอเรเตอร์ ** Math.hypot ใช้คำนวณรากที่สองของผลรวมกำลังสองได้อย่างปลอดภัย (ระยะทาง)

ด้านล่างนี้คือตัวอย่างการยกกำลังและการใช้ hypot Math.hypot ช่วยลดปัญหา overflow และ underflow

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) สะดวกในการคำนวณมุมโดยคำนึงถึงจตุภาค (quadrant) ที่ถูกต้อง

ด้านล่างคือตัวอย่างและการใช้งานพื้นฐานของ 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), การแทรกค่า (interpolation), การแปลงช่วง, และการปรับค่า (normalize) มุม clamp ใช้จำกัดค่าไม่ให้ออกนอกช่วง, ส่วน lerp และ mapRange ใช้แทรกค่าอย่างนุ่มนวลหรือแปลงไปยังช่วงใหม่ นอกจากนี้ normalizeAngle จะปรับค่ามุมให้อยู่ในช่วง [-π, π) เพื่อประมวลผลการหมุนได้เสถียร
  • ฟังก์ชันช่วยเหล่านี้ถูกใช้บ่อยในงานกราฟิก เกม และโปรแกรมเชิงอินเทอร์แอคทีฟ normalizeAngle สำคัญกับการเปรียบเทียบความแตกต่างของมุมและการแทรกมุม

ข้อควรระวังเกี่ยวกับทศนิยมและการปัดเศษ (ความแม่นยำและการเปรียบเทียบ)

เลขใน JavaScript ใช้มาตรฐาน IEEE-754 แบบ double-precision (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.cbrt, Math.log10, Math.log2 และ Math.hypot อาจใช้ไม่ได้ในสภาพแวดล้อมเก่า หากจำเป็นควรเตรียม polyfill ง่าย ๆ ไว้

ตัวอย่างด้านล่างคือ polyfill อย่างง่ายของ 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 เพื่อการใช้งานจริง
  • โปรดระวังความแม่นยำของตัวเลขทศนิยมและการรองรับของสภาพแวดล้อมเป้าหมาย และเตรียมโค้ดยอมรับข้อผิดพลาดหรือ polyfill หากจำเป็น

คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย

YouTube Video