Learn JavaScript

Math.imul() - метод для 32-битного целочисленного умножения в JavaScript

Math.imul() выполняет 32-битное целочисленное умножение.

Проще всего запомнить так: это не обычное умножение чисел JavaScript, а умножение так, как если бы оба значения были 32-битными целыми числами.

Именно поэтому Math.imul() иногда даёт результат, который отличается от обычного *.

Синтаксис

Math.imul(a, b)
  • a - первое значение
  • b - второе значение

Оба аргумента сначала приводятся к 32-битным целым числам, а потом перемножаются.

Что делает Math.imul()

Метод умножает два значения как 32-битные целые числа.

console.log(Math.imul(2, 4));   // 8
console.log(Math.imul(-1, 8));  // -8
console.log(Math.imul(-1, -1)); // 1

Это значит:

  • Math.imul(2, 4) даёт 8
  • Math.imul(-1, 8) даёт -8
  • Math.imul(-1, -1) даёт 1

На небольших значениях результат часто совпадает с обычным *.

Что возвращает Math.imul()

Math.imul() возвращает значение типа number.

const result = Math.imul(6, 7);

console.log(result);        // 42
console.log(typeof result); // "number"

Но важно понимать: по смыслу это число интерпретируется как результат 32-битного целочисленного умножения.

Чем Math.imul() отличается от обычного *

Это главный смысл метода.

Обычный оператор * работает с обычными числами JavaScript.

Math.imul() работает с 32-битными целыми числами и учитывает переполнение.

Пример:

console.log(0xffffffff * 5);       // 21474836475
console.log(Math.imul(0xffffffff, 5)); // -5

Ещё пример:

console.log(0x7fffffff * 2);       // 4294967294
console.log(Math.imul(0x7fffffff, 2)); // -2

То есть:

  • * считает обычное число
  • Math.imul() считает результат в рамках 32-битного целого диапазона

Почему появляются странные отрицательные результаты

Это связано с переполнением 32-битного целого числа.

Например:

console.log(Math.imul(0x7fffffff, 2)); // -2

Хотя математически результат должен быть 4294967294, в 32-битном знаковом формате это значение интерпретируется как -2.

Это не ошибка метода. Это его нормальное поведение.

На обычных числах всё выглядит привычно

Если значения небольшие, результат обычно совпадает с обычным умножением.

console.log(123456 * 789);         // 97406784
console.log(Math.imul(123456, 789)); // 97406784

Поэтому разница заметна не всегда, а в основном там, где важна именно 32-битная арифметика.

Аргументы сначала приводятся к 32-битным целым числам

Это самый важный нюанс при работе с Math.imul().

Метод не умножает аргументы как есть. Сначала оба значения приводятся к 32-битным целым числам.

Из-за этого некоторые результаты могут удивлять.

Дробные числа

Дробные значения сначала отбрасывают дробную часть.

console.log(Math.imul(1.9, 4)); // 4
console.log(Math.imul(0.5, 8)); // 0

Здесь важно понимать:

  • 1.9 превращается в 1
  • 0.5 превращается в 0

И уже после этого выполняется умножение.

Большие числа

Очень большие значения тоже могут вести себя неожиданно, потому что метод работает только с 32 битами.

console.log(Math.imul(4294967296, 2)); // 0

Здесь число выходит за пределы 32-битного диапазона и после преобразования становится 0, поэтому итог тоже 0.

Отрицательные значения

С отрицательными числами метод работает нормально, но всё равно в рамках 32-битной арифметики.

console.log(Math.imul(-1, 8));   // -8
console.log(Math.imul(-1, -8));  // 8
console.log(Math.imul(-1, -1));  // 1

Что происходит с 0

Если один из аргументов после преобразования становится 0, результат тоже будет 0.

console.log(Math.imul(0, 5));   // 0
console.log(Math.imul(-0, 5));  // 0
console.log(Math.imul(0.5, 8)); // 0

