Jen se snažím implementovat jednoduchý RNG v JS.
Děje se tak, že javascript vyhodnotí 119106029 * 1103515245
být 131435318772912110
spíše než 131435318772912105
. Víme, že je to špatně, protože dvě lichá čísla vynásobená nedávají sudé číslo.
Ví někdo, co se děje? Chci jen spolehlivý opakovatelný RNG a kvůli těmto nesprávným hodnotám nemohu získat výsledky, které by odpovídaly mé implementaci C stejné věci.
Odpověď
Podle standardu ECMAScript jsou všechna čísla v JavaScriptu (64bitový IEEE 754) standardně čísly s pohyblivou řádovou čárkou.
Všechna 32bitová celá čísla však mohou být přesně reprezentována jako čísla s plovoucí desetinnou čárkou. Výsledek můžete vynutit na 32 bitů pomocí příslušného bitového operátoru, jako je tento:
x = (a * b) >>> 0; // force to unsigned int32 x = (a * b) | 0; // force to signed int32
Divné, ale takový je standard.
(Toto chování zaokrouhlování je mimochodem jednou z nejčastěji hlášených „chyb“ proti JavaScriptovému enginu Firefoxu. Vypadá to, že letos bylo hlášeno zatím třikrát…)
Pokud chcete skutečnou celočíselnou matematiku, můžete použít BigInt
hodnoty, jiný typ čísla, zapsaný s n
na konci:
> 119106029n * 1103515245n 131435318772912105n
Toto je relativně nedávná funkce JS a nemusí být implementována ve starých prohlížečích.
Pokud jde o reprodukovatelná náhodná čísla v JavaScriptu, benchmark V8 používá toto:
// 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; }; })();