如何在特定范围内生成随机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`.

当前回答

在java-8中,他们在Random类中引入了方法int(int randomNumberOrigin,int randomNumber Bound)。

例如,如果要生成[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();
    }
}

您也可以对双值和长值执行此操作。

其他回答

我将简单地说明问题提供的解决方案有什么问题,以及错误的原因。

解决方案1:

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

问题:randomNum分配的值大于最大值。

解释:假设我们的最小值是5,而你的最大值是10。Math.random()中任何大于0.6的值都将使表达式的计算结果为6或更大,加上5将使其大于10(最大值)。问题是你将随机数乘以最大值(这会产生一个几乎和最大值一样大的数字),然后再加上最小值。除非最小值是1,否则它是不正确的。如其他答案所述,您必须切换到

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

+1是因为Math.random()永远不会返回1.0。

解决方案2:

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

这里的问题是,如果第一项小于0,“%”可能会返回负数。由于rn.nextInt()以约50%的概率返回负值,因此也不会得到预期的结果。

然而,这几乎是完美的。您只需进一步查看Javadoc,nextInt(int n)。使用该方法

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

也将返回所需的结果。

在java-8中,他们在Random类中引入了方法int(int randomNumberOrigin,int randomNumber Bound)。

例如,如果要生成[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();
    }
}

您也可以对双值和长值执行此操作。

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

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

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

以前的大多数建议都不考虑“溢出”。例如:min=整数.min_VALUE,max=100。到目前为止,我采用的正确方法之一是:

final long mod = max- min + 1L;
final int next = (int) (Math.abs(rand.nextLong() % mod) + min);

这将生成范围(最小值-最大值)不重复的随机数列表。

generateRandomListNoDuplicate(1000, 8000, 500);

添加此方法。

private void generateRandomListNoDuplicate(int min, int max, int totalNoRequired) {
    Random rng = new Random();
    Set<Integer> generatedList = new LinkedHashSet<>();
    while (generatedList.size() < totalNoRequired) {
        Integer radnomInt = rng.nextInt(max - min + 1) + min;
        generatedList.add(radnomInt);
    }
}

希望这对你有所帮助。