2つの2進数の間の乱数


156

2つのdoubleの間の乱数を生成することは可能ですか?

例:

public double GetRandomeNumber(double minimum, double maximum)
{
    return Random.NextDouble(minimum, maximum) 
}

それから私はそれを次のように呼びます:

double result = GetRandomNumber(1.23, 5.34);

どんな考えでもいただければ幸いです。

回答:


329

はい。

Random.NextDoubleは、0と1の間のdoubleを返します。次に、これに入る必要がある範囲(最大と最小の差)を掛け、それをベースに追加します(最小)。

public double GetRandomNumber(double minimum, double maximum)
{ 
    Random random = new Random();
    return random.NextDouble() * (maximum - minimum) + minimum;
}

実際のコードはランダムな静的メンバーでなければなりません。これにより、乱数ジェネレータを作成するコストが節約され、GetRandomNumberを頻繁に呼び出すことができるようになります。すべての呼び出しで新しいRNGを初期化しているため、呼び出し間でシステム時刻が変わらないほど速く呼び出した場合、RNGはまったく同じタイムスタンプでシードされ、同じ乱数ストリームを生成します。


33
GetRandomNumber()をループで呼び出すと、同じ値が何度も生成されるので注意してください
John Rasch

13
良い拡張方法かもしれませんpublic double GetRandomNumber(this Random random, double minimum, double maximum) {...}
ジョニー5

5
Random.NextDoubleは決して1.0を返さないため、この関数も最大数と等しくなることはありません。
マシュー

6
新しいRandom((int)DateTime.Now.Ticks)をシードとして配置することをお勧めします。これにより、クイックループでも「よりランダム」になります。
DanielSkowroński、2012

5
これは、最小値がdouble.MinValueで最大値がdouble.MaxValueの場合は機能しません。このユースケースの処理方法に関する提案はありますか?
Gene S

40

Johnny5は、拡張メソッドの作成を提案しました。これを行う方法を示すより完全なコード例を次に示します。

public static class RandomExtensions
{
    public static double NextDouble(
        this Random random,
        double minValue,
        double maxValue)
    {
        return random.NextDouble() * (maxValue - minValue) + minValue;
    }
}

これで、Randomクラスのメソッドであるかのように呼び出すことができます。

Random random = new Random();
double value = random.NextDouble(1.23, 5.34);

Randomループ内に多数の新しいオブジェクトを作成しないでください。これにより、同じ値が連続して何度も取得される可能性があります。たくさんの乱数が必要な場合はRandom、のインスタンスを1つ作成して再利用してください。


9

気をつけてください。randomたとえばfor(int i = 0; i < 10; i++)、ループの内部を生成する場合は、new Random()宣言をループの中に入れないでください。

MSDNから:

乱数の生成は、シード値から始まります。同じシードを繰り返し使用すると、同じ一連の数値が生成されます。異なるシーケンスを生成する1つの方法は、シード値を時間依存にすることで、ランダムの新しいインスタンスごとに異なるシリーズを生成します。デフォルトでは、Randomクラスのパラメーターなしのコンストラクターは、システムクロックを使用してシード値を生成します...

この事実に基づいて、次のようにします。

var random = new Random();

for(int d = 0; d < 7; d++)
{
    // Actual BOE
    boes.Add(new LogBOEViewModel()
    {
        LogDate = criteriaDate,
        BOEActual = GetRandomDouble(random, 100, 1000),
        BOEForecast = GetRandomDouble(random, 100, 1000)
    });
}

double GetRandomDouble(Random random, double min, double max)
{
     return min + (random.NextDouble() * (max - min));
}

このようにすると、さまざまなdouble値が得られることが保証されます。


8

最も単純なアプローチは、0と2つの数値の差の間の乱数を生成するだけです。次に、2つの数値のうち小さい方を結果に追加します。


3

次のようなコードを使用できます。

public double getRandomNumber(double minimum, double maximum) {
    return minimum + randomizer.nextDouble() * (maximum - minimum);
}

2

あなたはこれを行うことができます:

public class RandomNumbers : Random
{
    public RandomNumbers(int seed) : base(seed) { }

    public double NextDouble(double minimum, double maximum)
    {
        return base.NextDouble() * (maximum - minimum) + minimum;
    }
}

2

私はパーティーに少し遅れましたが、一般的なソリューションを実装する必要があり、どのソリューションも自分のニーズを満たすことができないことがわかりました。

受け入れられているソリューションは、狭い範囲に適しています。ただし、maximum - minimum大きな範囲では無限大になる可能性があります。したがって、修正されたバージョンは次のバージョンになります。

public static double NextDoubleLinear(this Random random, double minValue, double maxValue)
{
    // TODO: some validation here...
    double sample = random.NextDouble();
    return (maxValue * sample) + (minValue * (1d - sample));
}

これによりdouble.MinValue、との間でも乱数が生成されdouble.MaxValueます。しかし、これは別の「問題」をもたらします。それはこの投稿でうまく提示さています。そのような大きな範囲を使用すると、値が「不自然」に見えるかもしれません。たとえば、0から10,000のランダムなdoubleを生成した後、double.MaxValueすべての値は2.9579E + 304から1.7976E + 308の間でした。

そこで、対数スケールで数値を生成する別のバージョンも作成しました。

