更好的整数随机数生成器

时间:2015-05-12 18:53:39

标签: java random

目前,我正在使用随机数生成JPanel中的组件位置。我发现使用Random.nextInt(6000);返回的数字太多,小于100,太多,我的意思是它们中的大多数都小于100.所以我调查了一下,发现了一个更高质量的随机数生成器使用Long所以我冒昧地将其格式化(参见下面的实现)。之后我在1000-2000范围内获得了太多数字。

使用计数器变量测试后,当我生成2000个数字时,其中大约1350个数字在该范围内。

我需要一个更随机的数字生成器,甚至是 真正随机 的数字生成器(我不希望得到它) ,但如果我能得到的话会很好。

随机类:

public class HighQualityRandom extends Random {
private static final long serialVersionUID = 1L;

private Lock l = new ReentrantLock();
  private long u;
  private long v = 4101842887655102017L;
  private long w = 1;

  public HighQualityRandom() {
    this(System.nanoTime());
  }
  public HighQualityRandom(long seed) {
    l.lock();
    u = seed ^ v;
    nextLong();
    v = u;
    nextLong();
    w = v;
    nextLong();
    l.unlock();
  }

  public long nextLong() {
    l.lock();
    try {
      u = u * 2862933555777941757L + 7046029254386353087L;
      v ^= v >>> 17;
      v ^= v << 31;
      v ^= v >>> 8;
      w = 4294957665L * (w & 0xffffffff) + (w >>> 32);
      long x = u ^ (u << 21);
      x ^= x >>> 35;
      x ^= x << 4;
      long ret = (x + v) ^ w;
      return ret;
    } finally {
      l.unlock();
    }
  }

  public int next(int bits) {
    return (int) (nextLong() >>> (64-bits));
  }

}

实施:

    public int getRandomX(){
    HighQualityRandom ran = new HighQualityRandom();
    int rand = (int) ran.nextLong();
    String p = rand + "";
    if(rand < 0){
        rand = rand * -1;
    }
    p = rand + "";
    p = p.substring(0, 4);
    rand = Integer.parseInt(p);
    while(rand > 6144){
        rand = (int) ran.nextLong();
        p = rand + "";
        if(rand < 0){
            rand = rand * -1;
        }
        p = rand + "";
        p = p.substring(0,4);
        rand = Integer.parseInt(p);
    }
    System.out.print("X is: " + rand + " Y is: ");
    return rand;
}
public int getRandomY(){
    HighQualityRandom ran = new HighQualityRandom();
    int rand = (int) ran.nextLong();
    String p = rand + "";
    if(rand < 0){
        rand = rand * -1;
    }
    p = rand + "";
    p = p.substring(0, 4);
    rand = Integer.parseInt(p);
    while(rand > 4608){
        rand = (int) ran.nextLong();
        p = rand + "";
        if(rand < 0){
            rand = rand * -1;
        }
        p = rand + "";
        p = p.substring(0,4);

        rand = Integer.parseInt(p);
    }
    System.out.println(rand);
    return rand;
}

作为我正在对long做什么来解释我的4位数字的原因:

  1. 如果是负数,则乘以负数。
  2. 使它成为一个字符串。
  3. 子串前4位数字
  4. 如果它太大了:再做一次。
  5. 作为旁注,seed类中的Random参数应该是什么?我试过谷歌搜索,人们在谈论加密东西......

    编辑:

    使用java.util.random()实现:

        public int getRandomX(){
        Random ran = new Random();
        int rand = ran.nextInt(6144);
    
        if(rand <= 100){
            Game.between++;
        }
    
        return rand;
    }
    public int getRandomY(){
        Random ran = new Random();
        int rand = ran.nextInt(4608);
    
        if(rand <= 100){
            Game.between++;
        }
        System.out.println(Game.between);
    
        return rand;
    }
    

    平均而言,其中约37-40人不到100人(千分之一)。所以我错了,绝对不是50%的人在盒子外面或外面。但是:在28311552可能的解决方案(地图是6144x4608)中可供选择,似乎太多而不能被卡在<100。

2 个答案:

答案 0 :(得分:5)

我不知道你在做什么,但这是一个小例子程序:

Random r = new Random();
int count = 0;
for (int i = 0; i < 1000_000; i++)
    if (r.nextInt(6000) < 100)
        count++;
System.out.println(count);

拨打Random.nextInt(6000)一百万次。结果是:

16655

在理想情况下,它将是:100/5999 * 1000000 = 16669。我认为这非常接近。

你做错了什么。请发给您原始代码,证明Random.nextInt(6000)在超过50%的案例中提供的内容少于100个。

为了在游戏中生成随机数,java.util.Random完全没问题。还有java.security.SecureRandom,但你不需要那个游戏,而且速度要慢得多。

修改

要编辑:您始终在创建新的Random实例!不要那样做。如果您始终创建新的Random实例并且未指定种子值,则将根据计算机的当前时间对其进行播种。这本身就会降低发电机的“随机性”。

在我的示例中执行操作:创建一个Random实例,可选择将其播种到您想要的任何位置,并始终使用它!

编辑#2:

种子:它类似于随机数生成器的“状态”。引用Random类javadoc:

  

如果使用相同的种子创建了两个Random实例,并且为每个实例创建了相同的方法调用序列,则它们将生成并返回相同的数字序列。

实际上,如果要重现相同的序列,则只需设置种子。例如,您保存游戏/重播,并且您希望重新设置游戏。在这种情况下,您将保存起始种子以及游戏/重放,并且当再次玩游戏时,您将设置保存的种子,因此您将获得相同的随机序列。

答案 1 :(得分:0)

你的数字剥离事件正在引发你的问题。 XOR移位发生器工作正常,但其范围是64位 - 2的幂,而不是10的幂,所以没有理由认为其输出的十进制数字是随机的。所以取随机值并使用mod(10000)而不是挑出十进制数字。

99%的程序员不太了解数学,无法改进RNG或加密密码。不幸的是,大约10%的程序员认为他们只有1%的人可以。道德:不要乱用RNG,只是按照预期使用它并仔细阅读文档。