Есть ли способ правильно умножить два 32-битных целых в Javascript? - PullRequest
6 голосов
/ 04 июня 2011

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

Когда я пытаюсь это из C, используя long long, я получаю это:

printf("0x%llx * %d = %llx\n", 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 ]

10 голосов
/ 21 июня 2011

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

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, которое является правильной нижней половиной вычисления. Подобную функцию можно использовать для вычисления правильной верхней половины и сохранения ее в отдельном целом числе (ах * чч кажется правильным), но мне это не нужно.

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

5 голосов
/ 26 января 2015

Из сообщения на форуме :

нет необходимости делать цифры маленькими, это только важно сохранить количество значащих цифр ниже 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-битным значением и (в форме 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;
}
5 голосов
/ 04 июня 2011

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

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

3 голосов
/ 04 июня 2011

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

В javascript, это тот случай, когда 10000000000000001%2 == 0

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

Хотя, оказавшись на этой территории, вы уже почти достигли предела точности 64 бита.

0 голосов
/ 24 августа 2012

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

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

...