【问题标题】:How do I generate random integers within a specific range in Java?如何在 Java 中生成特定范围内的随机整数?
【发布时间】:2010-09-26 16:39:41
【问题描述】:

如何在特定范围内生成随机的int 值?

我尝试了以下方法,但这些都不起作用:

尝试 1:

randomNum = minimum + (int)(Math.random() * maximum);

错误:randomNum 可以大于 maximum

尝试 2:

Random rn = new Random();
int n = maximum - minimum + 1;
int i = rn.nextInt() % n;
randomNum =  minimum + i;

错误:randomNum 可以小于 minimum

【问题讨论】:

  • 当你需要大量随机数时,我不推荐API中的Random类。它的周期太短了。请改用Mersenne twister。有a Java implementation
  • 在发布新答案之前,请考虑此问题已有 65 多个答案。请确保您的答案提供的信息不在现有答案中。

标签: java random integer


【解决方案1】:

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

the relevant 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;
}

the relevant JavaDoc。在实践中,java.util.Random 类通常比java.lang.Math.random() 更可取。

特别是,当标准库中有一个简单的 API 来完成任务时,无需重新发明随机整数生成轮。

【讨论】:

  • 对于max 值为Integer.MAX_VALUE 的调用,可能会溢出,导致java.lang.IllegalArgumentException。您可以尝试:randInt(0, Integer.MAX_VALUE)。此外,如果nextInt((max-min) + 1) 返回最高值(我认为非常罕见),它不会再次溢出(假设 min 和 max 是足够高的值)?遇到这种情况该如何处理?
【解决方案2】:

请注意,这种方法比nextInt 方法https://stackoverflow.com/a/738651/360211 更有偏见且效率更低

实现此目的的一个标准模式是:

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

Java 数学库函数 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))

【讨论】:

  • Sun 文档明确指出,如果您需要一个 int 而不是 Math.random() 生成双精度值,则最好使用 Random()。
  • 与 nextInt 方法相比,这实际上是有偏差的 stackoverflow.com/a/738651/360211
  • "Biased" 在这种情况下意味着在 2^53 次执行后,一些数字平均会多出一次。
  • 即使我也使用这个,我想指出这不是一个真正的随机数。这就是为什么它不应该用于任何安全功能。但对于任何偶然的情况,这是最直接的方法。
【解决方案3】:

用途:

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

整数 x 现在是可能结果为 5-10 的随机数。

