6

Math.random()は[0,1)の範囲の64ビット浮動小数点数を生成するようですが、新しいcrypto.getRandomValues()APIはintのみを返します。このAPIを使用して[0,1)の数値を生成する理想的な方法は何でしょうか。

これは機能しているように見えますが、最適ではないようです。

ints = new Uint32Array(2)
window.crypto.getRandomValues(ints)
return ints[0] / 0xffffffff * ints[1] / 0xffffffff

編集:明確にするために、私はMath.random()よりも良い結果を生成しようとしています。浮動小数点の私の理解から、52ビットのランダム性に対して完全にランダムな分数を取得することが可能であるはずです。(?)

編集2:もう少し背景を説明するために、暗号的に安全なことは何もしようとはしていませんが、Math.random()の実装が不十分であるという事例がたくさんあります(例:http: //devoluk.com/google-chrome -math-random-issue.html)なので、より良い代替手段が利用できる場合は、それを使用したいと思います。

4

3 に答える 3

7

浮動小数点数は単なる仮数係数であり、2 を指数に累乗したものであることに注意してください。

floating_point_value = mantissa * (2 ^ exponent)

を使用Math.randomすると、32 ビットのランダムな仮数を持ち、常にの指数を持つ浮動小数点が生成されます-32。したがって、小数点以下の桁数は左に 32 桁にビット シフトされるため、仮数は小数点以下の桁の左側には決してありません。

mantissa =         10011000111100111111101000110001 (some random 32-bit int)
mantissa * 2^-32 = 0.10011000111100111111101000110001

数回実行Math.random().toString(2)して、これが事実であることを確認してください。

解決策:ランダムな 32 ビットの仮数を生成し、次のように掛けることができますMath.pow(2,-32)

var arr = new Uint32Array(1);
crypto.getRandomValues(arr);
var result = arr[0] * Math.pow(2,-32);
// or just   arr[0] * (0xffffffff + 1);

浮動小数点には均等な分布がないことに注意してください (仮数の精度が不足しているため、可能な値は数が大きくなるほどまばらになります)、非常に強力な乱数を必要とする暗号化アプリケーションやその他のドメインには適していません。 . そのためには、 によって提供される生の整数値を使用する必要がありますcrypto.getRandomValues()

編集:

JavaScript の仮数部は 52 ビットであるため、52 ビットの乱数を得ることができます。

var arr = new Uint32Array(2);
crypto.getRandomValues(arr);

// keep all 32 bits of the the first, top 20 of the second for 52 random bits
var mantissa = (arr[0] * Math.pow(2,20)) + (arr[1] >>> 12)

// shift all 52 bits to the right of the decimal point
var result = mantissa * Math.pow(2,-52);

つまり、全体として、いいえ、これはあなた自身のソリューションよりも短くはありませんが、それがあなたが望むことができる最善の方法だと思います. 32 ビット ブロックから構築する必要がある 52 のランダム ビットを生成し、1 未満に戻す必要があります。

于 2012-12-04T01:42:53.267 に答える
0

これは、[0,1) の範囲の数値が本当に必要な場合に最適です。

そのコードの問題は、異なる番号のオッズがもはや同じではないことです。

そのコードでは、たとえば、1 (1*1) よりも 0.5 (1*0.5,0.5*1,0.75*0.666) を取得する可能性が高くなります。

于 2012-12-04T01:23:07.970 に答える