`Объект` 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 снижает влияние переполнения и потери точности.

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 ограничивает значение заданным диапазоном, а lerp и mapRange выполняют плавную интерполяцию или преобразование диапазона. Кроме того, normalizeAngle всегда нормализует углы в диапазон [-π, π) для стабильных вычислений вращения.
  • Эти вспомогательные функции часто используются в графике, играх и интерактивном программировании. normalizeAngle важен для сравнения угловых разностей и интерполяции.

Особенности работы с плавающей точкой и округлением (точность и сравнение)

Числа в JavaScript представляют собой 64-битные значения с плавающей точкой по стандарту IEEE-754, поэтому при сравнении или округлении нужна осторожность. Например, 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.
  • Обращайте внимание на точность чисел с плавающей запятой и поддержку функций в вашей целевой среде, а при необходимости закладывайте устойчивость к ошибкам или используйте полифиллы.

Вы можете следовать этой статье, используя Visual Studio Code на нашем YouTube-канале. Пожалуйста, также посмотрите наш YouTube-канал.

YouTube Video