אובייקט `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(לוגריתם טבעי) נפוץ בסטטיסטיקה ומשוואות דיפרנציאליות. גם לוגריתמים בבסיס 10 או בבסיס 2 נבחרים בהתאם לצורך.
פונקציות טריגונומטריות (sin, cos, tan, asin, acos, atan2)
פונקציות טריגונומטריות חשובות במיוחד לחישוב זוויות, סיבובים, והמרות קואורדינטות. Math.atan2(y, x) שימושית לקביעת זוויות תוך התחשבות נכונה ברבעונים (quadrants).
להלן דוגמאות בסיסיות לשימוש ב-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מצמצמת ערך לטווח נתון, בעוד ש-lerpו-mapRangeמבצעות אינטרפולציה חלקה או המרת טווח. בנוסף,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}- רצוי תמיד לבדוק עומסים (hotspots) עם פרופיילר טרם ביצוע אופטימיזציות.
- יעיל לאחסן בזיכרון קבועים שנעשה בהם שימוש תדיר.
תאימות ופוליפילים
אובייקט 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לשימוש יומיומי. - הקפידו על דיוק נקודה צפה ובדקו תאימות בסביבת היעד; הכינו פתרונות לסבילות שגיאה או פוליפילים במידת הצורך.
תוכלו לעקוב אחר המאמר שלמעלה באמצעות Visual Studio Code בערוץ היוטיוב שלנו. נא לבדוק גם את ערוץ היוטיוב.