كيف أقوم بتوليد أعداد صحيحة عشوائية ضمن نطاق معين في Java؟

سئل على ١٢ ديسمبر ٢٠٠٨  ·  تمت مشاهدة 4.2M مرة  ·  مصدر

user42155 picture
في ١٢ ديسمبر ٢٠٠٨

كيف يمكنني إنشاء قيمة int عشوائية في نطاق معين؟

لقد جربت ما يلي ، لكن هذه لا تعمل:

المحاولة 1:

randomNum = minimum + (int)(Math.random() * maximum);
// Bug: `randomNum` can be bigger than `maximum`.

المحاولة 2:

Random rn = new Random();
int n = maximum - minimum + 1;
int i = rn.nextInt() % n;
randomNum =  minimum + i;
// Bug: `randomNum` can be smaller than `minimum`.

الإجابات

Greg Case picture
في ١٢ ديسمبر ٢٠٠٨
3908

في Java 1.7 أو أحدث ، الطريقة القياسية للقيام بذلك هي كما يلي:

import java.util.concurrent.ThreadLocalRandom;

// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
int randomNum = ThreadLocalRandom.current().nextInt(min, max + 1);

راجع ملف JavaDoc . يتميز هذا النهج بعدم الحاجة إلى التهيئة الصريحة لمثيل java.util.Random ، والذي يمكن أن يكون مصدر ارتباك وخطأ إذا تم استخدامه بشكل غير مناسب.

ومع ذلك ، لا توجد طريقة لتعيين البذور بشكل صريح ، لذا قد يكون من الصعب إعادة إنتاج النتائج في المواقف التي يكون فيها ذلك مفيدًا مثل اختبار حالات اللعبة أو حفظها أو ما شابه ذلك. في هذه الحالات ، يمكن استخدام تقنية pre-Java 1.7 الموضحة أدناه.

قبل Java 1.7 ، كانت الطريقة القياسية للقيام بذلك كما يلي:

import java.util.Random;

/**
 * Returns a pseudo-random number between min and max, inclusive.
 * The difference between min and max can be at most
 * <code>Integer.MAX_VALUE - 1</code>.
 *
 * @param min Minimum value
 * @param max Maximum value.  Must be greater than min.
 * @return Integer between min and max, inclusive.
 * @see java.util.Random#nextInt(int)
 */
public static int randInt(int min, int max) {

    // NOTE: This will (intentionally) not run as written so that folks
    // copy-pasting have to think about how to initialize their
    // Random instance.  Initialization of the Random instance is outside
    // the main scope of the question, but some decent options are to have
    // a field that is initialized once and then re-used as needed or to
    // use ThreadLocalRandom (if using at least Java 1.7).
    // 
    // In particular, do NOT do 'Random rand = new Random()' here or you
    // will get not very good / not very random results.
    Random rand;

    // nextInt is normally exclusive of the top value,
    // so add 1 to make it inclusive
    int randomNum = rand.nextInt((max - min) + 1) + min;

    return randomNum;
}

راجع ملف JavaDoc . من الناحية العملية ، غالبًا ما يُفضل فئة java.util.Random على java.lang.Math.random () .

على وجه الخصوص ، ليست هناك حاجة لإعادة اختراع عجلة توليد الأعداد الصحيحة العشوائية عندما تكون هناك واجهة برمجة تطبيقات مباشرة داخل المكتبة القياسية لإنجاز المهمة.

TJ_Fischer picture
في ١٢ ديسمبر ٢٠٠٨
1442

لاحظ أن هذا النهج أكثر انحيازًا وأقل كفاءة من نهج nextInt ، https://stackoverflow.com/a/738651/360211

أحد الأنماط القياسية لتحقيق ذلك هو:

Min + (int)(Math.random() * ((Max - Min) + 1))

تقوم وظيفة مكتبة Java Math Math.random () بإنشاء قيمة مزدوجة في النطاق [0,1) . لاحظ أن هذا النطاق لا يشمل الرقم 1.

من أجل الحصول على نطاق محدد من القيم أولاً ، تحتاج إلى الضرب في مقدار نطاق القيم التي تريد تغطيتها.

Math.random() * ( Max - Min )

يؤدي هذا إلى إرجاع قيمة في النطاق [0,Max-Min) ، حيث لا يتم تضمين "Max-Min".

على سبيل المثال ، إذا كنت تريد [5,10) ، فأنت بحاجة إلى تغطية خمس قيم صحيحة حتى تستخدمها

Math.random() * 5

سيؤدي هذا إلى إرجاع قيمة في النطاق [0,5) ، حيث لا يتم تضمين 5.

أنت الآن بحاجة إلى تحويل هذا النطاق إلى النطاق الذي تستهدفه. يمكنك القيام بذلك عن طريق إضافة قيمة Min.

Min + (Math.random() * (Max - Min))

ستحصل الآن على قيمة في النطاق [Min,Max) . باتباع مثالنا ، هذا يعني [5,10) :

5 + (Math.random() * (10 - 5))

لكن ، هذا لا يزال لا يشمل Max وأنت تحصل على قيمة مزدوجة. من أجل تضمين قيمة Max ، تحتاج إلى إضافة 1 إلى معلمة النطاق (Max - Min) ثم اقتطاع الجزء العشري عن طريق الإرسال إلى int. يتم تحقيق ذلك عن طريق:

Min + (int)(Math.random() * ((Max - Min) + 1))

وهناك لديك. قيمة عدد صحيح عشوائي في النطاق [Min,Max] ، أو حسب المثال [5,10] :

