c# Int.MinValue और int.MaxValue, समावेशी के बीच यादृच्छिक संख्या




.net random (12)

यहाँ एक बिटकॉइन है: Random.Next() में एक अधिभार है जो न्यूनतम मूल्य और अधिकतम मूल्य को स्वीकार करता है। यह अधिभार एक संख्या देता है जो न्यूनतम मूल्य (समावेशी) से अधिक या बराबर है और अधिकतम मूल्य (अनन्य) से कम है।

मैं अधिकतम मूल्य सहित पूरी रेंज को शामिल करना चाहूंगा। कुछ मामलों में, मैं इसे अधिकतम मूल्य में केवल एक जोड़कर पूरा कर सकता था। लेकिन इस मामले में, अधिकतम मूल्य int.MaxValue हो सकता है, और इसमें से एक को जोड़ने से मुझे जो चाहिए वह पूरा नहीं होगा।

तो क्या कोई अच्छी चाल जानता है int.MinValue से int.MaxValue , समावेशी रूप से एक यादृच्छिक संख्या प्राप्त करने के लिए?

अद्यतन करें:

ध्यान दें कि निचली सीमा int.MinValue हो int.MinValue लेकिन कुछ और भी हो सकती है। अगर मुझे पता है कि यह हमेशा int.MinValue तो समस्या सरल हो जाएगी।


Random.Next(int minValue, int maxValue) का आंतरिक कार्यान्वयन बड़ी रेंज के लिए दो नमूने बनाता है, जैसे Int32.MinValue और Int32.MaxValue बीच की सीमा। NextInclusive विधि के लिए मुझे चार नमूनों को मिलाकर एक और बड़ी रेंज Next का उपयोग करना पड़ा। तो प्रदर्शन को उस संस्करण के साथ तुलनीय होना चाहिए जो 4 बाइट्स (प्रति नमूना एक नमूना) के साथ एक बफर भरता है।

public static class RandomExtensions
{
    public static int NextInclusive(this Random random, int minValue, int maxValue)
    {
        if (maxValue == Int32.MaxValue)
        {
            if (minValue == Int32.MinValue)
            {
                var value1 = random.Next(Int32.MinValue, Int32.MaxValue);
                var value2 = random.Next(Int32.MinValue, Int32.MaxValue);
                return value1 < value2 ? value1 : value1 + 1;
            }
            return random.Next(minValue - 1, Int32.MaxValue) + 1;
        }
        return random.Next(minValue, maxValue + 1);
    }

}

कुछ परिणाम:

new Random(0).NextInclusive(int.MaxValue - 1, int.MaxValue); // returns int.MaxValue
new Random(1).NextInclusive(int.MaxValue - 1, int.MaxValue); // returns int.MaxValue - 1
new Random(0).NextInclusive(int.MinValue, int.MinValue + 1); // returns int.MinValue + 1
new Random(1).NextInclusive(int.MinValue, int.MinValue + 1); // returns int.MinValue
new Random(24917099).NextInclusive(int.MinValue, int.MaxValue); // returns int.MinValue
var random = new Random(784288084);
random.NextInclusive(int.MinValue, int.MaxValue);
random.NextInclusive(int.MinValue, int.MaxValue); // returns int.MaxValue

अपडेट: मेरे कार्यान्वयन में सबसे बड़ी संभव सीमा ( Int32.MinValue - Int32.MaxValue ) के लिए औसत प्रदर्शन है, इसलिए मैं एक नए के साथ आया जो 4 गुना तेज है। यह मेरी मशीन में प्रति सेकंड लगभग 22,000,000 यादृच्छिक संख्या का उत्पादन करता है। मुझे नहीं लगता है कि इससे कोई तेज हो सकता है।

public static int NextInclusive(this Random random, int minValue, int maxValue)
{
    if (maxValue == Int32.MaxValue)
    {
        if (minValue == Int32.MinValue)
        {
            var value1 = random.Next() % 0x10000;
            var value2 = random.Next() % 0x10000;
            return (value1 << 16) | value2;
        }
        return random.Next(minValue - 1, Int32.MaxValue) + 1;
    }
    return random.Next(minValue, maxValue + 1);
}

