Imul: примеры (JAVASCRIPT)
imul(a, b): numberОписание функции Math.imul()
Функция Math.imul() возвращает результат 32-битного умножения двух целых чисел с семантикой, аналогичной операции умножения в языке C. Она принимает два аргумента, которые приводятся к 32-битным целым числам со знаком. Основное предназначение – работа с 32-битной целочисленной арифметикой, что может быть полезно для таких областей, как графика, криптография или эмуляция низкоуровневых операций.
Аргументы функции: a и b. Оба являются числами. Если аргументы не числа, они будут преобразованы в числа. Затем значения отбрасывают дробную часть и приводятся к 32-битному целому числу со знаком, которое находится в диапазоне от -2147483648 до 2147483647.
Возвращаемое значение: 32-битное целое число со знаком, представляющее собой произведение переданных аргументов. Если результат умножения не помещается в 32 бита, происходит переполнение, и возвращаются только младшие 32 бита (как в C).
Простое использование
Функция обычно применяется с двумя числовыми аргументами.
console.log(Math.imul(2, 4));8
Пример с отрицательными числами.
console.log(Math.imul(-2, 4));-8
При переполнении возвращаются младшие 32 бита.
// 0xFFFFFFFF * 0xFFFFFFFF (в десятичной системе: -1 * -1)
console.log(Math.imul(0xFFFFFFFF, 0xFFFFFFFF));1
Альтернативы в JavaScript
В JavaScript для умножения обычно используется оператор *.
Отличия от Math.imul():
- Обычное умножение (*): Работает с числами двойной точности (64-битными с плавающей точкой). Это стандартный способ умножения любых чисел. Используется в подавляющем большинстве случаев.
- Math.imul(): Выполняет 32-битное целочисленное умножение с семантикой C (возвращает младшие 32 бита). Полезно для эмуляции 32-битной целочисленной арифметики, оптимизации или побитовых вычислений.
Выбор зависит от задачи: для точных математических расчётов с плавающей точкой используется *, а для низкоуровневых операций, где требуется определённое поведение при переполнении, — Math.imul().
Аналоги в других языках
В различных языках существуют операции или функции с похожим поведением.
C/C++: Оператор * между 32-битными целыми типами (например, int32_t) работает аналогично, с переполнением, если результат не помещается в тип.
int32_t a = 0x7FFFFFFF;
int32_t b = 2;
int64_t c = (int64_t)a * b; // Для избежания переполнения
int32_t d = a * b; // Произойдёт переполнениеPython: По умолчанию целые числа имеют произвольную точность и не переполняются. Для получения аналогичного Math.imul() поведения можно использовать & с маской.
def imul(a, b):
return (a * b) & 0xFFFFFFFF
print(imul(0xFFFFFFFF, 0xFFFFFFFF))1
PHP: Оператор * для целых чисел. Переполнение целого приводит к преобразованию в число с плавающей точкой. Для 32-битного умножения можно использовать intval($a * $b) & 0xFFFFFFFF.
echo intval(0xFFFFFFFF * 0xFFFFFFFF) & 0xFFFFFFFF;1
MySQL: Оператор *. Поведение при переполнении зависит от режима SQL. Чаще всего происходит обрезка до границ типа.
Распространённые ошибки
Ожидание точных больших чисел: Если не учитывать 32-битное ограничение, результат может быть неожиданным.
// Обычное умножение
console.log(0x7FFFFFFF * 2); // 4294967294
// Math.imul - переполнение
console.log(Math.imul(0x7FFFFFFF, 2));-2
Использование с числами с плавающей точкой: Дробная часть отбрасывается до умножения.
console.log(Math.imul(2.9, 3.9));6 // Аргументы приводятся к 2 и 3
Неявное приведение типов: Может привести к NaN.
console.log(Math.imul('a', 2));0 // 'a' преобразуется в NaN, но при целочисленном преобразовании NaN становится 0
История изменений
Функция Math.imul() была стандартизирована в спецификации ECMAScript 6 (ES6/ES2015). С момента добавления её поведение не изменялось. До ES6 она не существовала, и для её эмуляции требовалось написание собственной функции, например, с использованием побитовых операций.
Специфические примеры
Эмуляция 64-битного умножения двух 32-битных чисел с получением высокого и низкого слов.
function mul32to64(a, b) {
const aHigh = a >> 16 & 0xFFFF;
const aLow = a & 0xFFFF;
const bHigh = b >> 16 & 0xFFFF;
const bLow = b & 0xFFFF;
const lowLow = Math.imul(aLow, bLow);
const highLow = Math.imul(aHigh, bLow);
const lowHigh = Math.imul(aLow, bHigh);
const highHigh = Math.imul(aHigh, bHigh);
const low = lowLow;
const high = highHigh + (highLow >>> 16) + (lowHigh >>> 16);
return [high, low];
}
let [high, low] = mul32to64(0xFFFFFFFF, 0xFFFFFFFF);
console.log('High:', (high >>> 0).toString(16), 'Low:', (low >>> 0).toString(16));High: fffffffe Low: 1
Использование для оптимизации, когда известно, что числа 32-битные.
// В циклах при работе с массивами 32-битных целых
function sumOfProducts(arrA, arrB) {
let sum = 0;
for (let i = 0; i < arrA.length; i++) {
sum += Math.imul(arrA[i], arrB[i]);
}
return sum;
}
console.log(sumOfProducts([1, 2, 3], [4, 5, 6]));32
Работа с цветами в формате RGBA.
function blendAlpha(c1, c2, alpha) {
// alpha от 0 до 255
const invAlpha = 255 - alpha;
const r = (Math.imul(c1 >> 24 & 0xFF, invAlpha) + Math.imul(c2 >> 24 & 0xFF, alpha)) >> 8;
const g = (Math.imul(c1 >> 16 & 0xFF, invAlpha) + Math.imul(c2 >> 16 & 0xFF, alpha)) >> 8;
const b = (Math.imul(c1 >> 8 & 0xFF, invAlpha) + Math.imul(c2 >> 8 & 0xFF, alpha)) >> 8;
const a = (Math.imul(c1 & 0xFF, invAlpha) + Math.imul(c2 & 0xFF, alpha)) >> 8;
return (r << 24) | (g << 16) | (b << 8) | a;
}
console.log(blendAlpha(0xFF0000FF, 0x00FF00FF, 128).toString(16));7f7f00ff