web-dev-qa-db-ja.com

1つの乱数のみを生成する乱数発生器

以下の機能があります。

//Function to get random number
public static int RandomNumber(int min, int max)
{
    Random random = new Random();
    return random.Next(min, max);
}

私はそれを呼び出す方法:

byte[] mac = new byte[6];
for (int x = 0; x < 6; ++x)
    mac[x] = (byte)(Misc.RandomNumber((int)0xFFFF, (int)0xFFFFFF) % 256);

実行時にデバッガを使ってこのループを実行すると、さまざまな値が表示されます(これが望ましいことです)。ただし、そのコードの2行下にブレークポイントを設定すると、 "mac"配列のすべてのメンバは同じ値になります。

なぜそれが起こるのですか?

721
Ivan Prodanov

new Random()を実行するたびに、クロックを使用して初期化されます。これは、タイトなループでは同じ値を何度も取得することを意味します。単一のRandomインスタンスを保持し、sameインスタンスでNextを使用し続ける必要があります。

//Function to get a random number 
private static readonly Random random = new Random(); 
private static readonly object syncLock = new object(); 
public static int RandomNumber(int min, int max)
{
    lock(syncLock) { // synchronize
        return random.Next(min, max);
    }
}

編集(コメントを参照):なぜここにlockが必要なのですか?

基本的に、NextRandomインスタンスの内部状態を変更します。複数のスレッドから同時に実行する場合、couldは「結果をさらにランダムにしただけです」と主張しますが、 実際にすることは内部実装を破壊する可能性があり、異なるスレッドから同じ番号を取得することもできます mightは問題になるかもしれませんし、そうでないかもしれません。ただし、内部で発生することの保証はより大きな問題です。 Randomnotを行うため、スレッドの安全性を保証します。したがって、2つの有効なアプローチがあります。

  • 異なるスレッドから同時にアクセスしないように同期する
  • スレッドごとに異なるRandomインスタンスを使用する

どちらでも構いません。しかし、同時に複数の呼び出し元からsingleインスタンスをミューテックスすることは、単にトラブルを求めているだけです。

lockは、これらのアプローチの最初の(より単純な)アプローチを実現します。ただし、別のアプローチは次のとおりです。

private static readonly ThreadLocal<Random> appRandom
     = new ThreadLocal<Random>(() => new Random());

これはスレッドごとであるため、同期する必要はありません。

994
Marc Gravell

アプリケーション全体での再利用を容易にするために、静的クラスが役に立ちます。

public static class StaticRandom
{
    private static int seed;

    private static ThreadLocal<Random> threadLocal = new ThreadLocal<Random>
        (() => new Random(Interlocked.Increment(ref seed)));

    static StaticRandom()
    {
        seed = Environment.TickCount;
    }

    public static Random Instance { get { return threadLocal.Value; } }
}

あなたはそのようなコードで静的なランダムインスタンスを使うことができます

StaticRandom.Instance.Next(1, 100);
110
Phil

Markのソリューションは毎回同期する必要があるため、かなり高価になる可能性があります。

スレッド固有の格納パターンを使用することで、同期の必要性を回避できます。


public class RandomNumber : IRandomNumber
{
    private static readonly Random Global = new Random();
    [ThreadStatic] private static Random _local;

    public int Next(int max)
    {
        var localBuffer = _local;
        if (localBuffer == null) 
        {
            int seed;
            lock(Global) seed = Global.Next();
            localBuffer = new Random(seed);
            _local = localBuffer;
        }
        return localBuffer.Next(max);
    }
}

2つの実装を測定すると、大きな違いがわかります。

58
Hans Malherbe

からの私の答えはこちら

正しい解決策を繰り返し

namespace mySpace
{
    public static class Util
    {
        private static rnd = new Random();
        public static int GetRandom()
        {
            return rnd.Next();
        }
    }
}

だからあなたは呼び出すことができます:

var i = Util.GetRandom();

ずっと。

