Math.random () so với Random.nextInt (int)


135

Sự khác biệt giữa Math.random() * nRandom.nextInt(n)đâu nlà một số nguyên?


Tôi không biết toán, nhưng tôi biết rằng FindBugs phàn nàn nếu bạn sử dụngMath.random()
finnw 13/210

3
Hãy nhớ rằng Random không có phương thức tĩnh, vì vậy hãy sử dụng: (new Random ()). NextInt (n)). Để Math tạo ra một số nguyên tương tự, sử dụng: Math.floor ((Math.random () * n) +1);
Dimitri Dewaele

Câu trả lời:


169

Dưới đây là lời giải thích chi tiết về lý do tại sao " Random.nextInt(n)cả hiệu quả hơn và ít sai lệch hơn Math.random() * n" từ bài đăng trên diễn đàn Mặt trời mà Gili liên kết đến:

Math.random () sử dụng Random.nextDouble () trong nội bộ.

Random.nextDouble () sử dụng Random.next () hai lần để tạo ra một nhân đôi có các bit được phân phối đồng đều trong lớp phủ của nó, do đó, nó được phân phối đồng đều trong phạm vi 0 đến 1- (2 ^ -53).

Random.nextInt (n) sử dụng Random.next () trung bình ít hơn hai lần - nó sử dụng một lần và nếu giá trị thu được cao hơn bội số cao nhất của n dưới MAX_INT, thì nó sẽ trả về giá trị modulo n (điều này ngăn các giá trị trên bội số cao nhất của n dưới MAX_INT làm lệch phân phối), do đó trả về một giá trị được phân phối đồng đều trong phạm vi 0 đến n-1.

Trước khi chia tỷ lệ 6, đầu ra của Math.random () là một trong 2 ^ 53 giá trị có thể được rút ra từ phân phối đồng đều.

Chia tỷ lệ theo 6 không làm thay đổi số lượng giá trị có thể và chuyển sang int sau đó buộc các giá trị này vào một trong sáu 'nhóm' (0, 1, 2, 3, 4, 5), mỗi nhóm tương ứng với các phạm vi bao gồm một trong hai 1501199875790165 hoặc 1501199875790166 của các giá trị có thể (vì 6 không phải là giá trị của 2 ^ 53). Điều này có nghĩa là đối với một số lượng xúc xắc đủ (hoặc một con súc sắc có số lượng cạnh đủ lớn), con súc sắc sẽ tự cho thấy mình bị lệch về phía các thùng lớn hơn.

Bạn sẽ chờ đợi một con xúc xắc lăn rất lâu để hiệu ứng này xuất hiện.

Math.random () cũng yêu cầu xử lý gấp đôi và có thể đồng bộ hóa.


3
Random.nextInt và nextDouble cũng có thể được đồng bộ hóa.
adrianos

Trong bối cảnh này, "ít thiên vị" có nghĩa là gì, xin vui lòng?
ΦXocę 웃 Пepeúpa ツ

2
@ Xocę 웃 Пepeúpa simply Điều đó đơn giản có nghĩa là một số con số có khả năng được rút ra nhiều hơn những con số khác. Vì trong đó có xu hướng chọn một số số so với số khác (do đó không hoàn toàn ngẫu nhiên hoặc được cung cấp đồng phục cỡ mẫu đủ lớn)
ford hoàn thành

1
Lưu ý rằng nhận xét cuối cùng cho luồng đó báo cáo: "Xu hướng được mô tả là một phần trong 2 ^ 53, nhưng độ dài chu kỳ tối đa của PRNG được sử dụng chỉ là 2 ^ 48. Vì vậy, những gì bạn sẽ thấy trong ứng dụng là dữ liệu phân phối PRNG cơ bản, không phải thiên vị. " Điều này sẽ chỉ ra thực tế là hai phương pháp tương đương nhau
ảo ảnh kỹ thuật số

1
@ Xocę 웃 Пepeúpa ツ Thay thế 6bằng 5trên một khối súc sắc: nó sẽ là "5-bias". Bạn có thể ném xúc xắc một vài lần trước khi bạn nhận thấy có gì đó không ổn với xúc xắc. Bạn buộc phải thực hiện một kiểm tra kỹ lưỡng cực kỳ tinh vi trước khi bạn nhận thấy có gì đó không ổn với một trình tạo ngẫu nhiên.
Dávid Horváth

27

một điểm quan trọng khác là Random.nextInt (n) có thể lặp lại do bạn có thể tạo hai đối tượng Random với cùng một hạt giống. Điều này là không thể với Math.random ().



0

Theo ví dụ Random.nextInt(n)này có đầu ra ít dự đoán hơn thì Math.random () * n. Theo [mảng được sắp xếp nhanh hơn một mảng chưa sắp xếp] [1] Tôi nghĩ rằng chúng ta có thể nói Random.nextInt (n) là khó dự đoán .

usingRandomClass: Thời gian: 328 milesecond.

usingMathsRandom: Thời gian: 187 milesecond.

package javaFuction;
import java.util.Random;
public class RandomFuction 
{
    static int array[] = new int[9999];
    static long sum = 0;
    public static void usingMathsRandom() {
        for (int i = 0; i < 9999; i++) {
         array[i] = (int) (Math.random() * 256);
       }

        for (int i = 0; i < 9999; i++) {
            for (int j = 0; j < 9999; j++) {
                if (array[j] >= 128) {
                    sum += array[j];
                }
            }
        }
    }

    public static void usingRandomClass() {
        Random random = new Random();
        for (int i = 0; i < 9999; i++) {
            array[i] = random.nextInt(256);
        }

        for (int i = 0; i < 9999; i++) {
            for (int j = 0; j < 9999; j++) {
                if (array[j] >= 128) {
                    sum += array[j];
                }
            }

        }

    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        usingRandomClass();
        long end = System.currentTimeMillis();
        System.out.println("usingRandomClass " + (end - start));
        start = System.currentTimeMillis();
        usingMathsRandom();
        end = System.currentTimeMillis();
        System.out.println("usingMathsRandom " + (end - start));

    }

}

1
Trong vòng lặp thứ hai, bạn kiểm tra> = 50, điều này đúng trong hơn 50% các trường hợp. Điều đó sẽ gây ra điều này nếu tuyên bố là đúng trong hầu hết các lần, điều này làm cho nó dễ dự đoán hơn. Do đó, kết quả của bạn được thiên vị cho câu trả lời của bạn
Neuron

đó là lỗi đánh máy ... làm 128 trong ví dụ thứ hai bạn sẽ nhận được kết quả tương tự.
jatin Goyalty
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.