【问题标题】:Can Random.nextDouble() ever return the inclusive value?Random.nextDouble() 可以返回包含值吗?
【发布时间】:2020-02-12 12:12:57
【问题描述】:

我正在使用Random class's nextDouble() 方法,如下所示。我希望nextDouble() 在区间 [-50.0, 50.0) 上返回一个伪随机的double 值,但是,在循环运行 10 亿次之后,输出会输出到maximum: 49.99999995014588 minimum: -49.99999991024878。我在没有操作输出间隔的情况下运行了循环,得到了maximum: 0.9999999998979311 minimum: 0.0。我觉得这很奇怪,因为我对返回的0.0 所做的只是将其乘以 100.0 并从中减去 50.0。为什么下面这段代码 sn-p 永远不会准确返回 -50.0?

编辑:只是为了好玩,我又运行了 5 亿次循环,现在的输出是:maximum: 49.99999994222232 minimum: -49.999999996750944

import java.util.Random;

public class randomTest{

public static void main(String[] args) {

    double max = 0;
    double min = 0;
    Random math = new Random();
    for(int a = 0; a < 1000000000; a++) {
        double rand = math.nextDouble() * 100.0 - (100.0 / 2.0);
        max = Math.max(max, rand);
        min = Math.min(min, rand);
    }
    System.out.println("maximum: " + max + " minimum: " + min);
}
}

【问题讨论】:

    标签: java random


    【解决方案1】:

    javadoc 明确指出nextDouble() 的上限独占 不包括在内。这意味着不会返回1.0

    根据 javadoc,0.0 将被返回 .... 概率约为 254 中的 1。 (即 18,014,398,509,481,984 分之一。)

    (归结为确定对next(27) 的两次连续调用是否将返回零。如果您检查next(int) 使用的LCNG 规范,这是可能的。)


    所以,您的代码没有命中50.0,因为它不能。它应该能够点击-50.0,但您可能需要以 1.0E19 次的顺序运行它才能发生这种情况。你只运行了 5.0E8 次。

    【讨论】:

    • @Adrian 如果预期下限,那么您的操作将得到 -50.0,而不是 50.0
    • @Saravana 是的,我刚刚意识到我问为什么它没有达到 50.0 而不是问为什么它没有达到 -50.0。哎呀。
    【解决方案2】:

    nextDouble() 首先生成一个随机的long,即在数字 -263 和 263-1 之间均匀分布的整数。如果你生成十亿个数字,你仍然只生成 109/264 = 5.421 x 10-11 的可能性,很小分数。因此,生成任何特定数字的几率都非常小。

    即使考虑四舍五入,机会仍然很小。请注意,您的输出包含 16 个有效数字,这意味着您可以生成 1015 到 1016 个可能的十进制数字序列。如果只生成其中的 109,则生成任何特定数字的概率为 10-7

    【讨论】:

    • 这对我的回答没有任何影响。
    • 我不这么认为。只是想确定一下。
    【解决方案3】:

    取自 oracle 文档:

    public double nextDouble() 统一返回下一个伪随机数 从这个随机数中分布 0.0 到 1.0 之间的双精度值 生成器的序列。 nextDouble 的总合约是那个 double 值,从 0.0d 范围内(大约)均匀选择 (包括)到1.0d(不包括,是伪随机生成的,并且 返回。

    方法 nextDouble 由 Random 类实现,好像是:

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

    在前面的描述中使用对冲“大约”只是因为下一个方法只是

    大约是独立选择位的无偏源。如果它 是随机选择的比特的完美来源,那么算法 显示的将从规定的范围中选择双精度值 均匀性。

    [在Java的早期版本中,结果被错误地计算为:

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

    这似乎是等效的,如果不是更好的话,但实际上它引入了很大的不均匀性,因为

    浮点数四舍五入的偏差:它是 3 倍 有效数的低位可能是 0,而不是 那将是1!这种不均匀性可能并不重要 实践,但我们力求完美。]

    所以很明显生成数字时不包括最大值,

    【讨论】:

    • 参考文档的解释很好,但我不是问为什么不返回上限。
    • @Adrian,我想你想知道为什么它没有精确到 50 对吗?
    • 废话。我只是注意到我忘记了 50.0 前面的负数。您的回答对于我之前编辑之前提出的问题是正确的。
    【解决方案4】:

    自己实现。对我有用的东西:

    public double nextDoubleInclusive()
    {
        return myRandom.nextInt(Integer.MAX_VALUE) / (Integer.MAX_VALUE - 1.0);
    }
    

    【讨论】:

      【解决方案5】:

      请注意,在没有偏移的情况下运行时您可能没有得到 0.0。 您的“分钟”以 0.0 开头。

      对您的代码稍作更改(min = 1),您可以看到您没有获得 0.0(您可以,但可能性不大)。

          double max = 0;
          double min = 1;
          Random math = new Random();
          for(int a = 0; a < 1000000000; a++) {
              double rand = math.nextDouble();
              max = Math.max(max, rand);
              min = Math.min(min, rand);
          }
          System.out.println("maximum: " + max + " minimum: " + min);
      

      最大值:0.9999999989149039 最小值:4.5566594941703897E-10

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多