`Math` objet

Cet article explique l'objet Math.

Elle explique étape par étape, de l'utilisation de base aux schémas pratiques courants, ainsi que les pièges possibles et les contre-mesures.

YouTube Video

Math objet

L'objet Math de JavaScript fournit un ensemble d'utilitaires intégrés pour les calculs numériques.

Constantes

Les constantes définies dans Math sont utiles pour manipuler des valeurs de haute précision.

Le code suivant montre quelques constantes typiques.

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
  • Ces constantes peuvent être utilisées directement dans les fonctions trigonométriques, les conversions logarithmiques, la normalisation, et plus encore. Par exemple, Math.PI est nécessaire pour convertir des angles en radians.

Arrondis de base et valeurs absolues (abs, floor, ceil, round, trunc)

L'arrondi et la gestion des signes sont fréquemment utilisés, il est donc important de bien comprendre les différences entre Math.floor, Math.ceil et Math.round. En particulier avec les nombres négatifs, les résultats peuvent différer de l'intuition ; il convient donc de faire attention au fonctionnement de chaque règle d'arrondi et de les utiliser correctement.

Les exemples suivants illustrent les différences entre les fonctions d'arrondi.

 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 arrondit vers la valeur inférieure pour les nombres négatifs, donc -3.7 devient -4.
  • Math.ceil arrondit vers la valeur supérieure pour les nombres négatifs, donc -3.7 devient -3.
  • Math.round arrondit à l'unité supérieure pour les nombres positifs se terminant par .5, et pour les nombres négatifs, il arrondit vers zéro.
  • Les nombres négatifs peuvent donner des résultats contre-intuitifs ; il est donc important de bien comprendre dans quelle direction l'arrondi se fait.
  • Les fonctions d'arrondi doivent être choisies selon le cas d'utilisation. Par exemple, utilisez Math.floor pour les calculs d'indice, Math.ceil pour les limites supérieures et Math.trunc lorsque vous souhaitez simplement supprimer la partie décimale.

Multiplication, exponentiation et racines (pow, **, sqrt, cbrt, hypot)

L’exponentiation et les racines carrées peuvent être effectuées avec Math.pow ou avec l’opérateur **. Math.hypot calcule en toute sécurité la racine carrée de la somme des carrés (distance).

Voici des exemples d'exponentiation et de hypot. Math.hypot réduit l'impact des débordements et des sous-dépassements.

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 est utile pour manipuler les côtés d’un triangle ou la longueur de vecteurs multidimensionnels.

Fonctions exponentielles et logarithmiques (exp, log, log10, log2)

Les exponentielles et logarithmes sont fréquemment utilisés en probabilité, décroissance exponentielle et mise à l'échelle.

Voici ensuite des exemples de base de exp et de logarithmes. Veillez à utiliser la fonction adéquate selon la base de logarithme.

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
  • Les logarithmes naturels (Math.log) sont standard en statistiques et dans les équations différentielles. Les logarithmes décimaux et en base 2 sont également choisis selon l’application.

Fonctions trigonométriques (sin, cos, tan, asin, acos, atan2)

Les fonctions trigonométriques sont essentielles pour les calculs d’angle, les rotations et les transformations de coordonnées. Math.atan2(y, x) est utile pour calculer des angles en tenant correctement compte des quadrants.

Vous trouverez ci-dessous des exemples de base et l'utilisation de atan2. Les angles doivent être manipulés en radians.

 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 permet de déterminer l'angle d’un vecteur de façon fiable, il est donc préférable pour les calculs de rotation et d’orientation.

Génération de nombres aléatoires (Math.random et schémas pratiques)

Math.random() renvoie un nombre aléatoire uniformément distribué dans l’intervalle [0, 1). Vous pouvez le convertir ou l’étendre selon vos besoins pour des plages d’entiers ou des distributions normales, par exemple.