कुछ परिणाम:

new Random(0).NextInclusive(int.MaxValue - 1, int.MaxValue); // = int.MaxValue
new Random(1).NextInclusive(int.MaxValue - 1, int.MaxValue); // = int.MaxValue - 1
new Random(0).NextInclusive(int.MinValue, int.MinValue + 1); // = int.MinValue + 1
new Random(1).NextInclusive(int.MinValue, int.MinValue + 1); // = int.MinValue
new Random(1655705829).NextInclusive(int.MinValue, int.MaxValue); // = int.MaxValue
var random = new Random(1704364573);
random.NextInclusive(int.MinValue, int.MaxValue);
random.NextInclusive(int.MinValue, int.MaxValue);
random.NextInclusive(int.MinValue, int.MaxValue); // = int.MinValue

आप यह कोशिश कर सकते हैं। थोड़ा हैकरी लेकिन आप दोनों न्यूनतम और अधिकतम समावेशी प्राप्त कर सकते हैं।

static void Main(string[] args)
        {
            int x = 0;

            var r = new Random();

            for (var i = 0; i < 32; i++)
            {
                x = x | (r.Next(0, 2) << i);

            }

            Console.WriteLine(x);
            Console.ReadKey();
        }

जैसा कि मैं समझता हूँ कि आप रैंडम -2.147.483.648 और +2.147.483.647 के बीच मान रखना चाहते हैं। लेकिन समस्या यह है कि रैंडम रैंडम दिए गए मानों को केवल -2.147.483.648 से +2.147.483.64 6 तक मान दिया जाएगा, क्योंकि अधिकतम अनन्य है।

विकल्प 0: बात को दूर ले जाएं और इसके बिना करना सीखें

डगलस एडम्स एक प्रोग्रामर AFAIK नहीं थे, लेकिन उनके पास हमारे लिए कुछ अच्छी सलाह है: "कुछ भी अदृश्य बनाने में शामिल तकनीक इतनी असीम जटिल है कि नौ सौ निन्यानबे अरब, नौ सौ निन्यानबे मिलियन, नौ सौ और नब्बे एक ट्रिलियन में से नौ हज़ार, नौ सौ निन्यानवे बार यह बहुत सरल और अधिक प्रभावी है, बस बात को दूर ले जाना और इसके बिना करना। "

यह ऐसा मामला हो सकता है।

विकल्प 1: हमें एक बड़ा यादृच्छिक चाहिए!

Random.Next Int32 को तर्क के रूप में उपयोग करता है। एक विकल्प जो मैं सोच सकता हूं कि एक अलग रैंडम फंक्शन का उपयोग करना होगा, इनपुट के रूप में अगले उच्च स्तर के इंटेगर (Int64) ले सकते हैं। एक Int32 एक Int64 में निहित है। Int64 Number = Int64(Int32.MaxValue)+1;

लेकिन afaik, आपको ऐसा करने के लिए .NET पुस्तकालयों के बाहर जाना होगा। उस बिंदु पर आप एक रैंडम के लिए भी देख सकते हैं जो मैक्स में शामिल है।

लेकिन मुझे लगता है कि एक गणितीय कारण है कि इसे एक मूल्य को बाहर करना पड़ा।

विकल्प 2: अधिक रोल करें

एक और तरीका है कि रैंडम की दो कॉल का उपयोग करें - प्रत्येक को आधे से एक रेंज के लिए - और फिर उन्हें जोड़ें।

Number1 = rng.Next(-2.147.483.648, 0);
Number2 = rng.Next(0, 2.147.483.647);
resut = Number1 + Number2;