5 + (int)(Math.random() * ((10 - 5) + 1))
jackson picture
في ٤ سبتمبر ٢٠٠٩
393

استعمال:

Random ran = new Random();
int x = ran.nextInt(6) + 5;

العدد الصحيح x الآن هو الرقم العشوائي الذي له نتيجة محتملة 5-10 .

krosenvold picture
في ١٢ ديسمبر ٢٠٠٨
165

استعمال:

minimum + rn.nextInt(maxValue - minvalue + 1)
Alexis C. picture
في ٢٦ نوفمبر ٢٠١٤
154

باستخدام ، قدّموا الطريقة ints(int randomNumberOrigin, int randomNumberBound) في فئة Random .

على سبيل المثال ، إذا كنت تريد إنشاء خمسة أعداد صحيحة عشوائية (أو واحد) في النطاق [0 ، 10] ، فقط قم بما يلي:

Random r = new Random();
int[] fiveRandomNumbers = r.ints(5, 0, 11).toArray();
int randomNumber = r.ints(1, 0, 11).findFirst().getAsInt();

المعلمة الأولى تشير فقط إلى حجم IntStream الذي تم إنشاؤه (وهي طريقة التحميل الزائد لتلك التي تنتج IntStream غير محدود).

إذا كنت بحاجة إلى إجراء عدة مكالمات منفصلة ، فيمكنك إنشاء مكرر بدائي لانهائي من الدفق:

public final class IntRandomNumberGenerator {

    private PrimitiveIterator.OfInt randomIterator;

    /**
     * Initialize a new random number generator that generates
     * random numbers in the range [min, max]
     * @param min - the min value (inclusive)
     * @param max - the max value (inclusive)
     */
    public IntRandomNumberGenerator(int min, int max) {
        randomIterator = new Random().ints(min, max + 1).iterator();
    }

    /**
     * Returns a random number in the range (min, max)
     * @return a random number in the range (min, max)
     */
    public int nextInt() {
        return randomIterator.nextInt();
    }
}

يمكنك أيضًا القيام بذلك مقابل قيم double و long . اتمني ان يكون مفيدا! :)

Bill the Lizard picture
في ١٢ ديسمبر ٢٠٠٨
109

يمكنك تعديل مثال الرمز الثاني الخاص بك إلى:

Random rn = new Random();
int range = maximum - minimum + 1;
int randomNum =  rn.nextInt(range) + minimum;
hexabunny picture
في ١٢ مارس ٢٠١٥
102

يكفي تعديل بسيط لحلك الأول.

Random rand = new Random();
randomNum = minimum + rand.nextInt((maximum - minimum) + 1);

شاهد المزيد هنا لتنفيذ Random

andrew picture
في ١٣ فبراير ٢٠١٣
84

ThreadLocalRandom للفئة java.util.Random للبيئة متعددة مؤشرات الترابط. يتم إنشاء رقم عشوائي محليًا في كل من الخيوط. لذلك لدينا أداء أفضل من خلال تقليل الصراعات.

int rand = ThreadLocalRandom.current().nextInt(x,y);

x ، y - الفواصل الزمنية مثل (1،10)

Matt R picture
في ٨ يناير ٢٠٠٩
71

فئة Math.Random في Java تعتمد على 0. لذا ، إذا كتبت شيئًا كهذا:

Random rand = new Random();
int x = rand.nextInt(10);

x سيكون بين 0-9 شاملًا.

لذلك ، بالنظر إلى المصفوفة التالية من العناصر 25 ، فإن الكود لإنشاء رقم عشوائي بين 0 (أساس المصفوفة) و array.length سيكون:

String[] i = new String[25];
Random rand = new Random();
int index = 0;

index = rand.nextInt( i.length );

نظرًا لأن i.length سيعود 25 ، فإن nextInt( i.length ) سيعرض رقمًا بين النطاق 0-24 . الخيار الآخر هو استخدام Math.Random والذي يعمل بنفس الطريقة.

index = (int) Math.floor(Math.random() * i.length);

لفهم أفضل ، تحقق من مشاركة المنتدى فترات عشوائية (archive.org) .

Joel Sj&#246;strand picture
في ١٠ يناير ٢٠١١
50

سامحني لكوني صعب المراس ، لكن الحل الذي اقترحته الأغلبية ، أي min + rng.nextInt(max - min + 1)) ، يبدو محفوفًا بالمخاطر نظرًا لحقيقة أن:

  • rng.nextInt(n) لا يمكنه الوصول إلى Integer.MAX_VALUE .
  • قد يتسبب (max - min) حدوث تجاوز عندما يكون min سالبًا.

قد يعرض الحل المضمون النتائج الصحيحة لأي min <= max ضمن [ Integer.MIN_VALUE ، Integer.MAX_VALUE ]. خذ بعين الاعتبار التنفيذ الساذج التالي:

int nextIntInRange(int min, int max, Random rng) {
   if (min > max) {
      throw new IllegalArgumentException("Cannot draw random int from invalid range [" + min + ", " + max + "].");
   }
   int diff = max - min;
   if (diff >= 0 && diff != Integer.MAX_VALUE) {
      return (min + rng.nextInt(diff + 1));
   }
   int i;
   do {
      i = rng.nextInt();
   } while (i < min || i > max);
   return i;
}

على الرغم من عدم فعاليته ، لاحظ أن احتمال النجاح في الحلقة while سيكون دائمًا 50٪ أو أعلى.