2013-11-24 6 views
5

これはLua自体のバグか、何か間違っていたかどうかわかりませんでした。私はどこでもそれについて何も見つけることができませんでした。私はWindows用のLua(ルア5.1.4)を使用しています:"間隔が空です"、Lua math.randomは大きな数値では機能していませんか?

>return math.random(0, 1000000000) 
1251258 

予想通りこれは、0と10000000000の間のランダムな整数を返します。これは他のすべての値に対しても機能するようです。しかし、私が単一のものを追加した場合0:

>return math.random(0, 10000000000) 
stdin:1: bad argument #2 to 'random' (interval is empty) 

それ以上の数字は同じものをします。

私は数がこれを引き起こすことがあることを持っている正確にどのように高を把握しようとしたとしても奇妙なものが見つかりました:値が2147483647である場合、それは私に負の数を与える

>return math.random(0, 2147483647) 
-75617745 

を。それよりも高いとエラーをスローします。それより低くてもうまく動作します。

0b1111111111111111111111111111111はバイナリで、正確には2進数で31バイナリです。私はそれが何を意味するかは分かりません。

答えて

7

この予期しない動作(バグ?)は、math.randomがLua 5.1で渡された入力引数を処理する方法によるものです。 lmathlib.cから:あなたがCに知っている可能性

case 2: { /* lower and upper limits */ 
    int l = luaL_checkint(L, 1); 
    int u = luaL_checkint(L, 2); 
    luaL_argcheck(L, l<=u, 2, "interval is empty"); 
    lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */ 
    break; 
} 

として、標準int2,147,483,647に値-2,147,483,648を表すことができます。 +12,147,483,647に追加することは、使用例の場合と同様に、オーバーフローし、を囲み、-2,147,483,648という値を返します。正の値に負の数を掛けているため、最終結果は負の値になります。

さらに、2,147,483,647を超えるものは、オーバーフローラップアラウンドのためにluaL_argcheckに失敗します。 Luaの5.2へ

  • アップグレード:

    は、この問題に対処するには、いくつかの方法があります。この問題は、入力引数をlua_Numberとして扱うことで修正されています。

  • この整数オーバーフローの問題を持たないLuaJITに切り替えます。
  • 修正プログラムでLua 5.1のソースをパッチして再コンパイルします。
  • オーバーフローしないようにランダムな範囲を変更します。
4

ランダム関数がサポートする範囲(32ビット符号付き整数または符号ビットにより2^31)が必要ですが、math.randomはCレベルであるため、ルア「数字」タイプ(What is the maximum value of a number in Lua?、2^52、または2^53に基づく)では、2つの乱数を生成することができます。 "ギャップを埋める"に2番目を追加してください。たとえば、範囲を0〜2^36としたいとします。 math.randomから最大のものは2^31です。だから、何ができる:

-- 2^36 = 2^31 * 2^5 so 
scale = 2^5 
baseRand = scale * math.random(0, 2^31) 
-- baseRand is now between 0 and 2^36 but there are gaps of 2^5 in the set 
-- of possible values; fill the gaps with second random number: 
fillGap = math.random(0, 2^5) 
randNum = baseRand + fillGap 

これは限り所望の範囲は、Luaの数値のためのLuaインタプリタの最大値未満であると、設定コンパイル時のパラメータであるが、あなたはそれを構築株式を使用する場合は、2^52で動作します、非常に大きな数(最大の長い整数、2^63ほど大きくはないが)。

また、最大正のNビット整数は2^N-1(2^Nではありません)ですが、上記の手法はどの範囲にも適用できます。たとえば、スケール= 10^6、randNum = 10^6 * math.random(0、10^8)+ math.random(0、10^6)。

関連する問題