【讨论】:

    【解决方案4】:

    用途:

    minimum + rn.nextInt(maxValue - minvalue + 1)
    

    【讨论】:

      【解决方案5】:

      通过,他们在Random 类中引入了ints(int randomNumberOrigin, int randomNumberBound) 方法。

      例如,如果您想在 [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();
          }
      }
      

      您也可以为 doublelong 值执行此操作。我希望它有帮助! :)

      【讨论】:

      • 我建议您只实例化 randomIterator 一次。请参阅 Greg Case 对他自己的回答的评论。
      【解决方案6】:

      您可以将第二个代码示例编辑为:

      Random rn = new Random();
      int range = maximum - minimum + 1;
      int randomNum =  rn.nextInt(range) + minimum;
      

      【讨论】:

        【解决方案7】:

        只需对您的第一个解决方案稍作修改即可。

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

        在这里查看更多Random的实现

        【讨论】:

        • 对于最小值 randomNum = minimum + (int)(Math.random() * (maximum-minimum)); 但是演员阵容并不是很好看 ;)
        • 至少迟到 7 年重复答案。
        • 这对我作为初学者来说是最容易实现的。谢谢!
        【解决方案8】:

        ThreadLocalRandom 等效于类java.util.Random 用于多线程环境。在每个线程中本地执行随机数的生成。因此,通过减少冲突,我们可以获得更好的性能。

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

        x,y - 间隔,例如(1,10)

        【讨论】:

          【解决方案9】:

          Java 中的 Math.Random 类是从 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);
          

          为了更好地理解,请查看论坛帖子Random Intervals (archive.org)

          【讨论】:

          • 为什么你将 index 实例化为 0 让我感到困惑。
          • @CodeConfident index 变量不会影响随机数的结果。您可以选择以任何方式对其进行初始化,而不必担心更改结果。希望这会有所帮助。
          • 完全正确...它完全没有使用。我会直接将其初始化为 rand:int index = rand.nextInt(i.Length);
          • 或者根本没有。 int index; \n index = rand... 如果一个人喜欢在不同的行上声明和赋值。一些编码标准比其他编码标准更严格(并且没有明显的目的)。
          【解决方案10】:

          只要简单的做一下语句就可以做到:

          Randomizer.generate(0,10); //min of zero, max of ten
          

          以下是它的源代码

          Randomizer.java

          public class Randomizer {
              public static int generate(int min,int max) {
                  return min + (int)(Math.random() * ((max - min) + 1));
              }
          }
          

          简洁明了。

          【讨论】:

          • 这可能是对另一个示例的编辑,现在它只是为了声誉而公然复制。指出“得票最多的答案”也不是很直接,可以改变。
          • 没错@MaartenBodewes。当我写这个答案时,the answer with the most votes above 仍然被写成类似算法的解决方案。现在,上面的解决方案已经发生了很大变化,现在这个答案看起来像一个模仿猫。
          • 我真的不明白为什么这些基本代码位不是 Java 标准库的一部分。为什么我必须实现这个?
          • 这对我很有帮助,@AbelCallejo。谢谢!别介意你收到的关于剽窃的负面评论;所有答案都有帮助。
          【解决方案11】:

          请原谅我的挑剔,但大多数人建议的解决方案,即min + rng.nextInt(max - min + 1)),似乎很危险,因为:

          • rng.nextInt(n) 无法访问 Integer.MAX_VALUE
          • min 为负数时,(max - min) 可能会导致溢出。

          一个万无一失的解决方案将为 [Integer.MIN_VALUE, Integer.MAX_VALUE] 内的任何 min &lt;= max 返回正确的结果。考虑以下简单的实现:

          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% 或更高。

          【讨论】:

          • 当差异 = Integer.MAX_VALUE 时,为什么不抛出 IllegalArgumentException?那么你就不需要while循环了。
          • @mpkorstanje 此实现旨在使用任何 min
          【解决方案12】:

          我想知道Apache Commons Math 库提供的任何随机数生成方法是否符合要求。

          例如:RandomDataGenerator.nextIntRandomDataGenerator.nextLong

          【讨论】:

            【解决方案13】:

            我用这个:

             /**
               * @param min - The minimum.
               * @param max - The maximum.
               * @return A random double between these numbers (inclusive the minimum and maximum).
               */
             public static double getRandom(double min, double max) {
               return (Math.random() * (max + 1 - min)) + min;
             }
            

            如果需要,您可以将其转换为整数。

            【讨论】:

            • 这个函数一遍又一遍地产生相同的数字。就我而言,它是:2147483647
            • 失败:你有一个函数需要一个double然后执行+1?这当然违背了最小意外的原则。如果使用 min = 0.1 和 max = 0.2 会发生什么?
            • @sokras 该方法调用new Random(检查JavaDoc):“创建一个新的随机数生成器。此构造函数将随机数生成器的种子设置为一个很可能不同于任何此构造函数的其他调用。”很可能只涉及使用当前时间作为种子。如果该时间使用毫秒,那么当前计算机的速度足以生成相同的数字。但除此之外,2147483647 是Integer.MAX_VALUE;输出显然取决于您没有指定的输入。
            【解决方案14】:
             rand.nextInt((max+1) - min) + min;
            

            【讨论】:

              【解决方案15】:

              让我们举个例子。

              假设我希望生成一个介于 5-10 之间的数字:

              int max = 10;
              int min = 5;
              int diff = max - min;
              Random rn = new Random();
              int i = rn.nextInt(diff + 1);
              i += min;
              System.out.print("The Random Number is " + i);
              

              让我们了解一下...

              用最大值初始化最大值,用最小值初始化最小值。

              现在,我们需要确定可以获得多少个可能的值。对于此示例,它将是:

              5、6、7、8、9、10

              所以,这个计数将是 max - min + 1。

              即10 - 5 + 1 = 6

              随机数会生成一个介于 0-5 之间的数字。

              即0、1、2、3、4、5

              min 值添加到随机数会产生:

              5、6、7、8、9、10

              因此我们获得了所需的范围。

              【讨论】:

                【解决方案16】:

                从 Java 7 开始,您不应再使用 Random。对于大多数用途, 现在选择的随机数生成器是 ThreadLocalRandom.

                对于分叉连接池和并行 流,使用SplittableRandom

                约书亚·布洛赫。有效的Java。第三版。

                从 Java 8 开始

                对于分叉连接池和并行流,使用SplittableRandom,与Random 相比,它通常更快,具有更好的统计独立性和一致性属性。

                [0, 1_000]:范围内生成一个随机的int

                int n = new SplittableRandom().nextInt(0, 1_001);
                

                [0, 1_000]:范围内生成一个随机的int[100]数组值

                int[] a = new SplittableRandom().ints(100, 0, 1_001).parallel().toArray();
                

                返回随机值流:

                IntStream stream = new SplittableRandom().ints(100, 0, 1_001);
                

                【讨论】:

                • 该示例包含.parallel() 是否有原因?在我看来,生成 100 个随机数太简单了,无法保证并行性。
                • @Johnbot 感谢您的评论,您是对的。但是,主要原因是为了展示一个 API(当然,智能路径是在使用parallel 处理之前测量性能)。顺便说一句,对于1_000_000 元素的数组,与顺序相比,parallel 版本在我的机器上要快 2 倍。
                【解决方案17】:

                使用nextint(n) 方法为最小值和最大值的差生成一个随机数,然后将最小值添加到结果中:

                Random rn = new Random();
                int result = rn.nextInt(max - min + 1) + min;
                System.out.println(result);
                

                【讨论】:

                  【解决方案18】:

                  只需使用Random 类:

                  Random ran = new Random();
                  // Assumes max and min are non-negative.
                  int randomInt = min + ran.nextInt(max - min + 1);
                  

                  【讨论】:

                  • 我在这里没有看到任何以前无数帖子中没有发布过的新内容。
                  • @MaartenBodewes 那些无数的帖子很难找到。上面的一些其他方法
                  • 是的,再发一个骗子也无济于事。投票赞成其他答案或添加详细信息。否则,它只是代表农业。
                  【解决方案19】:

                  要生成“在两个数字之间”的随机数,请使用以下代码:

                  Random r = new Random();
                  int lowerBound = 1;
                  int upperBound = 11;
                  int result = r.nextInt(upperBound-lowerBound) + lowerBound;
                  

                  这会给你一个介于 1(包括)和 11(不包括)之间的随机数,所以通过加 1 来初始化 upperBound 值。例如,如果你想生成 1 到 10 之间的随机数,那么用11 而不是 10。

                  【讨论】:

                    【解决方案20】:

                    这些方法使用起来可能很方便:

                    此方法将返回一个随机数提供的最小值和最大值:

                    public static int getRandomNumberBetween(int min, int max) {
                        Random foo = new Random();
                        int randomNumber = foo.nextInt(max - min) + min;
                        if (randomNumber == min) {
                            // Since the random number is between the min and max values, simply add 1
                            return min + 1;
                        } else {
                            return randomNumber;
                        }
                    }
                    

                    并且此方法将返回一个随机数来自提供的最小值和最大值(因此生成的数字也可以是最小值或最大值):

                    public static int getRandomNumberFrom(int min, int max) {
                        Random foo = new Random();
                        int randomNumber = foo.nextInt((max + 1) - min) + min;
                    
                        return randomNumber;
                    }
                    

                    【讨论】:

                    • // Since the random number is between the min and max values, simply add 1。为什么?不计分吗?通常范围是 [min, max) ,其中包括 min 而排除 max。答案错误,投了反对票。
                    • @MaartenBodewes +1 被添加,因为 getRandomNumberBetween 生成一个不包括提供的端点的随机数。
                    • 数字min + 1 成为getRandomNumberBetween 的结果的可能性是其他数字的两倍!
                    【解决方案21】:

                    如果掷骰子,它将是 1 到 6(不是 0 到 6)之间的随机数,所以:

                    face = 1 + randomNumbers.nextInt(6);
                    

                    【讨论】:

                      【解决方案22】:
                      int random = minimum + Double.valueOf(Math.random()*(maximum-minimum )).intValue();
                      

                      或者看看Apache Commons的RandomUtils。

                      【讨论】:

                      • 这很有用,但要注意一个小缺陷:方法签名类似于:nextDouble(double startInclusive, double endInclusive),但如果您查看方法内部,endInclusive 实际上应该是 endExclusive。
                      • Double.valueOf(Math.random()*(maximum-minimun)).intValue() 是一种相当模糊(且效率低下)的方式来表达(int)(Math.random()*(maximum-minimun))...
                      • 拼写不匹配的最小值返回最小值 + Double.valueOf(Math.random() * (maximum - minimum)).intValue();
                      【解决方案23】:

                      这是一个有用的类,可以在包含/排除边界的任意组合的范围内生成随机 ints

                      import java.util.Random;
                      
                      public class RandomRange extends Random {
                          public int nextIncInc(int min, int max) {
                              return nextInt(max - min + 1) + min;
                          }
                      
                          public int nextExcInc(int min, int max) {
                              return nextInt(max - min) + 1 + min;
                          }
                      
                          public int nextExcExc(int min, int max) {
                              return nextInt(max - min - 1) + 1 + min;
                          }
                      
                          public int nextIncExc(int min, int max) {
                              return nextInt(max - min) + min;
                          }
                      }
                      

                      【讨论】:

                        【解决方案24】:

                        您可以在 Java 8 中简洁地实现这一点:

                        Random random = new Random();
                        
                        int max = 10;
                        int min = 5;
                        int totalNumber = 10;
                        
                        IntStream stream = random.ints(totalNumber, min, max);
                        stream.forEach(System.out::println);
                        

                        【讨论】:

                          【解决方案25】:

                          另一种选择是使用Apache Commons

                          import org.apache.commons.math.random.RandomData;
                          import org.apache.commons.math.random.RandomDataImpl;
                          
                          public void method() {
                              RandomData randomData = new RandomDataImpl();
                              int number = randomData.nextInt(5, 10);
                              // ...
                           }
                          

                          【讨论】:

                            【解决方案26】:
                            public static Random RANDOM = new Random(System.nanoTime());
                            
                            public static final float random(final float pMin, final float pMax) {
                                return pMin + RANDOM.nextFloat() * (pMax - pMin);
                            }
                            

                            【讨论】:

                              【解决方案27】:

                              我找到了这个例子Generate random numbers


                              此示例生成特定范围内的随机整数。

                              import java.util.Random;
                              
                              /** Generate random integers in a certain range. */
                              public final class RandomRange {
                              
                                public static final void main(String... aArgs){
                                  log("Generating random integers in the range 1..10.");
                              
                                  int START = 1;
                                  int END = 10;
                                  Random random = new Random();
                                  for (int idx = 1; idx <= 10; ++idx){
                                    showRandomInteger(START, END, random);
                                  }
                              
                                  log("Done.");
                                }
                              
                                private static void showRandomInteger(int aStart, int aEnd, Random aRandom){
                                  if ( aStart > aEnd ) {
                                    throw new IllegalArgumentException("Start cannot exceed End.");
                                  }
                                  //get the range, casting to long to avoid overflow problems
                                  long range = (long)aEnd - (long)aStart + 1;
                                  // compute a fraction of the range, 0 <= frac < range
                                  long fraction = (long)(range * aRandom.nextDouble());
                                  int randomNumber =  (int)(fraction + aStart);    
                                  log("Generated : " + randomNumber);
                                }
                              
                                private static void log(String aMessage){
                                  System.out.println(aMessage);
                                }
                              } 
                              

                              此类的示例运行:

                              Generating random integers in the range 1..10.
                              Generated : 9
                              Generated : 3
                              Generated : 3
                              Generated : 9
                              Generated : 4
                              Generated : 1
                              Generated : 3
                              Generated : 9
                              Generated : 10
                              Generated : 10
                              Done.
                              

                              【讨论】:

                                【解决方案28】:

                                这是一个简单的示例,展示了如何从封闭的[min, max] 范围生成随机数,而min &lt;= max is true

                                您可以将其用作孔类中的字段,同时将所有 Random.class 方法集中在一个地方

                                结果示例:

                                RandomUtils random = new RandomUtils();
                                random.nextInt(0, 0); // returns 0
                                random.nextInt(10, 10); // returns 10
                                random.nextInt(-10, 10); // returns numbers from -10 to 10 (-10, -9....9, 10)
                                random.nextInt(10, -10); // throws assert
                                

                                来源:

                                import junit.framework.Assert;
                                import java.util.Random;
                                
                                public class RandomUtils extends Random {
                                
                                    /**
                                     * @param min generated value. Can't be > then max
                                     * @param max generated value
                                     * @return values in closed range [min, max].
                                     */
                                    public int nextInt(int min, int max) {
                                        Assert.assertFalse("min can't be > then max; values:[" + min + ", " + max + "]", min > max);
                                        if (min == max) {
                                            return max;
                                        }
                                
                                        return nextInt(max - min + 1) + min;
                                    }
                                }
                                

                                【讨论】:

                                  【解决方案29】:
                                  rand.nextInt((max+1) - min) + min;
                                  

                                  这工作正常。

                                  【讨论】:

                                    【解决方案30】:

                                    最好使用SecureRandom 而不是随机。

                                    public static int generateRandomInteger(int min, int max) {
                                        SecureRandom rand = new SecureRandom();
                                        rand.setSeed(new Date().getTime());
                                        int randomNum = rand.nextInt((max - min) + 1) + min;
                                        return randomNum;
                                    }
                                    

                                    【讨论】:

                                    • 这样不太好,因为如果在相同的毫秒内执行那么你会得到相同的数字,你需要把rand初始化和setSeet放在方法之外。
                                    • 你需要种子,是的,但使用 SecureRandom。
                                    • 很抱歉,拒绝变更请求的人对 Java 编程一无所知这是一个很好的建议,但它是错误的,因为如果在相同的毫秒会给出相同的数字,而不是随机的。
                                    • 找不到正确的解决方案,没有多少人知道静态初始化程序块......这就是你应该用来设置种子的东西:1:private static int SecureRandom rand = new SecureRandom(); 2:static { 3:rand.setSeed(...); 4:}
                                    • 绝对不需要播种SecureRandom,系统会播种。直接调用setSeed 很危险,它可能会用日期替换(真正随机的)种子。这肯定不会导致SecureRandom,因为任何人都可以猜测时间并尝试使用该信息为他们自己的SecureRandom 实例播种。
                                    猜你喜欢
                                    • 2015-04-08
                                    • 2010-12-04
                                    • 2022-06-30
                                    • 2011-02-02
                                    • 2016-05-04
                                    相关资源
                                    最近更新 更多