Java的随机函数可以为零吗?

Thi*_*ree 16 java random

出于好奇,Math.random()可以为零吗?

例如,如果我有:

while (true){
  if (Math.random() == 0)
    return 1;
}
Run Code Online (Sandbox Code Playgroud)

我真的会得到一个回报吗?还需要考虑舍入误差,因为Math.random()返回一个double.

我问,因为我的CS教授说random()从0到1包括在内,我一直认为它是独占的.

Ang*_*ngs 38

是的,它确实可以.Math.random()创建一个java.util.Random带有种子的全局生成器(System.currentTimeMillis() ^ 0x5DEECE66DL) & ((1L << 48) - 1)并调用nextDouble()它.如果它的种子到达状态107048004364969L(并且它将java.util.Random具有完整的时间段),则下一个double生成的将是0.0.虽然运气不好,但你可能最终会在周期中出现错误的平价,因为这 Random.nextDouble()会使状态两次提升.如果运气稍差,你可能不得不在循环结束之前生成2 ^ 47个随机数,因为我没有找到任何其他种子0.0.

种子前进,好像是,seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); 并且使用两个连续种子值的26和27个高位生成双精度.在示例中,两个下一个种子值将为0L11L.

如果您设法创建全局生成器System.currentTimeMillis()==107038380838084L,则代码会立即返回.你可以用以下方法模拟:

java.util.Random k = new java.util.Random(107038380838084L); System.out.println(k.nextDouble()==0);

  • 并且,如果你认为在下一次尝试中看起来太可疑而不能达到零,那么使用`new java.util.Random(164311266871034L)`,你将在两次尝试中击中它.或者`new java.util.Random(240144965573432L)`和三次尝试.或者`new java.util.Random(881498)`,在376050调用`nextDouble`之后你会得到一个零. (8认同)

Mat*_*nit 21

根据文档,"返回带有正号的双精度值,大于或等于0.0且小于1.0." 这意味着它可以为零.

正如Hank所写,它在上边界独占的(永远不会是1),所以也许这就是你的困惑来自:-).


Joe*_*oey 10

它完全有可能永远不会返回零.Java包含的PRNG是一个48位的LCG,从中只使用了32位.对于double尾数的所有53位为零,您基本上需要至少一次调用next()高32位为零的位置和另一位大多数位于零的位置.(如果我没弄错的话,我会说发生器的工作方式不会发生这种情况,但现在已经很晚了,我已经累了,我也不会打赌它.)

由于方法文档明确说明了如何获得随机数,因此Java运行库的其他实现几乎没有余地产生不同的结果.该合约可能会说,你得到的数字是[0,1).但实际上有很多值你永远不会命中(因为你需要来自生成器的两个连续值,它们可以在连续值之间产生线性相关性 - 只有48位状态.你不能生成所有不同的值53位组合 - 至少不是它的完成方式.)

当然,由于Math.random()自动播种静态Random实例,我们可能还必须考虑这里的种子,这可能需要非常具体才能使测试用例得以解决.这可能意味着确切的时间点可能是几十年或几千年.


Han*_*Gay 9

它包含零,不包括零,例如,[0, 1)0 <= x < 1取决于您喜欢的符号.


Ira*_*ter 5

从理论上讲,它可以返回零值.

在实践中,您可能需要等待很长时间才能完全为零.如果随机数发生器实现良好,它至少有56位内部状态(否则返回结果的所有位都不是随机的).这意味着,如果随机生成的值的分布是平坦的,那么在2 ^ 56中最多只有一次机会获得所有位为零的值.这大约是10 ^ -19.我不会屏住呼吸.

(其他人正确地观察到,如同记载的那样,理论上[并且可能在实践中]它不能返回值1.0).