java - 为什么这个随机值的分布是 25/75 而不是 50/50?

标签 java random double bit-manipulation probability

编辑:所以基本上我要写的是 double 的 1 位散列。

我想以 50/50 的几率将 double 映射到 truefalse。为此,我编写了选择一些随机数的代码(仅作为示例,我想在有规律的数据上使用它并且仍然得到 50/50 的结果),检查它们的最后一位并递增 y 如果是 1,或者 n 如果是 0。

但是,此代码不断导致 25% y 和 75% n。为什么不是 50/50?为什么会有如此奇怪但直截了当 (1/3) 的分布?

public class DoubleToBoolean {
    @Test
    public void test() {

        int y = 0;
        int n = 0;
        Random r = new Random();
        for (int i = 0; i < 1000000; i++) {
            double randomValue = r.nextDouble();
            long lastBit = Double.doubleToLongBits(randomValue) & 1;
            if (lastBit == 1) {
                y++;
            } else {
                n++;
            }
        }
        System.out.println(y + " " + n);
    }
}

示例输出:

250167 749833

最佳答案

因为 nextDouble 是这样工作的:( source )

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

next(x)使x随机位。

现在为什么这很重要?因为第一部分(除法之前)生成的数字大约有一半小于 1L << 52 ,因此它们的有效位并没有完全填充它可以填充的 53 位,这意味着有效位的最低有效位始终为零。


由于受到了广泛关注,这里有一些关于 double 的额外解释。在 Java(和许多其他语言)中看起来确实如此,以及为什么它在这个问题中很重要。

基本上,double看起来像这样:(source)

double layout

在这张图片中看不到的一个非常重要的细节是数字被“标准化”1 使得 53 位小数以 1 开头(通过选择这样的指数),即然后省略 1。这就是为什么图片显示分数(有效位)为 52 位,但实际上有 53 位。

规范化意味着如果在 nextDouble 的代码中第 53 位被设置,该位是隐含的前导 1 并且它消失了,其他 52 位按字面意思复制到结果 double 的有效位.但是,如果该位未设置,则其余位必须左移,直到设置为止。

平均而言,一半的生成数字属于有效数字没有完全左移的情况(其中大约一半的最低有效位为 0),另一半为移动至少 1(或完全为零),因此它们的最低有效位始终为 0。

1:并非总是如此,显然它不能对没有最高 1 的零进行。这些数字称为非正规数或次正规数,请参阅 wikipedia:denormal number .

关于java - 为什么这个随机值的分布是 25/75 而不是 50/50?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27625611/

相关文章:

java - 使用 XSD 进行 XML 验证如何工作?

java - Java 中的字符串打乱顺序

c - 如何在 C 中生成随机长整型,其中每个数字都非零?而且随机数是重复的

java - 不同的舍入方法似乎不起作用

java - 在 Java 中,两个 double 相乘为零?

java - JDBC 事务问题。无法使其原子性

java - 在随机排序的 ArrayList 中将特定元素与其上面的元素交换

python - 在网格中生成随机 X,Y 坐标

c - 需要帮助在 C 中实现总随机字符

c - 当我没有从返回 double 的函数返回值时,为什么我会得到 1.#QNB