2 Çift Sayı Arasındaki Rastgele Sayı


156

2 çift arasında rastgele bir sayı üretmek mümkün müdür?

Misal:

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

Sonra ben aşağıdaki ile çağırıyorum:

double result = GetRandomNumber(1.23, 5.34);

Herhangi bir düşünce takdir edilecektir.

Yanıtlar:


329

Evet.

Random.NextDouble, 0 ile 1 arasında bir çift döndürür. Ardından, girmeniz gereken aralıkla (maksimum ve minimum arasındaki fark) çarpar ve bunu tabana (minimum) eklersiniz.

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

Gerçek kod rastgele bir statik üye olmalıdır. Bu, rasgele sayı üretecini yaratmanın maliyetini azaltır ve GetRandomNumber'ı çok sık aramanızı sağlar. Her çağrıda yeni bir RNG başlattığımızdan, sistem süresinin çağrılar arasında değişmeyecek kadar hızlı çağırırsanız, RNG tam olarak aynı zaman damgası ile tohumlanır ve aynı rasgele sayılar akışı oluşturur.


33
Tekrar tekrar aynı değeri üreteceği için bir döngüde GetRandomNumber () çağırırsanız dikkat edin
John Rasch

13
Güzel bir uzatma yöntemi olabilir,public double GetRandomNumber(this Random random, double minimum, double maximum) {...}
Johnny5

5
Random.NextDouble hiçbir zaman 1.0 döndürmediği için, bu fonksiyonun asla maksimum sayıya eşit olmayacağını unutmayın.
Matthew

6
Ben bir tohum olarak yeni Rastgele ((int) DateTime.Now.Ticks) koymak öneririz bu hızlı döngüler bile "daha rasgele" yapmalısınız.
Daniel Skowroński

5
Min değeri çift, MinValue ve maks değeri çiftse MaksValue. Bu kullanım senaryosunun nasıl ele alınacağına dair herhangi bir öneriniz var mı?
Gene S

40

Johnny5 bir uzantı yöntemi oluşturmayı önerdi. Bunu nasıl yapabileceğinizi gösteren daha eksiksiz bir kod örneği:

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

Şimdi sanki Randomsınıfta bir yöntemmiş gibi diyebilirsiniz :

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

RandomBir döngüde çok sayıda yeni nesne oluşturmamanız gerektiğini unutmayın, çünkü bu, aynı değeri arka arkaya birçok kez elde etmenizi sağlayacaktır. Çok sayıda rasgele sayıya ihtiyacınız varsa, bir örneğini oluşturun Randomve yeniden kullanın.


9

Dikkat edin: randomÖrneğin içinde bir döngü oluşturuyorsanız for(int i = 0; i < 10; i++),new Random() bildirimi döngünün içine .

Gönderen MSDN :

Rastgele sayı üretimi bir tohum değerinden başlar. Aynı tohum tekrar tekrar kullanılırsa, aynı sayı dizisi üretilir. Farklı sekanslar üretmenin bir yolu, tohum değerini zamana bağımlı hale getirerek her yeni Random örneğiyle farklı bir seri üretmektir. Varsayılan olarak, Random sınıfının parametresiz kurucusu, tohum değerini oluşturmak için sistem saatini kullanır ...

Bu gerçeğe dayanarak, bir şey yapın:

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));
}

Bu şekilde farklı çift değerler elde edeceğinizin garantisi vardır.


8

En basit yaklaşım, 0 ile iki sayının farkı arasında rastgele bir sayı üretecektir. Ardından iki sayıdan daha küçük olanı sonuca ekleyin.


3

Bunun gibi bir kod kullanabilirsiniz:

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

2

Bunu yapabilirsin:

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

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

2

Partiye biraz geç kaldım ama genel bir çözüm uygulamam gerekiyordu ve çözümlerin hiçbirinin ihtiyaçlarımı karşılayamadığı ortaya çıktı.

