问一个比较老的问题,看了很多人的回答我还是有点疑问,想请大伙再帮忙回答一下。

Gavin-Zhang 2014-08-09 11:19:48
Java 里面有关随机种子数的问题

import java.util.*;

public class Bool {
public static void main(String[] args) {
Random rand = new Random(47);
int i = rand.nextInt(100);
int j = rand.nextInt(100);
System.out.println("i = " + i);
System.out.print("j = " + j);
}

/* Output:
i = 58
j = 55

这里为什么每次i都等于58,j都等于55
我知道47是个随机种子数,得到的也是固定的值,那为什么每次都是58和55呢?

...全文
229 3 打赏 收藏 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
Gavin-Zhang 2014-08-10
  • 打赏
  • 举报
回复
1楼回复的好详细,不过我基础还是不够,好多地方看不懂。不过还是谢谢给我这么详细的答案啊。二楼的文字我看得懂,也谢谢二楼。
zhangshuhua0509 2014-08-10
  • 打赏
  • 举报
回复
固定的种子,在产生相同范围(题中为0-100)的随机数时,总是产生一组相同的随机数,即第一个是58,第二个是55。 所谓的随机,是说这一组数是随机的,即在55后面可能出现任意100以内的数字,但第3个确实永远都是那个数字,总而言之,相同种子,出现的是一组固定的集合,但集合中每个位置的的元素是随机的,而出现顺序总是相同的,因为种子相同,它内部得出的结果必然相同 在Random构造方法中如果是没有参数的构造方法,将会用当前时间来做种子,这样才使得第一个数也是看起来随机的。
gaofuqi 2014-08-10
  • 打赏
  • 举报
回复
还是看看Random的源码吧,首先是3个常量:

 private final static long multiplier = 0x5DEECE66DL //十进制是25214903917;
 private final static long addend = 0xBL //十进制是11;
 private final static long mask = (1L << 48) - 1//十进制是281474976710655,十六进制是0xffffffffffff;
然后是构造方法和setSeed:

public Random(long seed) {
        this.seed = new AtomicLong(0L);
        setSeed(seed);
    }
	synchronized public void setSeed(long seed) {
        seed = (seed ^ multiplier) & mask;
        this.seed.set(seed);
    	haveNextNextGaussian = false;
    }
1.创建初始值为0的原子long类型的seed; 2.将传入的参数seed重新计算,(seed ^ multiplier) & mask为0x5DEECE642, 首先我们不必理会multiplier和mask为什么会0x5DEECE66DL和0xffffffffffff, multiplier和mask都是常量,可以确认的是相同的seed重新计算后的值也是一样的; 3.设置this.seed的值即刚才重新计算的seed值; 4.将haveNextNextGaussian设置为false,本来默认就是false, 暂时不用理解haveNextNextGaussian的意义,后面再看看是否有使用到。 然后再看看nextInt方法:

 public int nextInt(int n) {
        if (n <= 0)
            throw new IllegalArgumentException("n must be positive");

        if ((n & -n) == n)  // i.e., n is a power of 2
            return (int)((n * (long)next(31)) >> 31);

        int bits, val;
        do {
            bits = next(31);
            val = bits % n;
        } while (bits - val + (n-1) < 0);
        return val;
    }
	
	 protected int next(int bits) {
        long oldseed, nextseed;
        AtomicLong seed = this.seed;
        do {
	    oldseed = seed.get();
	    nextseed = (oldseed * multiplier + addend) & mask;
        } while (!seed.compareAndSet(oldseed, nextseed));
        return (int)(nextseed >>> (48 - bits));
    }
1.如果n不是正整数抛出异常; 2.(n & -n) == n 用来判断n是否为2的x次方,如果是则返回(int)((n * (long)next(31)) >> 31), 这里有两次使用了next(31),我们就看看next(31)产生了什么整数: 1).oldseed是(0x2F^0x5DEECE66D)&0xffffffffffff的值0x5DEECE642, nextseed为(oldseed*0x5DEECE66D+0xB)& 0xffffffffffff的值0xBA2442955625, 2).seed.compareAndSet(oldseed, nextseed)判断nextseed是否为预期的结果, 如果是预期结果返回0xBA2442955625 >>> (48 - 31)为0x5D12214A; 因此next(31)为0x5D12214A(十进制为1561469258) 3. val = bits % n = 0xBA24 % 100 = 58 ,不满足1561469258 - 58 + (100-1) < 0 因此返回val即58 以按照以上过程同样也可以推导出为什么第二次是55

62,620

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