1

デフォルトのc#Random()は疑似乱数シーケンスであることを私は知っています。私はこのようなものが必要です、私はこの質問で本当のランダムを探していません。

質問させてください:

私が試した: 、他の人が言っnew Random(100000000).Next(999999999)たように、私は145156561を手に入れました。

私の質問は次のとおりです。同じシードによる疑似乱数シーケンスは、異なるシステム(win2003、win2008、monoなど)、異なる.netバージョン(.net 3、.net 4、c#2、c#3など)で変更されますか、または他の環境で変更されますか?

知りたいのは、コーディングした後、現在および将来、どこでも同じシードによって常に同じ疑似乱数シーケンスを取得するのでしょうか。

4

5 に答える 5

6

確実ではありません。一般に、この種のことを理解する方法は、ドキュメント(MSDN for .NET)を確認することです。アルゴリズムが説明されておらず、他の方法で公開されているアルゴリズムの実装でない場合は、実装の詳細と見なされ、変更される可能性があります。

これらのドキュメントもかなり厳密に読む必要があります。解釈の余地がある場合は、最悪のシナリオを想定する必要があります。この場合: http: //msdn.microsoft.com/en-us/library/system.random.aspxは次のように述べています。

異なるランダムオブジェクトに同一のシード値を提供すると、各インスタンスは同一の乱数シーケンスを生成します。

そしてそれがフレームワークに適用されること:

サポート対象:4、3.5、3.0、2.0、1.1、1.0.NETFrameworkクライアントプロファイル

サポート対象:4、3.5SP1ポータブルクラスライブラリ

サポート対象:ポータブルクラスライブラリ

それについては、将来のバージョンで同じように機能することが保証されているかどうか、またはサポートされているさまざまなフレームワークから同じ結果が得られるかどうかについては何もわかりません。実際、それは次のように述べています。

発信者へのメモ

Randomクラスでの乱数ジェネレーターの実装は、.NETFrameworkのメジャーバージョン間で同じであることが保証されていません。その結果、アプリケーションコードは、同じシードが異なるバージョンの.NETFrameworkで同じ疑似ランダムシーケンスになると想定してはなりません。

于 2012-04-09T20:50:12.613 に答える
3

これを実現する最良の方法は、独自の乱数ジェネレーターを実装することです。http://www.agner.org/random/をご覧ください

于 2012-04-09T20:50:15.467 に答える
2

いいえ、これが異なる.NETバージョン間で当てはまるとは限りません。

Randomクラスの現在の実装は、DonaldE.Knuthの減算乱数ジェネレーターアルゴリズムに基づいています。

currentという単語の使用に注意してください。これは、フレームワークの新しいバージョンで置き換えることができることを意味します。(これは、 ChrisShainの投稿で言及されている引用でも明示的に述べられています。

100%確実にしたい場合は、将来のすべてのバージョンでシーケンスを複製できます。たとえば、メルセンヌツイスターなどの独自のPRNGを含めます。

于 2012-04-09T20:54:24.000 に答える
2

ランダムクラスのMSDNによる。

発信者へのメモ

Randomクラスでの乱数ジェネレーターの実装は、.NETFrameworkのメジャーバージョン間で同じであることが保証されていません。その結果、アプリケーションコードは、同じシードが異なるバージョンの.NETFrameworkで同じ疑似ランダムシーケンスになると想定してはなりません。

Randomしたがって、同じシーケンスを使用して信頼することはできません。

于 2012-04-09T20:57:48.993 に答える
2

Chris Shainのすばらしい答えが明らかにしたように、異なるプラットフォームでも、または.NETのメジャーバージョン間でも同じ結果に依存することはできません。

Windowsの.NETで実行されるMonoGameを使用してゲームを作成したため、 @ BlueLineGamesでこの正確な問題が発生しましたが、OSXのMonoで実行すると異なる値が生成されました。

スティーブが提案したように、独自のPRNGを作成することは優れたソリューションです。他の誰かの時間を節約できることを願って、System.Randomの代わりにドロップできるクラスといくつかの簡単な使用法情報があります。

/// <summary>
/// This class is a drop-in replacement to use instead of Random(). Its
/// main purpose is to work identically across multiple platforms for a given
/// seed value - whereas the Random class is not guaranteed to give the
/// same results on different platforms even when the seed is the same.
/// 
/// This is an implementation of a Linear Congruential Generator which is
/// a very simple pseudorandom number generator. It is used instead of Random()
/// since Random() is implemented differently in Mono than .NET (and even
/// between different major-versions of .NET).
/// 
/// This is NOT recommended to be used for anything that should be secure such
/// as generating passwords or secret tokens. A "cryptogrpahically secure pseudorandom
/// number generator" (such as Mersenne Twister) should be used for that, instead.
/// 
/// More about Linear Congruential Generators can be found here:
/// http://en.wikipedia.org/wiki/Linear_congruential_generator
/// </summary>
public class CrossPlatformRandom : Random
{
    // To start with, we'll be using the same values as Borland Delphi, Visual Pascal, etc.
    // http://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
    private const int LCG_MULTIPLIER = 134775813; // 0x08088405
    private const int LCG_INCREMENT = 1;

    private int _seed;

    /// <summary>
    /// Initializes a new instance of the CrossPlatformRandom class, using a time-dependent
    /// default seed value.
    /// 
    /// Please note that this values generated from this are NOT guaranteed to be the same
    /// cross-platform because there is no seed value. In cases where the caller requires
    /// predictable or repeatable results, they MUST specify the seed.
    /// </summary>
    public CrossPlatformRandom()
    {
        // System.Random is time-dependent, so we will just use its first number to generate
        // the seed.
        Random rand = new Random();
        this._seed = rand.Next();
    }

    /// <summary>
    /// Initializes a new instance of the System.Random class, using the specified seed value.
    /// </summary>
    /// <param name="seed">A number used to calculate a starting value for the pseudo-random number sequence. If a negative number is specified, the absolute value of the number is used.</param>
    public CrossPlatformRandom(int seed)
    {
        _seed = seed;
    }

    private int GetNext() // note: returns negative numbers too
    {
        _seed = (_seed * LCG_MULTIPLIER) + LCG_INCREMENT;
        return _seed;
    }

    /// <summary>
    //  Returns a nonnegative random number.
    /// </summary>
    /// <returns>A 32-bit signed integer greater than or equal to zero and less than System.Int32.MaxValue.</returns>
    public override int Next()
    {
        return this.Next(int.MaxValue);
    }

    /// <summary>
    /// Returns a nonnegative random number less than the specified maximum.
    /// </summary>
    /// <param name="maxValue">The exclusive upper bound of the random number to be generated. maxValue must be greater than or equal to zero.</param>
    /// <returns> A 32-bit signed integer greater than or equal to zero, and less than maxValue; that is, the range of return values ordinarily includes zero but not maxValue. However, if maxValue equals zero, maxValue is returned.</returns>
    /// <exception cref="System.ArgumentOutOfRangeException">maxValue is less than zero.</exception>
    public override int Next(int maxValue)
    {
        if (maxValue < 0)
        {
            throw new System.ArgumentOutOfRangeException("maxValue is less than zero.");
        }

        ulong result = (ulong)(uint)GetNext() * (ulong)(uint)maxValue;
        return (int)(result >> 32);
    }

    /// <summary>
    /// Returns a random number within a specified range.
    /// </summary>
    /// <param name="minValue">The inclusive lower bound of the random number returned.</param>
    /// <param name="maxValue">The exclusive upper bound of the random number returned. maxValue must be greater than or equal to minValue.</param>
    /// <returns>A 32-bit signed integer greater than or equal to minValue and less than maxValue; that is, the range of return values includes minValue but not maxValue. If minValue equals maxValue, minValue is returned.</returns>
    /// <exception cref="System.ArgumentOutOfRangeException">minValue is greater than maxValue.</exception>
    public override int Next(int minValue, int maxValue)
    {
        if (minValue > maxValue)
        {
            throw new System.ArgumentOutOfRangeException("minValue is greater than maxValue.");
        }

        return minValue + this.Next(maxValue - minValue);
    }

    /// <summary>
    /// Fills the elements of a specified array of bytes with random numbers.
    /// </summary>
    /// <param name="buffer">An array of bytes to contain random numbers.</param>
    /// <exception cref="System.ArgumentNullException">buffer is null.</exception>
    public override void NextBytes(byte[] buffer)
    {
        if (buffer == null)
        {
            throw new System.ArgumentNullException("buffer is null.");
        }

        for (int index = 0; index < buffer.Length; index++)
        {
            buffer[index] = (byte)this.Next((int)byte.MaxValue);
        }
    }

    /// <summary>
    /// Returns a random number between 0.0 and 1.0.
    /// </summary>
    /// <returns>A double-precision floating point number greater than or equal to 0.0, and less than 1.0.</returns>
    public override double NextDouble()
    {
        return this.Sample();
    }

    /// <summary>
    /// Returns a random number between 0.0 and 1.0.
    /// 
    /// Since System.Random no longer uses this as the basis for all of the other random methods,
    /// this method isn't used widely by this class. It's here for completeness, primarily in case Random
    /// adds new entry points and we are lucky enough that they base them on .Sample() or one of the other existing methods.
    /// </summary>
    /// <returns>A double-precision floating point number greater than or equal to 0.0, and less than 1.0.</returns>
    protected override double Sample()
    {
        return ((double)this.Next() / (double)int.MaxValue);
    }
}

Random()を使用する代わりに、このクラスを安全にドロップできるはずですが、実際には、シードを使用して構築する場所(例:new Random(seedValue))でのみ実行する必要があります。

使用例:

int seed = 42;
CrossPlatformRandom r = new CrossPlatformRandom(seed);
for (int i = 0; i < 10; ++i)
    Console.WriteLine(r.Next(100));
于 2014-04-30T01:30:07.977 に答える