Câu hỏi Làm cách nào để tạo các số nguyên ngẫu nhiên trong một phạm vi cụ thể trong Java?


Làm cách nào để tạo ngẫu nhiên int giá trị trong một phạm vi cụ thể?

Tôi đã thử những điều sau đây, nhưng những người không làm việc:

Cố gắng 1:

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

Nỗ lực 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`.

2903
2017-12-12 18:20


gốc




Các câu trả lời:


Trong Java 1.7 trở lên, cách tiêu chuẩn để thực hiện điều này như sau:

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

Xem JavaDoc có liên quan. Cách tiếp cận này có lợi thế là không cần phải khởi tạo một cách rõ ràng java.util.Random ví dụ, có thể là một nguồn gây nhầm lẫn và lỗi nếu được sử dụng không thích hợp.

Tuy nhiên, ngược lại không có cách nào để thiết lập rõ ràng hạt giống để có thể khó tái tạo kết quả trong các tình huống hữu ích như kiểm tra hoặc lưu trạng thái trò chơi hoặc tương tự. Trong những tình huống đó, kỹ thuật tiền Java 1.7 được hiển thị bên dưới có thể được sử dụng.

Trước Java 1.7, cách tiêu chuẩn để thực hiện điều này như sau:

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

Xem JavaDoc có liên quan. Trong thực tế, java.util.Random lớp thường thích hợp hơn để java.lang.Math.random ().

Đặc biệt, không cần phải tái tạo lại bánh xe tạo số nguyên ngẫu nhiên khi có một API đơn giản trong thư viện chuẩn để thực hiện nhiệm vụ.


3260
2017-12-12 18:25



Đối với cuộc gọi trong đó max giá trị là Integer.MAX_VALUE có thể tràn, dẫn đến java.lang.IllegalArgumentException. Bạn có thể thử với: randInt(0, Integer.MAX_VALUE). Còn nếu nextInt((max-min) + 1) trả về giá trị cao nhất (khá hiếm, tôi giả định) nó sẽ không tràn lại (giả sử min và max là giá trị đủ cao)? Làm thế nào để đối phó với loại tình huống này? - Daniel
Điều này không hiệu quả trong thời gian dài - momo
@MoisheLipsker Nó phải là nextLong không có một ràng buộc như nextInteger - momo
@leventov ThreadLocalRandom đã được thêm vào Java 2 1/2 năm sau khi câu hỏi này được hỏi lần đầu tiên. Tôi đã luôn luôn được các ý kiến ​​vững chắc rằng quản lý của trường hợp ngẫu nhiên nằm ngoài phạm vi của câu hỏi. - Greg Case
Trong Android Random rand = new Random (); - Webserveis


Lưu ý rằng cách tiếp cận này thiên vị hơn và kém hiệu quả hơn nextInt tiếp cận, https://stackoverflow.com/a/738651/360211

Một mẫu chuẩn để hoàn thành điều này là:

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

Các Java Math library function Math.random () tạo ra một giá trị kép trong phạm vi [0,1). Lưu ý rằng phạm vi này không bao gồm 1.

Để nhận được một phạm vi giá trị cụ thể trước tiên, bạn cần phải nhân với độ lớn của phạm vi giá trị bạn muốn được đề cập.

Math.random() * ( Max - Min )

Điều này trả về một giá trị trong phạm vi [0,Max-Min), trong đó 'Max-Min' không được bao gồm.

Ví dụ: nếu bạn muốn [5,10), bạn cần phải bao gồm năm giá trị số nguyên để bạn sử dụng

Math.random() * 5

Điều này sẽ trả về một giá trị trong phạm vi [0,5), trong đó 5 không được bao gồm.

Bây giờ bạn cần phải chuyển phạm vi này lên đến phạm vi mà bạn đang nhắm mục tiêu. Bạn làm điều này bằng cách thêm giá trị Min.

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

Bây giờ bạn sẽ nhận được một giá trị trong phạm vi [Min,Max). Theo ví dụ của chúng tôi, điều đó có nghĩa là [5,10):

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

Nhưng, điều này vẫn không bao gồm Max và bạn đang nhận được một giá trị gấp đôi. Để có được Max bao gồm giá trị, bạn cần phải thêm 1 vào thông số phạm vi của mình (Max - Min) và sau đó cắt bớt phần thập phân bằng cách đúc thành một int. Điều này được thực hiện thông qua:

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

Và bạn có nó rồi đấy! Giá trị số nguyên ngẫu nhiên trong phạm vi [Min,Max]hoặc theo ví dụ [5,10]:

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

1324
2017-12-12 18:35



Các tài liệu Sun nói rõ ràng rằng bạn nên sử dụng Random () nếu bạn cần một int thay vì Math.random () tạo ra gấp đôi. - Lilian A. Moraru
Điều này thực sự thiên vị so với các phương thức nextInt stackoverflow.com/a/738651/360211 - weston


Sử dụng:

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

Số nguyên x bây giờ là số ngẫu nhiên có kết quả có thể 5-10.


311
2017-09-04 04:23





Sử dụng:

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

122
2017-12-12 18:25





Với  họ đã giới thiệu phương pháp ints(int randomNumberOrigin, int randomNumberBound) bên trong Random lớp học.

Ví dụ: nếu bạn muốn tạo năm số nguyên ngẫu nhiên (hoặc một số nguyên) trong phạm vi [0, 10], chỉ cần làm:

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

Tham số đầu tiên chỉ cho biết kích thước của IntStream được tạo ra (đó là phương thức quá tải của phương thức tạo ra không giới hạn IntStream).

Nếu bạn cần thực hiện nhiều cuộc gọi riêng biệt, bạn có thể tạo trình lặp lặp nguyên thủy vô hạn từ luồng:

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

Bạn cũng có thể làm điều đó cho double và long giá trị.

Hy vọng nó giúp! :)


99
2017-11-26 18:29



Tôi sẽ đề nghị bạn khởi tạo bộ ngẫu nhiên một lần. Xem Greg Case bình luận về câu trả lời của riêng mình. - Naxos84
nếu bạn có thể, bạn có thể giải thích ý nghĩa của streamSize - tham số đầu tiên của phương thức này streamSize !=0. Sự khác biệt là gì nếu streamSize 1/2 / n được đưa ra? - Erfan Ahmed Emon
Giải pháp ngọt ngào, đặc biệt là các dòng suối. - cen


Bạn có thể chỉnh sửa ví dụ mã thứ hai của mình thành:

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

90
2017-12-12 18:31





Chỉ cần một sửa đổi nhỏ của giải pháp đầu tiên của bạn là đủ.

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

Xem thêm tại đây để thực hiện Random


89
2018-03-12 22:44



Đối với tối thiểu <= value <maximum, tôi đã làm tương tự với Math: randomNum = tối thiểu + (int) (Math.random () * (tối đa tối thiểu)); nhưng việc đúc không thực sự tốt đẹp để xem;) - AxelH


ThreadLocalRandom tương đương với lớp java.util.Random cho môi trường đa luồng. Tạo một số ngẫu nhiên được thực hiện cục bộ trong mỗi chủ đề. Vì vậy, chúng tôi có hiệu suất tốt hơn bằng cách giảm xung đột.

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

x, y - khoảng thời gian, ví dụ: (1,10)


54
2018-02-12 23:19



Vì Chúa, câu trả lời này nên được chấp nhận. Xem thêm Có lý do gì để viết không new Random() kể từ Java 8? - leventov
@leventov không thể là câu trả lời được chấp nhận, việc triển khai này chỉ hỗ trợ => LOLLIPOP - Relm
Mọi người nên được phát triển cho> Lollipop trong một thời bây giờ, không làm như vậy, chỉ đơn giản là kéo thị trường. Giúp ứng dụng của bạn hỗ trợ các API mới hơn để buộc các nhà cung cấp cập nhật. - Martin Marconcini


Các Math.Random lớp trong Java là dựa trên 0. Vì vậy, nếu bạn viết một cái gì đó như thế này:

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

x sẽ ở giữa 0-9 bao gồm.

Vì vậy, được đưa ra mảng sau 25 các mục, mã để tạo ra một số ngẫu nhiên giữa 0 (cơ sở của mảng) và array.length sẽ là:

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

index = rand.nextInt( i.length );

i.length sẽ trở lại 25, các nextInt( i.length ) sẽ trả về một số giữa phạm vi 0-24. Các tùy chọn khác là đi với Math.Random hoạt động theo cách tương tự.

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

Để hiểu rõ hơn, hãy xem bài đăng trên diễn đàn Khoảng thời gian ngẫu nhiên (archive.org).


53
2018-01-08 15:04



Liên kết khoảng thời gian ngẫu nhiên đã chết. - Tapper7
@ Tapper7 Cập nhật liên kết để trỏ đến phiên bản đã lưu trữ. - Matt R
1 cho wayBackMachine lưu trữ ảnh chụp màn hình liên kết & câu trả lời của bạn vẫn là tham khảo hữu ích để có được "ngẫu nhiên" ints w / trong một phạm vi. - Tapper7
Nó ngăn cản tôi tại sao bạn nhanh chóng lập chỉ mục thành 0. - AjahnCharles
@CodeConfident The index biến sẽ không ảnh hưởng đến kết quả của số ngẫu nhiên. Bạn có thể chọn khởi tạo nó theo bất kỳ cách nào bạn muốn mà không phải lo lắng về việc thay đổi kết quả. Hi vọng điêu nay co ich. - Matt R