Kabul edilen çözüm küçük aralıklar için iyidir; ancak, maximum - minimumbüyük aralıklar için sonsuz olabilir. Yani düzeltilmiş bir sürüm bu sürüm olabilir:

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));
}

Bu, double.MinValueve arasında bile rasgele sayılar üretir double.MaxValue. Ama bu güzel sunulur başka bir "sorun", tanıtır Bu mesajda biz böyle büyük değerleri de "doğal olmayan" görünebilir aralıkları kullanırsanız. Örneğin, 0 ile 10 arasında 10.000 rasgele çift oluşturduktan sonradouble.MaxValue üretildikten tüm değerler 2.9579E + 304 ile 1.7976E + 308 arasındaydı.

Bu yüzden logaritmik ölçekte rakamlar üreten başka bir versiyon daha oluşturdum:

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);
}

Bazı testler:

Burada 0 Double.MaxValueile her iki strateji arasında 10.000 rasgele çift sayı üretmenin sıralı sonuçları verilmiştir . Sonuçlar logaritmik ölçek kullanılarak görüntülenir:

0..Double.MaxValue

Doğrusal rastgele değerler ilk bakışta yanlış gibi görünse de, istatistikler bunların hiçbirinin diğerinden daha iyi olmadığını gösteriyor: doğrusal stratejinin bile eşit bir dağılımı var ve değerler arasındaki ortalama fark her iki stratejide de hemen hemen aynı .

Farklı aralıklarla oynamak bana lineer stratejinin 0 aralığında ve ushort.MaxValue"makul" minimum değeri 10.78294704 ile "aklı" olacağını gösterdi ( ulongaralık için minimum değer 3.03518E + 15 int;: 353341). Bunlar, farklı ölçeklerle gösterilen her iki stratejinin de aynı sonuçlarıdır:

0..UInt16.MaxValue


Düzenle:

Son zamanlarda kütüphanelerimi açık kaynak yaptım RandomExtensions.NextDouble, tam doğrulama ile yöntemi görmekten çekinmeyin .


1

Değerlerden biri negatifse ne olur? Daha iyi bir fikir olmazdı:

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

5
Bence Math.Abs()gereksiz. Bunu sağladığınızdan beri min >= max, max - minyine de negatif olmayan bir sayı olmalıdır.
Brian Reischl

1

Aralıkta rastgele bir sayıya ihtiyacınız varsa [ 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)

Bunun yerine kullanın:

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
İyi bir nokta, ama bu öneri burada ikinci örnekte olduğu gibi çarpık dağılım ile sonuçlanıyor stackoverflow.com/a/3365388/3922292
Piotr Falkowski

0

Bir döngüde aynı rasgele sayıyı üretme hakkında şık bir çözüm olarak, döngü dışında yeni Random () nesnesini genel değişken olarak bildirmektir.

Eğer bir döngü içinde çalıştırıyorsanız, Random sınıfının örneğini GetRandomInt işlevi dışında bildirmeniz gerektiğine dikkat edin.

"Bu neden?" sen sor.

Random sınıfı aslında rastgele rasgele sayılar üretir ve randomizatör için “tohum” sistem zamanıdır. Döngünüz yeterince hızlıysa, sistem saat zamanı rastgele belirleyiciden farklı görünmez ve Random sınıfının her yeni örneği aynı tohumla başlar ve size aynı sahte rasgele sayı verir.

Kaynak burada: http://www.whypad.com/posts/csharp-get-a-random-number-between-x-and-y/412/


Bu OP'nin asıl sorusunu cevaplamaya çalışmadığı için yorum olarak daha uygundur.
b1nary.atr0phy

0

Statik bir Rastgele kullanın veya sayılar, sistem saatinin tohumlanması nedeniyle sıkı / hızlı döngülerde tekrarlanma eğilimindedir.

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);
    }
    //=-------------------------------------------------------------------
 }

Ayrıca bkz: 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);

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.