public static double NextDoubleLogarithmic(this Random random, double minValue, double maxValue)
{
    // TODO: some validation here...
    bool posAndNeg = minValue < 0d && maxValue > 0d;
    double minAbs = Math.Min(Math.Abs(minValue), Math.Abs(maxValue));
    double maxAbs = Math.Max(Math.Abs(minValue), Math.Abs(maxValue));

    int sign;
    if (!posAndNeg)
        sign = minValue < 0d ? -1 : 1;
    else
    {
        // if both negative and positive results are expected we select the sign based on the size of the ranges
        double sample = random.NextDouble();
        var rate = minAbs / maxAbs;
        var absMinValue = Math.Abs(minValue);
        bool isNeg = absMinValue <= maxValue ? rate / 2d > sample : rate / 2d < sample;
        sign = isNeg ? -1 : 1;

        // now adjusting the limits for 0..[selected range]
        minAbs = 0d;
        maxAbs = isNeg ? absMinValue : Math.Abs(maxValue);
    }

    // Possible double exponents are -1022..1023 but we don't generate too small exponents for big ranges because
    // that would cause too many almost zero results, which are much smaller than the original NextDouble values.
    double minExponent = minAbs == 0d ? -16d : Math.Log(minAbs, 2d);
    double maxExponent = Math.Log(maxAbs, 2d);
    if (minExponent == maxExponent)
        return minValue;

    // We decrease exponents only if the given range is already small. Even lower than -1022 is no problem, the result may be 0
    if (maxExponent < minExponent)
        minExponent = maxExponent - 4;

    double result = sign * Math.Pow(2d, NextDoubleLinear(random, minExponent, maxExponent));

    // protecting ourselves against inaccurate calculations; however, in practice result is always in range.
    return result < minValue ? minValue : (result > maxValue ? maxValue : result);
}

いくつかのテスト:

以下は、0からDouble.MaxValue両方の戦略で10,000のランダムなdouble数を生成した結果のソートです。結果は対数目盛を使用して表示されます。

0..Double.MaxValue

線形ランダム値は一見間違っているように見えますが、統計はそれらのどれも他より「優れている」ことはないことを示しています:線形戦略でさえ均一な分布を持ち、値間の平均差は両方の戦略でほとんど同じです。

さまざまな範囲で遊んだところ、線形戦略は範囲が0でushort.MaxValue「妥当な」最小値10.78294704(ulong範囲の最小値は3.03518E + 15; int:353341)で「正気」であることがわかりました。これらは、異なるスケールで表示された両方の戦略の同じ結果です。

0..UInt16.MaxValue


編集:

最近、ライブラリをオープンソースにRandomExtensions.NextDoubleしました。完全に検証されたメソッドを自由に見てください。


1

値の1つが負の場合はどうなりますか?より良いアイデアはないでしょう:

double NextDouble(double min, double max)
{
       if (min >= max)
            throw new ArgumentOutOfRangeException();    
       return random.NextDouble() * (Math.Abs(max-min)) + min;
}

5
Math.Abs()は冗長だと思います。あなたはそれを保証したのでmin >= maxmax - minとにかく負でない数でなければなりません。
Brian Reischl 2013年

1

[ double.MinValue; の範囲の乱数が必要な場合 double.MaxValue]

// Because of:
double.MaxValue - double.MinValue == double.PositiveInfinity

// This will be equals to NaN or PositiveInfinity
random.NextDouble() * (double.MaxValue - double.MinValue)

代わりに使用:

public static class RandomExtensions
{
    public static double NextDoubleInMinMaxRange(this Random random)
    {
        var bytes = new byte[sizeof(double)];
        var value = default(double);
        while (true)
        {
            random.NextBytes(bytes);
            value = BitConverter.ToDouble(bytes, 0);
            if (!double.IsNaN(value) && !double.IsInfinity(value))
                return value;
        }
    }
}

2
ここで第二の例のように歪んだ分布の良い点が、この命題結果stackoverflow.com/a/3365388/3922292
ピョートルFalkowski

0

ループで呼び出す場合に同じ乱数を生成する方法については、ループの外側にある新しいRandom()オブジェクトをグローバル変数として宣言するのが便利です。

これをループで実行する場合は、GetRandomInt関数の外部でRandomクラスのインスタンスを宣言する必要があることに注意してください。

"どうしてこれなの?" あなたが尋ねる。

まあ、ランダムクラスは実際には擬似乱数を生成し、ランダマイザーの「シード」はシステム時間です。ループが十分に速い場合、システムクロック時間はランダマイザーと異なって表示されず、Randomクラスの新しい各インスタンスは同じシードで開始し、同じ擬似乱数を与えます。

ソースはここにあります:http : //www.whypad.com/posts/csharp-get-a-random-number-between-x-and-y/412/


これは、OPの実際の質問に答えようとさえしないので、コメントとしてより適しています。
b1nary.atr0phy 2016

0

スタティックランダムを使用するか、システムクロックがシードするため、数値がタイト/高速ループで繰り返される傾向があります。

public static class RandomNumbers
{
    private static Random random = new Random();
    //=-------------------------------------------------------------------
    // double between min and the max number
    public static double RandomDouble(int min, int max) 
    {
        return (random.NextDouble() * (max - min)) + min;
    }
    //=----------------------------------
    // double between 0 and the max number
    public static double RandomDouble(int max) 
    {
        return (random.NextDouble() * max);
    }
    //=-------------------------------------------------------------------
    // int between the min and the max number
    public static int RandomInt(int min, int max) 
    {   
        return random.Next(min, max + 1);
    }
    //=----------------------------------
    // int between 0 and the max number
    public static int RandomInt(int max) 
    {
        return random.Next(max + 1);
    }
    //=-------------------------------------------------------------------
 }

参照:https : //docs.microsoft.com/en-us/dotnet/api/system.random?view=netframework-4.8


-1
Random random = new Random();

double NextDouble(double minimum, double maximum)
{  

    return random.NextDouble()*random.Next(minimum,maximum);

}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.