Voici des exemples de fonctions utilitaires pour les nombres aléatoires. Si vous avez besoin de nombres aléatoires sécurisés, utilisez 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 est pratique pour un usage général, mais pour la reproductibilité (replays de jeux) ou la cryptographie, il faut prévoir des mesures pour la reproductibilité ou la sécurité.

Aides pratiques (clamp, lerp, mapRange, normalisation d’angle)

Il est utile d'écrire vous-même de petites fonctions utilitaires pour les tâches mathématiques fréquemment utilisées.

Voici des exemples d’implémentation d’utilitaires couramment utilisés.

 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));
  • Ce code regroupe de petites fonctions utilitaires courantes pour les opérations numériques telles que la limitation de valeurs (clamp), l’interpolation, le changement de plage, et la normalisation d’angle. clamp limite une valeur à une plage donnée, tandis que lerp et mapRange servent à l’interpolation douce ou à la conversion vers une autre plage. De plus, normalizeAngle ramène toujours les angles dans l’intervalle [-π, π) pour stabiliser les calculs de rotation.
  • Ces fonctions utilitaires sont fréquemment utilisées en graphisme, jeux ou programmation d’interaction. normalizeAngle est important pour comparer des différences angulaires ou réaliser des interpolations.

Précautions pour les flottants et l'arrondi (précision et comparaison)

Les nombres JavaScript sont des flottants double précision IEEE-754 (64 bits), il est donc nécessaire d’être prudent lors des comparaisons ou des arrondis. Par exemple, 0.1 + 0.2 !== 0.3.

Voici un exemple de traitement des erreurs d’arrondi. Il est important d’utiliser des comparaisons tolérant de petites erreurs, ou des fonctions d’arrondi appropriées.

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
  • Pour des vérifications robustes d’égalité numérique, utilisez une marge d’erreur absolue (eps) ou relative.

Conseils de performance

Les fonctions de Math sont optimisées en natif et sont souvent plus rapides que des logiques équivalentes écrites à la main. Si le même calcul (par exemple, Math.PI / 180) est répété dans une boucle, le stocker dans une variable en amont réduit le surcoût inutile.

Voici un exemple de conversion de degrés en radians en créant une constante en dehors d’une boucle.

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}
  • Il est préférable d’identifier les points chauds avec un profileur avant d’optimiser.
  • Il est efficace de mettre en cache les constantes fréquemment utilisées.

Compatibilité et polyfills

Math existe depuis longtemps, mais certaines fonctions comme Math.cbrt, Math.log10, Math.log2 ou Math.hypot peuvent ne pas être prises en charge dans les anciens environnements. Préparez un polyfill simple si nécessaire.

Voici un exemple de polyfill simple pour 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));

Beaucoup d’environnements les supportent déjà, mais vérifiez la compatibilité si nécessaire.

Vérifiez la prise en charge des navigateurs selon l’environnement visé de votre projet.

Exemple pratique : mises à jour par pas de temps dans une simulation physique simple

Enfin, voici un exemple pratique combinant plusieurs fonctions Math. Ceci est un exemple très simple pour la mise à jour de la position, de la vitesse et du contrôle d’angle.

C’est un modèle très simplifié d’un moteur physique.

 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);
  • En combinant ce type d’aides Math, la logique de simulation et d’animation peut être simplifiée.

Résumé

  • Math couvre tout, des constantes et des fonctions de base jusqu’aux fonctions avancées ; il constitue la base du traitement numérique.
  • Choisissez les fonctions selon leur objectif, qu’il s’agisse de nombres aléatoires, de fonctions trigonométriques, d’exponentielles/logarithmes ou d’arrondi ; et créez de petits utilitaires tels que clamp ou lerp pour un usage pratique.
  • Faites attention à la précision des flottants et au support de votre environnement cible, et prévoyez une tolérance d’erreur ou un polyfill si besoin.

Vous pouvez suivre l'article ci-dessus avec Visual Studio Code sur notre chaîne YouTube. Veuillez également consulter la chaîne YouTube.

YouTube Video