アプリケーションユーザーがトレーニングするための疑似ランダムデータセットを作成しています。
Rand()関数に1、2、3などをシードすると、シードされた関数からほぼ同じ結果が得られることに驚いています。ただし、シードが指定されていない場合、これには「適切にランダム」であるが反復可能な値が続くようです。
SELECT Rand(1) AS R1A, Rand() AS R1B, Rand(2) AS R2A, Rand() AS R2B,
Rand(3) AS R3A, Rand() AS R3B, Rand(4) AS R4A, Rand() AS R4B
0.713591993212924
0.472241415009636
0.713610626184182
0.217821139260039
0.71362925915544
0.963400850719992
0.713647892126698
0.708980575436056
一見すると、Rand(@seed)を評価して結果を破棄し、Rand()を評価してトレーニングデータのいくつかの本当に「ランダムな」数値を取得できるようです-これまでのところ、レコードごとに4つ使用する予定でした。もう少し必要になるかもしれません。
その計画は適切に機能しますか?そして、私はここで何を見ていますか?そして、それはドキュメントにあるべきですか?見つかりませんでした。
ドキュメンテーションはこれを手がかりとして意味するかもしれないと言います:
Rand関数は、CランタイムライブラリのRand関数と同様の方法で動作する疑似乱数ジェネレーターです。シードが指定されていない場合、システムは独自の変数シード番号を生成します。
CのRand関数は、同様のシード入力に対して同様の出力を生成しますか?
Rand(@number)の後にRand()が続くと常に同じ数が生成されることもドキュメントに明記できると思います。しかし、それが私が望んでいたことであり、経験豊富なコンピュータープログラマーが期待することです。
https://www.random.org/ から取得したランダムなデータキーをテーブルに入力して目的に使用できると思いますが、これには欠点があります。
私はRand()について次の結論を出しました。今のところ、私はそれを続けると思いますが、代替案を念頭に置いてください。
Rand(@int)は、指定された整数値を使用して乱数ジェネレータのシードを設定し、統計的に独立したnotであるfloat結果を返します。 Rand(@int)とRand(@ int + 1)はほぼ同じ結果を生成します。
もちろん、Rand(@int)は常に同じ結果を生成します。
Rand(-@ int)とRand(@int)は同じ結果になります。
Rand(0)は例外です。他の例外がある可能性があります。 Rand(0)は常に結果0.943597390424144を生成しますが、Rand(1)の結果とは異なります。
Rand(@int)の後にn回呼び出されたRand()は、常に同じn個の数値を生成します。 n番目の番号を「Rand(@int、@n)」とすると、
CREATE PROCEDURE sproc_Rand(@seed int, @nth int, @Rand float OUTPUT) AS
SET @Rand = Rand(@seed);
WHILE ( @nth > 0 ) BEGIN SET @Rand = Rand(); SET @nth = @nth - 1; END
Rand(@int、@n)とRand(@ int + 1、@n) "modulo 1"の違い-
(1.0 + Rand(@int, @n) - Rand(@int+1, @n) % 1
一定またはほぼ一定です。 @n = 1の場合、約0.75です。 @n = 5の場合、0.991です。 @n = 6の場合、0.91です。 @n = 100の場合、0.83です。
したがって、いいえ、単純なインクリメントシードが使用されている場合、これらは良い「ランダムな」数値ではありません。
緩和策として現在検討しているのは、Rand(row_id)ではなく、
Rand(row_id * @factor_1 + @factor_2)
ここで、@ factor1と@ factor2は定数項であり、@ factor_1は約10,000です。そして、異なるプロジェクトのために、異なる要因。
これまでのところ、繰り返し可能な結果が必要な場合、(まだ理解していない乗法逆数以外の)使用可能な他の方法は、テーブルを作成して、他の方法の1つからの非反復乱数で埋めることです。次に、必要に応じて、そのテーブルから数値を引き出します。
everがRand()
に「シード」を提供する唯一の理由は、テストのために(疑似)ランダム値のまったく同じシーケンスが必要な場合です。
シードなしで呼び出すだけで、ほとんどの目的には十分です。
do予測可能なシーケンスが必要で、開始(ランダム)値に単に不満がある場合、Rand()
は-2,147,483,648からシードを取得します2,147,483,647(intのフルレンジ)までなので、1または2以上異なるシードを試してください。
最後に、SQL 2008以降を使用している場合、代わりに CRYPT_GEN_RANDOM を検討するオプションもあります(警告、それは浮動小数点数ではなくvarbinaryを返すため、コードを少し変更する必要がある可能性があります): この記事のいくつかの違いと説明を参照 。
はい、シードを使用してRand()
を呼び出すと、SQL Serverのすべての/ほとんどのバージョンで同じ結果が生成されます。 SQL Server 2012でテストしたところ、問題と同じ結果が得られました。また、以下を実行すると、グループに少なくとも1つのRand()
が存在する場合でも、シードのない任意の数のRand(<seed>)
が毎回同じ結果を生成することがわかります。それらが別々のバッチにある場合:
SELECT Rand(), Rand(2), Rand(), Rand(),
Rand();
GO
SELECT Rand(), Rand();
-- 0.302870228294199 0.713610626184182 0.217821139260039 0.570956802191052
-- 0.213689267406154
-- 0.68442381362486 0.201630044636296
ただし、次のような疑似乱数を探している場合:
次に、Modular Multiplicative Inverses(MMI)の使用方法を確認する必要があります。これについては、次のStackOverflowの質問に対する回答で詳しく説明します。
この手法も非常に高速で、事前生成を必要としません(つまり、ランダムセットを保存する必要がありません)。また、SQL Serverの以前のバージョン(2000および2005)でも機能しますが、CRYPT_GEN_RANDOM
は使用できません。
また、このトピックについて、値を生成するための汎用T-SQL UDFを含むプレゼンテーションを行いました。 効率的に生成する一意の疑似乱数プレゼンテーションを確認してください。
私はテクニックで非常に良いランダム性を作り出すことができます。実際の値が必要な場合は、tinyintテーブルなどを作成してみてください。明らかに、大きなサンプルサイズには最適ではありません。
SELECT TOP 1 [Value] FROM [TinyInt] ORDER BY NEWID();
乱数だけに使うのではありません。時間内に完了しない可能性のあるものに使用するため、2、3回のバッチ実行ですべてに到達できるようにしたいと思います。メンテナンスに最適です。