【问题标题】:For a positive integer n, is Math.random()*n >= n possible?对于正整数 n,Math.random()*n >= n 可能吗?
【发布时间】:2019-07-12 12:00:39
【问题描述】:

根据Why are floating point numbers inaccurate?,浮点数有错误。

我的问题是,对于一个正整数 n,Math.random()*n 是否有可能出现错误,导致其结果等于或大于 n?

【问题讨论】:

  • 浮点没有常用的“错误”,只是数学意义上的“错误”,或不准确的程度。这样,小于 1 的数乘以正整数不能得到大于或等于 n 的数。

标签: javascript floating-point


【解决方案1】:

Math.random() * n 不会产生大于或等于n 的数字,因为Math.random() 返回一个浮点数x,其中0 <= x < 1Math.random() 函数的文档是 here

【讨论】:

  • 这是不正确的。 Math.random() 不会返回 1,但相乘的结果可能会向上舍入到 n
  • @Sneftel:没错,在my answer有证明。
【解决方案2】:

我只是想添加一些可能有用的信息,实际上如果n 设置为Number.POSITIVE_INFINITY,则条件变为true

let posInf = Number.POSITIVE_INFINITY;
console.log(Math.random(), posInf);
console.log(Math.random() * posInf >= posInf);

【讨论】:

    【解决方案3】:

    答案是肯定的,但仅限于非常极端的情况。

    有可能

    Math.random()*n >= n
    

    在 n 非常大的情况下返回 true。

    请注意,在这些情况下,结果将等于所选数字 n。

    来自Math.random()documentation

    请注意,由于 JavaScript 中的数字是具有四舍五入行为的 IEEE 754 浮点数,因此以下函数声明的范围(不包括 Math.random() 本身的范围)并不准确。如果选择了极大的界限(253 或更高),则在极少数情况下可以计算通常被排除的上限。

    function getRandomArbitrary(min, max) {
      return Math.random() * (max - min) + min;
    }
    

    虽然在技术上是可能的,但这种情况非常罕见,可以忽略不计

    【讨论】:

    • 您引用的文档考虑了Math.random() * (max-min) + min,这与Math.random() * max 不同。对于这个问题中询问的情况,根据my answer中的证明是不可能的。
    • 该文档似乎具有误导性:大范围并不是这里唯一的问题。如果你选择min = 1.0max = 1.0 + 2**-52,你会期望Math.random() * (max - min) + minmax 大约一半的时间。
    【解决方案4】:

    如果n大于浮点格式的最小正正规数,则Math.Random()*nn。

    (正如abacabadabacaba 在评论中指出的那样,如果 n 是最小正常值,例如 2-1022 用于 IEEE-754 基本 64 位二进制,并且Math.Random 返回它的最大值 1 − 2−53,然后乘积舍入到最小正态,所以 Math.Random()*n = n。)

    证明如下。

    预赛

    • 在这个答案中,用code format 编写的表达式指的是计算值。代码格式之外的表达式指的是精确的数学。对于任何数字 nn 是将 n 舍入为浮点格式的结果。 ab 是浮点舍入前ab 的精确数学乘积,a*b 是舍入后的浮点结果。
    • 使用了 IEEE-754 二进制浮点,具有舍入到最近的偶数。需要熟悉 IEEE-754。
    • ULP 代表最低精度单位。它是特定数字的浮点表示的有效位的最低有效位的值。
    • p 是浮点表示的有效位数中的位数。对于 IEEE-754 基本 64 位二进制浮点,p 为 53,但此证明适用于其他宽度。
    • 如果 h 是正常浮点表示中有效数的高位表示的值(由于按指数缩放),h•21-p是低位表示的值,是表示数字的ULP,h•2-p 是 ½ ULP,是通过将此指数范围内的任何数字四舍五入为浮点格式所产生的最大变化。
    • n 在正常范围内”,我的意思是n 是正常的。这意味着 2m•(1−2p) ≤ n M+1•(1−2p),其中mM 是浮点格式的最小和最大指数(IEEE-754 64 位二进制浮点为 -1022 和 1023)。

    引理 0:舍入是弱单调的

    给定 a b,考虑将它们舍入为浮点格式的结果,ab(使用最近舍入-tie-to-even 规则)。

    假设b a。

    如果aa,那么ba≤ab。这是不可能的,因为b 距离ba 更远,所以b 必须四舍五入到a 或更接近的数字,而不是b .反之,如果 a a,则 ab a 或 b a a .在前一种情况下,a 无法四舍五入到 a,因为 b 更接近。在后一种情况下,如果ab,则 b 不能舍入到b,因为a 更接近,并且如果 b em> a,那么 a 不能四舍五入到 a,因为 b 更接近。

    所以不可能是b a;一定是ab

    引理 1:浮点乘法是弱单调的

    乘以一个正数y是弱单调的,因为,如果 x0x1,然后是 x0•y x1•y, 引理 0 告诉我们 x0*yx1*y

    证明

    g 成为Math.Random() 的最大可能结果。由于 JavaScript 的 Math.Random() 返回 [0, 1) 中的数字,所以 g 为 1−2p

    根据引理 1,如果 g*n n,则 Math.random() 的任何结果 xg 满足 x*n n.

    我们将证明g*n n 然后证明这意味着g*n n。

    考虑g*n。如果n正好是浮点格式的最小正常数的2的幂,那么gn在浮点格式中完全可以表示,并且没有四舍五入,所以@987654375 @ = (1−2p)•n n。如果n不是2的幂,那么gn是(1−2p)•n = nn•2-p。后者比nn 的½ ULP 以上,因此,当它舍入为浮点格式时,它会向下舍入,产生小于n 的结果。 (请注意,对于 any 数字 n 而言,情况并非如此,因为 g*n 可能处于亚正常范围内,其中 ULP 可能大于 n•21−p。但是,我们假设 n 在正常范围内,这对于直到n 溢出的所有正整数都是如此.)

    因此g*n n。最后,我们考虑当 n 被舍入为浮点格式时,结果n 大于 n 的可能性,这可能导致@987654393 @>n。但是,g*n n 要求 g*n 至少比 n 小 1 ULP,但是将 n 舍入到 n 最多可以将值增加 ½ ULP。所以g*nn.

    【讨论】:

    • 这个证明有一个错误:如果 n = 2^m,那么gn 是非正规的(即使n 不是),事实上g*n = n.
    • @abacabadabacaba:谢谢,我注意到了例外情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-15
    相关资源
    最近更新 更多