我发现我的程序发生了一些奇怪的事情。
该程序主要用于组件点击,因为它是测试随机性的概念。
正如您所看到的,它正确打印,因为它应该倾向于向中间点击,这是完美的。
问题是,它似乎有偏见。
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次百分比等打印出的所有结果,它很长,所以我不会发布,但我确实有信息。
答案 0 :(得分:16)
既不是Java Math.rand()
也不是伪随机生成问题。这导致了奇怪的(但预期的)行为:
Math.random() - Math.random()
两个uniformly分布式random variables的和(和减法)不会导致均匀分布的变量。据我记得,他们会产生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);
您的代码(不带乘法)生成随机变量,其中包含0
到center.x * 2
和center.x
{{1}}的可能值。到现在为止还挺好。但是分布是trangular,这意味着expected value在该范围内不相等。
两个随机变量的乘法(其中一个不再均匀分布)具有更复杂的分布,但肯定不均匀。
后一个代码片段生成一个简单,均匀分布的变量,其概率密度函数在整个空间中相等。
在你的程序中,这是一个明显的数学错误,但伪随机生成器实际上可以在空间中生成“非随机”模式。请查看该文章中的probability density图片:
答案 1 :(得分:2)
不使用Math.random()
,而是使用java.util.Random
。首先,使用当前时间为随机生成器播种:
Random randGenerator = new java.util.Random(System.currentTimeMillis());
然后随机生成一个。
randGenerator.nextDouble();
答案 2 :(得分:0)
在这种情况下播种随机播放没有太大作用,因为它已经使用System.nanoTime()来播种自身:
public Random() { this(++seedUniquifier + System.nanoTime()); }
private static volatile long seedUniquifier = 8682522807148012L;
Math.random()方法反复使用相同的Random,并使用默认构造函数来构建它。
问题是你正在对两个改变分布的随机数进行计算。