これは、あるインタビュアーからの質問でした。答えられませんでした。
質問は、指定された配列から乱数を選択すると仮定します。
条件は、シーケンシャルに何かを選択することは想定されておらず、組み込みのランダム関数を使用しないことです。
何も思いつきません。この Math.Random がどのように機能するか知りたいですか?
私はグーグルで検索しましたが、その背後にある実装/ロジックが見つかりませんでした。
誰でも知っていますか?
これまでに 3 人が、ティックの最後の桁を使用するように指示しました。これはうまくいきません。タイトなループでこれを試してみると、それが悪い考えである理由がすぐにわかります。
質問はあまりうまく提起されていません。私は面接であいまいな質問をするのが好きです。候補者があいまいな状況にどのように対処しているかを知ることができるからです。この場合、私はすぐに反論し、インタビュアーが「ランダム」とは何を意味するのかを調べます。疑似ランダム性は十分ですか?利用可能な高品質のエントロピーのソースはありますか?
明確な質問があると、答えやすくなります。
問題は、エントロピーの管理に帰着します。エントロピーのソースが非常に弱い場合 (Ticks の値 (価値のない最後の桁ではなく、値全体) など)、それを使用して疑似乱数ジェネレーターをシードできます。高品質のエントロピー ソースがある場合は、それを使用してランダム ビットを直接生成できます。
ランダムであることが保証されています。(頬にしっかりと舌を入れる):
void Main()
{
Enumerable.Range(0, 10).Select(x => ComeOnItsKindaRandom(0, 10)).Dump();
}
public int ComeOnItsKindaRandom(int minValue, int maxValue)
{
var query = "http://www.random.org/integers/?num=1&min={0}&max={1}&col=1&base=10&format=plain&rnd=new";
var request = WebRequest.Create(string.Format(query, minValue, maxValue));
var response = request.GetResponse();
using(var sr = new StreamReader(response.GetResponseStream()))
{
var body = sr.ReadToEnd().Trim();
return int.Parse(body);
}
}
私は使用します
DateTime.Now.Tick
そして、たとえばMath.Random(10)の場合、ちょうど十分な数を取ると、最後の2つの数だけを取ります。
または、次のようにこのティックのモジュロを取ることができます:
public static class MyMath
{
private static int counter = 1;
public static int Random(int max)
{
counter++;
long ticks = DateTime.Now.Ticks;
int result = Math.Abs((int) (ticks/counter)%max);
return result;
}
}
次のテストを参照してください。
[Test]
public void test()
{
List<int> test = new List<int>();
for (int i = 0; i < 10; i++)
{
test.Add(MyMath.Random(100));
}
Console.WriteLine("result:");
foreach (int i in test)
{
Console.WriteLine();
}
}
これは C での乱数の実装です。C# で書き直してみてください。
Cの乱数:終わり、ついに? http://www.cse.yorku.ca/~oz/marsaglia-rng.html
とてもクオリティが高いそうです。
しかし、インタビューでこのコードを書くのは簡単ではありませんが、使用されたアイデアを彼に伝えることはできます。
彼らは、あなたがLCG (線形合同法ジェネレーター)アルゴリズムについて知っているかどうかを見ているだけだったと思います。
ただし、それらの背後にある数学はややトリッキーであるため、頭のてっぺんから書き出すことができると期待できるとは思えません。
しかし、それができない場合は、このようにチートしてランダムなインデックスを生成することはできませんか?
int index = Guid.NewGuid().GetHashCode() % array.Length;