हालांकि मैं 90% निश्चित हूं जो रैंडन वितरण को बर्बाद कर देगा। मेरे पीएंडपी आरपीजी अनुभव ने मुझे पासा के अवसरों के साथ कुछ अनुभव दिया और मैं एक तथ्य के लिए जानता हूं कि 2 पासा (या वही 2 बार) आपको एक बहुत ही अलग परिणाम वितरण प्राप्त करेंगे फिर एक विशिष्ट मर जाएगा। यदि आपको इस यादृच्छिक वितरण की आवश्यकता नहीं है, तो यह एक विकल्प है। लेकिन अगर आप उसके वितरण के बारे में बहुत ज्यादा परवाह नहीं करते हैं तो यह एक चेक के लायक है।

विकल्प 3: क्या आपको पूरी रेंज की आवश्यकता है? या क्या आप इसमें मिनट और अधिकतम होने की परवाह करते हैं?

मुझे लगता है कि आप परीक्षण के कुछ रूप कर रहे हैं और आपको सीमा में होने के लिए Int.MaxValue और Int.MinValue दोनों की आवश्यकता है। लेकिन क्या आप के बीच में भी हर मूल्य की आवश्यकता है, या आप उनमें से एक के बिना कर सकते हैं? यदि आपको कोई मान ढीला करना है, तो क्या आप IntoaxValue के बजाय 4 को खोना पसंद करेंगे?

Number = rng.Next(Int.MinValue, Int.MaxValue);
if(Number > 3)
  Number = Number +1;

इस तरह का कोड आपको 4 को छोड़कर MinValueand और Maxvalue के बीच हर नंबर पर मिलेगा। लेकिन ज्यादातर मामलों में कोड जो 3 और 5 से निपट सकते हैं, वे 4 से भी निपट सकते हैं। 4 को स्पष्ट रूप से परीक्षण करने की आवश्यकता नहीं है।

बेशक, मान लें कि 4 कुछ महत्वपूर्ण परीक्षण संख्या नहीं है जिसे चलाना है (मैंने उन कारणों से 1 और 0 से बचा है)। आप यादृच्छिक रूप से "स्किप" करने के लिए संख्या भी तय कर सकते हैं:

skipAbleNumber = rng.Next(Int.MinValue +1, Int.MaxValue);

और फिर > skipAbleNumber उपयोग करें तब > 4


यह विधि आपको किसी भी पूर्णांक सीमा के भीतर एक यादृच्छिक पूर्णांक दे सकती है। यदि अधिकतम सीमा int.MaxValue से कम है, तो यह साधारण रैंडम का उपयोग करता है। पाठ (Int32, Int32) लेकिन इसके मूल्य को शामिल करने के लिए 1 से ऊपरी सीमा को जोड़ने के साथ। यदि नहीं, लेकिन int.MinValue की तुलना में कम सीमा के साथ, यह सीमा 1 को कम करने के लिए 1 के साथ निचली सीमा को कम करता है जो परिणाम में 1 जोड़ता है। अंत में, यदि दोनों सीमाएँ int.MinValue और int.MaxValue हैं, तो यह एक यादृच्छिक पूर्णांक 'a' उत्पन्न करता है जो कि प्रत्येक की 50% संभावना के साथ 0 या 1 है, तो यह दो अन्य पूर्णांक बनाता है, पहला int.MinValue और के बीच है -1 समावेशी, 2147483648 मूल्य, और दूसरा 0 और int.MaxValue समावेशी, 2147483648 मूल्यों के बीच भी है, और 'a' के मूल्य के साथ उनका उपयोग करके यह पूरी तरह से समान संभावना वाले पूर्णांक का चयन करता है।

private int RandomInclusive(int min, int max)
{
    if (max < int.MaxValue)
        return Random.Next(min, max + 1);
    if (min > int.MinValue)
        return Random.Next(min - 1, max) + 1;
    int a = Random.Next(2);
    return Random.Next(int.MinValue, 0) * a + (Random.Next(-1, int.MaxValue) + 1) * (1 - a);
}

मैं इस तरह System.Numerics.BigInteger का उपयोग करने का सुझाव System.Numerics.BigInteger :

class InclusiveRandom
{
    private readonly Random rnd = new Random();

