Есть ли способ правильно умножить два 32-битных целых числа в Javascript?

есть ли способ правильно умножить два 32-битных целых числа в Javascript?

когда я пробую это с помощью C long long Я получаю это:

printf("0x%llx * %d = %llxn", 0x4d98ee96ULL, 1812433253,
      0x4d98ee96ULL * 1812433253);
==> 0x4d98ee96 * 1812433253 = 20becd7b431e672e

но из Javascript результат отличается:

x = 0x4d98ee97 * 1812433253;
print("0x4d98ee97 * 1812433253 = " + x.toString(16));
==> 0x4d98ee97 * 1812433253 = 20becd7baf25f000

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

есть ли способ получить правильный ответ? (Я использую Mozilla js-1.8.5 на x86_64 Fedora 15 в случае, если это вопросы.)

5 ответов


это, кажется, делает то, что я хотел без внешней зависимости:

function multiply_uint32(a, b) {
    var ah = (a >> 16) & 0xffff, al = a & 0xffff;
    var bh = (b >> 16) & 0xffff, bl = b & 0xffff;
    var high = ((ah * bl) + (al * bh)) & 0xffff;
    return ((high << 16)>>>0) + (al * bl);
}

это выполняет 32-разрядное умножение по модулю 2^32, которое является правильной нижней половиной вычисления. Аналогичная функция может использоваться для вычисления правильной верхней половины и хранения ее в отдельном целочисленном числе (ah * bh кажется правильным), но мне это не нужно.

обратите внимание на нулевой сдвиг. Без этого функция генерирует отрицательные значения всякий раз, когда установлен высокий бит.


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

например, BigInt.js:http://www.leemon.com/crypto/BigInt.js


С форум пост:

нет необходимости делать номера маленькими, это только важно сохранить количество значащих цифр ниже 53

function mult32s(n, m) //signed version
{
    n |= 0;
    m |= 0;
    var nlo = n & 0xffff;
    var nhi = n - nlo;
    return ( (nhi * m | 0) + (nlo * m) ) | 0;
}

function mult32u(n, m) //unsigned version
{
    n >>>= 0;
    m >>>= 0;
    var nlo = n & 0xffff;
    var nhi = n - nlo;
    return ( (nhi * m >>> 0) + (nlo * m) ) >>> 0;
}

и | и >>> операторы приводят к преобразованию результата в 32-разрядное целое число. В первом случае он преобразуется в целое число со знаком, во втором-в целое число без знака.

в строке умножения первого | / >>> оператор вызывает 64-разрядный промежуточный результат с 48-битный significand (в форме 0x NNNN NNNN NNNN 0000), чтобы отбросить его более высокие биты, поэтому промежуточный результат в виде 0x NNNN 0000.
второй | / >>> оператор приводит к тому, что результат второго умножения и сложения ограничивается 32 битами.

в случае, если один из множителей является константой, вы можете упростить умножение дальше:

function mult32s_with_constant(m) //signed version
{
    m |= 0
    //var n = 0x12345678;
    var nlo = 0x00005678;
    var nhi = 0x12340000;
    return ( (nhi * m | 0) + (nlo * m) ) | 0;
}

или, если вы знаете, что результат будет меньше 53 бит, тогда вы можете сделать просто:

function mult32s(n, m) //signed version
{
    n |= 0;
    m |= 0;
    return ( n * m ) | 0;
}

Вы правы. Целые числа Javascript рассматриваются как поплавки, которые имеют низкую точность при работе с ints.

в javascript это так, что 10000000000000001%2 == 0

друг, также упоминает о том, что 10000000000000001 == 10000000000000000, и что это действительно связано со спецификацией (хотя ints используются для оптимизации, спецификация по-прежнему требует float-подобного поведения).

хотя, как только вы находитесь на этой территории, вы уже почти на пределе точности 64bit int.


GWT имеет эмуляцию Java (64-разрядного) знакового длинного целочисленного типа. Я сделал для него интерфейс JavaScript,вот демо. Используя номера по умолчанию, вы можете видеть, что значение такое же, как и в C.

шестнадцатеричное значение в столбце "эмуляция" должно соответствовать тому, что вы видите в своем отладчике, но могут возникнуть проблемы с шестнадцатеричным представлением, так как я использую собственный JavaScript для его создания. Конечно, это можно сделать и в GWT, что возможно, так будет правильнее. Если номер JavaScript может представлять все строковые представления, которые генерирует GWT, шестнадцатеричное представление также должно быть правильным. Посмотрите в источнике для использования. Причина, по которой они ({sub,mod,div,mul}ss) принимают строки, заключается в том, что я не знаю, как сделать длинный объект GWT из JavaScript.