乱数を生成するために真のステートレスな静的メソッドが厳密に必要な場合は、Guidに頼ることができます。

public static class Util
{
    public static int GetRandom()
    {
        return Guid.NewGuid().GetHashCode();
    }
}

これは少し遅くなるでしょうが、少なくとも私の経験からすると、Random.Nextよりもずっとランダムになることがあります。

しかしではありません:

new Random(Guid.NewGuid().GetHashCode()).Next();

不要なオブジェクトの作成は、特にループの下では遅くなります。

そして決して

new Random().Next();

それが遅い(ループの内側)だけでなく、そのランダムさは...まあ私によると本当によくありません。

35
nawfal

乱数を生成するには、次のクラスを使用します。

byte[] random;
System.Security.Cryptography.RNGCryptoServiceProvider prov = new System.Security.Cryptography.RNGCryptoServiceProvider();
prov.GetBytes(random);
23
fARcRY

1)Marc Gravellが言ったように、1つのランダムジェネレータを使うようにしてください。 System.Environment.TickCountというコンストラクタにこれを追加するのは、常にクールです。

2)ワンチップ。 100個のオブジェクトを作成し、それぞれが独自のrandom-generatorを持つべきだとしましょう(非常に短時間で乱数のLOADSを計算するのに便利です)。これをループ(100個のオブジェクトの生成)で行う場合は、(完全にランダムになるように)これを行うことができます。

int inMyRandSeed;

for(int i=0;i<100;i++)
{
   inMyRandSeed = System.Environment.TickCount + i;
   .
   .
   .
   myNewObject = new MyNewObject(inMyRandSeed);  
   .
   .
   .
}

// Usage: Random m_rndGen = new Random(inMyRandSeed);

乾杯。

13
sabiland

実行するたびに

Random random = new Random (15);

何百万回実行しても問題ありませんが、常に同じシードを使用します。

使うなら

Random random = new Random ();

ハッカーが種を推測し、あなたのアルゴリズムがあなたのシステムのセキュリティに関連している場合、あなたは異なる乱数列を得ます - あなたのアルゴリズムは壊れています。私はあなたがmultを実行します。このコンストラクタでは、シードはシステムクロックによって指定され、いくつかのインスタンスが非常に短い期間(ミリ秒)で作成された場合、それらは同じシードを持つことができます。

安全な乱数が必要な場合は、このクラスを使わなければなりません

System.Security.Cryptography.RNGCryptoServiceProvider

public static int Next(int min, int max)
{
    if(min >= max)
    {
        throw new ArgumentException("Min value is greater or equals than Max value.");
    }
    byte[] intBytes = new byte[4];
    using(RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
    {
        rng.GetNonZeroBytes(intBytes);
    }
    return  min +  Math.Abs(BitConverter.ToInt32(intBytes, 0)) % (max - min + 1);
}

使用法:

int randomNumber = Next(1,100);
3
Joma

randomクラス変数を次のように宣言するだけです。

    Random r = new Random();
    // ... Get three random numbers.
    //     Here you'll get numbers from 5 to 9
    Console.WriteLine(r.Next(5, 10));

リストから毎回異なる乱数を取得したい場合は、

r.Next(StartPoint,EndPoint) //Here end point will not be included

毎回Random r = new Random()を一度宣言することによって。

2
Abdul

解決策はたくさんあります。ここでは、数字だけを消したい場合、メソッドはランダムに結果の長さを受け取ります。

public String GenerateRandom(Random oRandom, int iLongitudPin)
{
    String sCharacters = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ123456789";
    int iLength = sCharacters.Length;
    char cCharacter;
    int iLongitudNuevaCadena = iLongitudPin; 
    String sRandomResult = "";
    for (int i = 0; i < iLongitudNuevaCadena; i++)
    {
        cCharacter = sCharacters[oRandom.Next(iLength)];
        sRandomResult += cCharacter.ToString();
    }
    return (sRandomResult);
}
1
Marztres