Это полезно помнить: Math.imul() не сохраняет -0 как отдельный результат.

Без аргументов

Если вызвать Math.imul() без аргументов, результатом будет 0.

console.log(Math.imul()); // 0

Если передать только один аргумент, результат тоже будет 0.

console.log(Math.imul(5)); // 0

Это может показаться неожиданным, особенно если вы привыкли, что многие методы Math без аргументов дают NaN.

Неявное приведение типов

Math.imul() сначала пытается привести аргументы к числам, а затем к 32-битным целым.

console.log(Math.imul("5", "6")); // 30
console.log(Math.imul(null, 4));  // 0
console.log(Math.imul(true, 4));  // 4
console.log(Math.imul(undefined, 4)); // 0

На практике лучше передавать в метод уже готовые числа.

Массивы и странные значения

Из-за приведения типов некоторые значения могут вести себя неочевидно.

console.log(Math.imul([], 4));     // 0
console.log(Math.imul([5], 4));    // 20
console.log(Math.imul([1, 2], 4)); // 0

Это ещё одна причина, почему лучше не полагаться на неявное преобразование.

NaN и Infinity

Для специальных значений результат будет таким:

console.log(Math.imul(NaN, 4));       // 0
console.log(Math.imul(Infinity, 4));  // 0
console.log(Math.imul(-Infinity, 4)); // 0

Это важно помнить:

  • NaN даёт 0
  • Infinity даёт 0
  • -Infinity даёт 0

Причина в том, что после преобразования эти значения становятся 0 в 32-битном формате.

Math.imul() и побитовые операции

Math.imul() особенно полезен рядом с побитовыми операциями и низкоуровневой логикой.

Например, в хеш-функциях или алгоритмах, где важно точно повторять 32-битную арифметику.

Это как раз тот случай, где обычный * может быть не тем, что нужно.

Числа не меняются

Math.imul() не изменяет исходные значения. Он только возвращает новый результат.

const a = 6;
const b = 7;
const result = Math.imul(a, b);

console.log(a);      // 6
console.log(b);      // 7
console.log(result); // 42

Когда это полезно

Math.imul() удобно использовать, когда:

  • нужна именно 32-битная целочисленная арифметика
  • вы работаете с побитовыми операциями
  • пишете хеши, генераторы или низкоуровневые алгоритмы
  • важно предсказуемое переполнение как у 32-битных целых чисел

Пример:

const value = Math.imul(0xffffffff, 5);

console.log(value); // -5

Для обычной бизнес-логики чаще хватает *, но для низкоуровневых вычислений Math.imul() бывает очень полезен.

Частые ошибки

Думать, что это обычное умножение

console.log(0xffffffff * 5);         // 21474836475
console.log(Math.imul(0xffffffff, 5)); // -5

Math.imul() - это не замена *, а отдельный инструмент для 32-битной арифметики.

Забывать про преобразование к целому числу

console.log(Math.imul(1.9, 4)); // 4

Дробная часть здесь не участвует в вычислении.

Ожидать NaN для undefined или Infinity

console.log(Math.imul(undefined, 4)); // 0
console.log(Math.imul(Infinity, 4));  // 0

Из-за 32-битного преобразования здесь получится 0, а не NaN.

Быстрая памятка

  • Math.imul(a, b) делает 32-битное целочисленное умножение
  • метод возвращает number
  • результат может отличаться от обычного *
  • перед умножением аргументы приводятся к 32-битным целым
  • дробные части отбрасываются
  • большие числа могут переполняться
  • Math.imul() особенно полезен для побитовой и низкоуровневой логики
  • NaN, Infinity и undefined после преобразования часто дают 0

Коротко

Math.imul() - это стандартный способ выполнить 32-битное целочисленное умножение в JavaScript. Главное, что нужно запомнить: метод работает не как обычный *, а как умножение в рамках 32-битной арифметики, поэтому может давать переполнение, отбрасывать дробную часть и возвращать результаты, которые на первый взгляд кажутся неожиданными.