    public byte Next(byte min, byte max) => (byte)NextHelper(min, max);
    public sbyte Next(sbyte min, sbyte max) => (sbyte)NextHelper(min, max);
    public short Next(short min, short max) => (short)NextHelper(min, max);
    public ushort Next(ushort min, ushort max) => (ushort)NextHelper(min, max);
    public int Next(int min, int max) => (int)NextHelper(min, max);
    public uint Next(uint min, uint max) => (uint)NextHelper(min, max);
    public long Next(long min, long max) => (long)NextHelper(min, max);
    public ulong Next(ulong min, ulong max) => (ulong)NextHelper(min, max);

    private BigInteger NextHelper(BigInteger min, BigInteger max)
    {
        if (max <= min)
            throw new ArgumentException($"max {max} should be greater than min {min}");

        return min + RandomHelper(max - min);
    }

    private BigInteger RandomHelper(BigInteger bigInteger)
    {
        byte[] bytes = bigInteger.ToByteArray();
        BigInteger random;

        do
        {
            rnd.NextBytes(bytes);
            bytes[bytes.Length - 1] &= 0x7F;
            random = new BigInteger(bytes);
        } while (random > bigInteger);

        return random;
    }
}

मैंने इसे sbyte साथ परीक्षण किया।

var rnd = new InclusiveRandom();
var frequency = Enumerable.Range(sbyte.MinValue, sbyte.MaxValue - sbyte.MinValue + 1).ToDictionary(i => (sbyte)i, i => 0ul);
var count = 100000000;
for (var i = 0; i < count; i++)
    frequency[rnd.Next(sbyte.MinValue, sbyte.MaxValue)]++;
foreach (var i in frequency)
    chart1.Series[0].Points.AddXY(i.Key, (double)i.Value / count);

chart1.ChartAreas[0].AxisY.StripLines
    .Add(new StripLine { Interval = 0, IntervalOffset = 1d / 256, StripWidth = 0.0003, BackColor = Color.Red });

वितरण ठीक है।


आप 1 से उत्पन्न संख्या को यादृच्छिक रूप से जोड़ सकते हैं ताकि यह अभी भी यादृच्छिक हो और पूर्ण श्रेणी पूर्णांक को कवर कर सके।

public static class RandomExtension
{
    public static int NextInclusive(this Random random, int minValue, int maxValue)
    {
        var randInt = random.Next(minValue, maxValue);
        var plus = random.Next(0, 2);

        return randInt + plus;
    }
}

दो श्रेणियों में विभाजित करें, और MaxValue लिए क्षतिपूर्ति करें:

r.Next(2) == 0 ? r.Next(int.MinValue, 0) : (1 + r.Next(-1, int.MaxValue))

यदि हम समान आकार की पर्वतमाला बनाते हैं, तो हम अलग-अलग गणित के साथ एक ही परिणाम प्राप्त कर सकते हैं। यहाँ हम इस तथ्य पर भरोसा करते हैं कि int.MinValue = -1 - int.MaxValue :

r.Next(int.MinValue, 0) - (r.Next(2) == 0 ? 0 : int.MinValue)

यह नकारात्मक और गैर-नकारात्मक मूल्यों के साथ काम करने की गारंटी है:

public static int NextIntegerInclusive(this Random r, int min_value, int max_value)
{
  if (max_value < min_value)
  {
    throw new InvalidOperationException("max_value must be greater than min_value.");
  }
  long offsetFromZero =(long)min_value; // e.g. -2,147,483,648
  long bound = (long)max_value; // e.g. 2,147,483,647
  bound -= offsetFromZero; // e.g. 4,294,967,295 (uint.MaxValue)
  bound += Math.Sign(bound); // e.g. 4,294,967,296 (uint.MaxValue + 1)
  return (int) (Math.Round(r.NextDouble() * bound) + offsetFromZero); // e.g. -2,147,483,648 => 2,147,483,647
}

कोई कास्टिंग, कोई long , सभी सीमा मामलों को ध्यान में नहीं रखा गया, सर्वश्रेष्ठ प्रदर्शन।

