java - Math#random 不是那么随机吗?

标签 java math random

我发现我的程序发生了一些奇怪的事情。

这个程序主要用于组件点击,因为它是一个测试随机性的概念。

enter image description here

如您所见,它打印正确,因为它应该倾向于向中间点击,这非常完美。

问题是,它似乎有偏见。

import java.applet.Applet;
import java.awt.Point;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.awt.*;

public class Testing extends Applet {

/**
 * 
 */
private static final long serialVersionUID = -2441995094105327849L;

public void init() {
    setSize(WIDTH, HEIGHT);
    img = createImage(WIDTH, HEIGHT);
    g = img.getGraphics();
    paint(g);
    setVisible(true);
    g.setColor(new Color(0, 0, 0));
    g.fillRect(0, 0, WIDTH, HEIGHT);
    g.setColor(new Color(55, 55, 55, 55));
    main();
}

public final static int WIDTH = 400, HEIGHT = 400;
public static int[] widths = new int[WIDTH], heights = new int[HEIGHT];
public static ArrayList<String> set = new ArrayList<String>();
public Image img;
public Graphics g;

public void paint(Graphics g) {
    g.drawImage(img, 0, 0, null);
}

public void update(Graphics g) {
    paint(g);
}

public void main() {
    int count101 = 0;
    int count100 = 0;
    int count99 = 0;
    try {
        PrintWriter pw = new PrintWriter(new FileWriter(
                new File("Data.dat")));
        Point center = new Point(WIDTH / 2, HEIGHT / 2);

        int runs = 10000000;

        for (int i = 0; i < runs; i++) {
            int x = center.x
                    - (int) ((Math.random() - Math.random())
                            * Math.random() * center.x);
            int y = center.y
                    - (int) ((Math.random() - Math.random())
                            * Math.random() * center.y);
            widths[x]++;
            heights[y]++;
            repaint();
            g.fillRect(x, y, 1, 1);
            if((x & y) == 101){
                count101++;
            }
            if((x & y) == 100){
                count100++;
            }
            if((x & y) == 99){
                count99++;
            }
        }
        System.out.println(count101);
        System.out.println(count100);
        System.out.println(count99);
        repaint();
        pw.flush();
        pw.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
}

这会不断打印出有偏见的结果。

打印如下:

3640
10918
3741

这是相当有偏差的,因为它在大多数情况下都遵循趋势,随着所有其他值线性增加,但一旦达到 100 标记,它就会决定投下炸弹并多捡 6%然后每隔一个。

有谁知道这样做的原因吗?

哦,顺便说一句,我确实有一个 txt 文件,其中包含每个重复打印 10,000,000 次的结果以及百分比等,它很长所以我不会发布,但我确实有信息。

最佳答案

既不是Java Math.rand() 问题,也不是伪随机生成问题。这导致了奇怪的(但预期的)行为:

Math.random() - Math.random()

两个 uniformly 的总和(和减法)分布式random variables不会导致均匀分布的变量。据我记得,它们的结果是 triangular distribution :

triangular distribution

参见:Distribution of mean of two standard uniform variables .

这就是您所看到的 - 具有三角分布的二维随机变量的完美例证。此外,如果你继续添加均匀分布的随机变量,你最终会得到 normal distribution .

要实现均匀分布,你所要做的就是替换掉笨拙的东西:

int x = center.x
                - (int) ((Math.random() - Math.random())
                        * Math.random() * center.x);

简单的:

int x = (int) (Math.random() * center.x * 2);

您的代码(没有乘法)生成随机变量,其可能值从 0center.x * 2 并带有 expected valuecenter.x。到目前为止,一切都很好。但是分布是三角形的,这意味着 probability density在该范围内不相等。

两个随机变量的乘积(其中一个不再均匀分布)具有更复杂的分布,但肯定不均匀。

后面的代码片段生成了一个简单的、均匀分布的变量,其概率密度函数在整个空间内都相等。

旁注

在您的程序中,这是一个明显的数学错误,但伪随机生成器实际上可以在空间中生成“非随机”模式。看看Strange Attractors and TCP/IP Sequence Number Analysis , 图片来自那篇文章:

3d-space
(来源:coredump.cx)

关于java - Math#random 不是那么随机吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9726991/

相关文章:

java - 如何在 10 位数字的第三位和下一个第三位和下一个第四位显示带点的数字?

java - 使用 Nashorn 从脚本运行 Java

java - 如何在 Eclipse 中运行带有 Bower 的 Maven Web 应用程序?

java - 在java中生成一定范围内的随机整数以满足百分位数

javascript - Angular - 错误 : 10 $digest() iterations reached. 中止

java - listview回收早了吗?还是 Universal ImageLoader 错误地取消了?还是我的逻辑错了?

algorithm - MATLAB 函数可以将数学函数作为输入吗?

java - 使用 delta 计算耗时

c# - 如何得到多次执行伯努利实验的详细结果(概率树)

php - MySql Select 数据在 PHP 中是多对多关系