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

以下方法存在与整数溢出相关的错误:

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

当前回答

您可以使用以下方法来执行此操作:

int range = 10;
int min = 5
Random r = new Random();
int = r.nextInt(range) + min;

其他回答

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

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

注意,该方法比下一个Int方法更偏向且效率更低,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 + (Math.random() * (Max - Min))

现在,您将获得范围为[Min,Max)的值。按照我们的示例,这意味着[5,10):

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

但是,这仍然不包括Max,您将得到双倍的值。为了获得包含的最大值,您需要向范围参数(Max-Min)添加1,然后通过强制转换为int来截断小数部分。这可以通过以下方式实现:

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

在[Min,Max]范围内的随机整数值,或者按照示例[5,10]:

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

为了避免重复多次所说的内容,我为那些需要加密更强的伪随机数生成器的人展示了一种替代方法,方法是使用SecureRandom类,该类扩展了random类。从源代码中可以看到:

此类提供加密强随机数生成器(RNG)。密码强随机数最小符合使用FIPS中指定的统计随机数生成器测试140-2,加密模块的安全要求,第4.9.1节。此外,SecureRandom必须产生非确定性输出。因此,传递给SecureRandom对象的任何种子材料必须不可预测,并且所有SecureRandom输出序列必须如RFC 1750:随机性中所述,加密性强安全建议。调用者通过no参数获得SecureRandom实例构造函数或getInstance方法之一:SecureRandom随机=新的SecureRandum();许多SecureRandom实现采用伪随机数生成器的形式(PRNG),这意味着他们使用确定性算法来生成来自真实随机种子的伪随机序列。其他实施方式可以产生真正的随机数,而其他人可以使用组合这两种技术的组合。

要生成介于最小值和最大值之间的随机数,请执行以下操作:

public static int generate(SecureRandom secureRandom, int min, int max) {
        return min + secureRandom.nextInt((max - min) + 1);
}

对于给定的最小(含)和最大(不含)值:

return min + secureRandom.nextInt((max - min));

运行代码示例:

public class Main {

    public static int generate(SecureRandom secureRandom, int min, int max) {
        return min + secureRandom.nextInt((max - min) + 1);
    }

    public static void main(String[] arg) {
        SecureRandom random = new SecureRandom();
        System.out.println(generate(random, 0, 2 ));
    }
}

stackoverflow、baeldung、极客等来源提供了Random和SecureRandom类之间的比较。

从baeldung可以看到:

使用SecureRandom最常见的方法是生成int、long、,浮点、双精度或布尔值:int randomInt=secureRandom.nextInt();long randomLong=secureRandom.netLong();float randomFloat=secureRandom.netFloat();doublerandomDouble=secureRandom.nexDouble();boolean randomBoolean=secureRandom.nextBoolean();为了生成int值,我们可以传递一个上界作为参数:int randomInt=secureRandom.nextInt(上限);此外,我们可以为int、double和long生成一个值流:IntStream randomIntStream=secureRandom.ints();LongStream randomLongStream=secureRandom.long();DoubleStream randomDoubleStream=secureRandom.doubles();对于所有流,我们可以显式设置流大小:IntStream IntStream=secureRandom.ints(streamSize);

该类提供了几个其他选项(例如,选择基础随机数生成器),这些选项超出了本问题的范围。

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

rng.nextInt(n)无法达到整数.MAX_VALUE。当min为负值时,(max-min)可能会导致溢出。

万无一失的解决方案将为[Integer.min_VALUE,Integer.max_VALUE]内的任何min<=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%或更高。

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

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

有关Random的实现,请参阅此处的更多信息