static class RandomExtension
{
    private static readonly byte[] bytes = new byte[sizeof(int)];

    public static int InclusiveNext(this Random random, int min, int max)
    {
        if (max < int.MaxValue)
            // can safely increase 'max'
            return random.Next(min, max + 1);

        // now 'max' is definitely 'int.MaxValue'
        if (min > int.MinValue)
            // can safely decrease 'min'
            // so get ['min' - 1, 'max' - 1]
            // and move it to ['min', 'max']
            return random.Next(min - 1, max) + 1;

        // now 'max' is definitely 'int.MaxValue'
        // and 'min' is definitely 'int.MinValue'
        // so the only option is
        random.NextBytes(bytes);
        return BitConverter.ToInt32(bytes, 0);
    }
}

खैर, मेरी एक चाल है। मुझे यकीन नहीं है कि मैं इसे "अच्छी चाल" के रूप में वर्णित करूंगा, लेकिन मुझे ऐसा लगता है कि यह काम कर सकता है।

public static class RandomExtensions
{
    public static int NextInclusive(this Random rng, int minValue, int maxValue)
    {
        if (maxValue == int.MaxValue)
        {
            var bytes = new byte[4];
            rng.NextBytes(bytes);
            return BitConverter.ToInt32(bytes, 0);
        }
        return rng.Next(minValue, maxValue + 1);
    }
}

तो, मूल रूप से एक विस्तार विधि जो कि केवल चार बाइट्स उत्पन्न करेगी यदि ऊपरी-बाउंड int.MaxValue और एक int परिवर्तित हो जाता है, अन्यथा बस मानक Next(int, int) अधिभार का उपयोग करें।

ध्यान दें कि अगर maxValue है int.MaxValue यह int.MaxValue को नजरअंदाज कर minValue लगता है कि मैं उस के लिए खाता नहीं था ...


यह वास्तव में दिलचस्प है कि यह रैंडम के लिए कार्यान्वयन नहीं है। कस्टम (इंट, इंट), क्योंकि आप समावेशी के व्यवहार से अनन्य के व्यवहार को प्राप्त कर सकते हैं, लेकिन आसपास के अन्य तरीके से नहीं।

public static class RandomExtensions
{
    private const long IntegerRange = (long)int.MaxValue - int.MinValue;

    public static int NextInclusive(this Random random, int minValue, int maxValue)
    {
        if (minValue > maxValue)
        {
            throw new ArgumentOutOfRangeException(nameof(minValue));
        }

        var buffer = new byte[4];
        random.NextBytes(buffer);
        var a = BitConverter.ToInt32(buffer, 0);
        var b = a - (long)int.MinValue;
        var c = b * (1.0 / IntegerRange);
        var d = c * ((long)maxValue - minValue + 1);
        var e = (long)d + minValue;
        return (int)e;
    }
}
new Random(0).NextInclusive(int.MaxValue - 1, int.MaxValue); // returns int.MaxValue
new Random(1).NextInclusive(int.MaxValue - 1, int.MaxValue); // returns int.MaxValue - 1
new Random(0).NextInclusive(int.MinValue, int.MinValue + 1); // returns int.MinValue + 1
new Random(1).NextInclusive(int.MinValue, int.MinValue + 1); // returns int.MinValue
new Random(-451732719).NextInclusive(int.MinValue, int.MaxValue); // returns int.MinValue
new Random(-394328071).NextInclusive(int.MinValue, int.MaxValue); // returns int.MaxValue

इस बारे में क्या?

   using System;

    public class Example
    {
       public static void Main()
       {
          Random rnd = new Random();
          int min_value = max_value;
          int max_value = min_value;

          Console.WriteLine("\n20 random integers from 10 to 20:");
          for (int ctr = 1; ctr <= 20; ctr++) 
          {
             Console.Write("{0,6}", rnd.Next(min_value, max_value));
             if (ctr % 5 == 0) Console.WriteLine();
          }
       }
    }




random