math.random 在 Java 中的分布是怎样的?

What is the distribution of math.random in Java?

我想在 Java 程序中使用 math.random()。

这种获得双打的方式分布情况如何?

这记录在 Java SE API docs:

public static double random()

Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0. Returned values are chosen pseudorandomly with (approximately) uniform distribution from that range.

文档继续提到它在幕后使用 java.util.Random,大概是 nextDouble()(尽管没有明确说明)。

关于nextDouble中不均匀性的说明如下:

The method nextDouble is implemented by class Random as if by:

 public double nextDouble() {
   return (((long)next(26) << 27) + next(27))
     / (double)(1L << 53);
 }

The hedge "approximately" is used in the foregoing description only because the next method is only approximately an unbiased source of independently chosen bits. If it were a perfect source of randomly chosen bits, then the algorithm shown would choose double values from the stated range with perfect uniformity.

看来 non-uniformity 只是由于 next 的潜在不均匀性,而不是 nextDouble 算法本身的重大偏差:

[In early versions of Java, the result was incorrectly calculated as:

  return (((long)next(27) << 27) + next(27))
     / (double)(1L << 54);

This might seem to be equivalent, if not better, but in fact it introduced a large nonuniformity because of the bias in the rounding of floating-point numbers: it was three times as likely that the low-order bit of the significand would be 0 than that it would be 1! This nonuniformity probably doesn't matter much in practice, but we strive for perfection.]

注意,这里是从区间[0,1]统一绘制的,分成2-53等步长,也就是不是等同于从0到1之间的所有double值的集合中统一抽取。这是一个细微的区别:所有double值的集合如图所示,0 和 1 本身在数轴上的间隔不均匀:

图片转自docs.oracle.com