JavaScript Integer математические неверные результаты - PullRequest
3 голосов
/ 07 августа 2010

Я просто пытаюсь реализовать простой RNG в JS.

Что происходит, так это то, что javascript оценивает 119106029 * 1103515245 как 131435318772912110, а не 131435318772912105. Мы знаем, что это неправильно, поскольку умножение двух нечетных чисел не дает четного числа.

Кто-нибудь знает, что случилось? Мне просто нужен надежный повторяемый ГСЧ, и из-за этих неправильных значений я не могу получить результаты, совпадающие с моей реализацией на C того же самого.

Ответы [ 3 ]

17 голосов
/ 07 августа 2010

В соответствии со стандартом ECMAScript все числа в JavaScript являются (64-разрядными IEEE 754) числами с плавающей запятой.

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

x = (a * b) >>> 0;  // force to unsigned int32
x = (a * b) | 0;    // force to signed int32

Странно, но это стандарт.

(Между прочим, это поведение округления одна из наиболее часто сообщаемых "ошибок" в движке JavaScript Firefox. Похоже, об этом уже было сообщено 3 раза в этом году ...)

Что касается воспроизводимых случайных чисел в JavaScript, тест V8 использует это:

// To make the benchmark results predictable, we replace Math.random
// with a 100% deterministic alternative.
Math.random = (function() {
  var seed = 49734321;
  return function() {
    // Robert Jenkins' 32 bit integer hash function.
    seed = ((seed + 0x7ed55d16) + (seed << 12))  & 0xffffffff;
    seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
    seed = ((seed + 0x165667b1) + (seed << 5))   & 0xffffffff;
    seed = ((seed + 0xd3a2646c) ^ (seed << 9))   & 0xffffffff;
    seed = ((seed + 0xfd7046c5) + (seed << 3))   & 0xffffffff;
    seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
    return (seed & 0xfffffff) / 0x10000000;
  };
})();
3 голосов
/ 07 августа 2010

Когда целое число в javascript слишком велико, чтобы поместиться в 32-битное значение, некоторые браузеры преобразуют его в число с плавающей запятой.Поскольку значения с плавающей запятой сохраняются только с ограниченной точностью, при больших значениях может происходить некоторое округление.

1 голос
/ 07 августа 2010

Если сделано в C / C ++ (double), последние цифры будут ... 112 вместо 105 (что правильно). Если выполняется с 'long double', результат будет таким, как ожидалось (... 105). Так выглядит Интерпретатор Javascript преобразует числа в 8-байтовые числа внутренне, делает расчет и делает некоторое неизвестное округление что приводит к чуть лучшему результату, чем стандарт C / C ++ двойной расчет.

GCC 4.5:

 int main(int argc, char** argv)
{
 long double a = 119106029;
 long double b = 1103515245;
 long double c = a * b;
 printf("%.Lf\n", c);

 return 0;
}

Результат:

131435318772912105

Ожидаемый:

131435318772912105

Так что я не вижу шансов в Javascript без помощь библиотеки BIGNUM (если есть).

Привет

БВУ

...