【问题标题】:How many double numbers are there between 0.0 and 1.0?0.0 和 1.0 之间有多少个双数?
【发布时间】:2011-02-28 01:35:51
【问题描述】:

这是我多年来一直在想的事情,但我从来没有花时间问过。

许多(伪)随机数生成器生成一个介于 0.0 和 1.0 之间的随机数。从数学上讲,这个范围内有无限个数,但double 是一个浮点数,因此具有有限的精度。

所以问题是:

  1. 0.0 到 1.0 之间到底有多少个 double 数字?
  2. 1 和 2 之间的数字是否一样多?在 100 和 101 之间?在 10^100 和 10^100+1 之间?

注意:如果它有所作为,我对 Java 对 double 的定义特别感兴趣。

【问题讨论】:

    标签: random floating-point double precision


    【解决方案1】:

    Java doubles 是 IEEE-754 格式,因此它们有 52 位小数;在任意两个相邻的 2 次方之间(包括一个但不包括下一个),因此将有 2 到 52 次方不同 doubles(即其中 4503599627370496 个)。例如,这就是包含 0.5 和排除 1.0 之间的不同 doubles 的数量,并且恰好也有很多介于 1.0 包括和 2.0 排除之间,等等。

    在 0.0 和 1.0 之间计算doubles 比在 2 的幂之间计算更难,因为在该范围内包含许多 2 的幂,而且还涉及到非规范化数字的棘手问题。指数的 11 位中有 10 位涵盖了所讨论的范围,因此,包括非规格化数字(我认为有几种 NaN),您将有 1024 倍于 doubles,因为介于 2 的幂之间——无论如何,总共不超过2**62。排除非规范化 &c,我相信计数将是 1023 次 2**52

    对于像“100 到 100.1”这样的任意范围,它甚至更难,因为上限不能精确地表示为 double(不是任何 2 的幂的精确倍数)。作为一个方便的近似值,由于 2 的幂之间的级数是线性的,您可以说所述范围是 2 的周围幂(64 和 128)之间的跨度的0.1 / 64th,所以你会期望大约

    (0.1 / 64) * 2**52
    

    不同的doubles -- 与7036874417766.4004... 给予或接受一两个;-)。

    【讨论】:

    • @Alex:请注意,当我写 100 到 100.1 时,我写错了。我的意思是 100 到 101。基本上,任意 N 在 N 和 N+1 之间。
    • @Alex:所以让我直截了当地说:可能的双精度值不能超过 2**64(因为它是 64 位类型),显然这些值中有很大一部分位于 @ 987654337@?
    • @polygene,是的,是的——具体来说,大约四分之一的可能值(对于任何基数和指数与分数长度的任何“正常”浮点表示)介于 0.0 和 1.0 之间(另一个四分之一在 1.0 和无穷大之间,剩下的一半在实轴的负半边)。本质上,指数的一半值(具有正常偏差,在其范围内的一半)表示底的负幂,因此数字
    • @polygenelubricants:对于许多应用程序,0 和 1 之间的范围比 100 和 101 之间的范围更重要和有趣,这就是为什么它获得更大份额的值。例如,在物理学中,您经常需要处理非常小的值,例如牛顿的引力常数 6.67e-11。具有良好的精度比 100 到 101 之间更有用。阅读floating-point-gui.de 了解更多信息。
    • 您还可以将任何数字缩放到 0.0 和 1.0 之间,单独跟踪比例,从而减少计算错误。当整个数轴可以在两个数字之间映射时,这很好!
    【解决方案2】:

    表示介于0x00000000000000000x3ff0000000000000 之间的每个double 值都位于区间[0.0, 1.0] 中。那是 (2^62 - 2^52) 不同的值(加或减一对取决于您是否计算端点)。

    区间[1.0, 2.0]对应0x3ff00000000000000x400000000000000之间的表示;这是 2^52 个不同的值。

    区间[100.0, 101.0]对应0x40590000000000000x4059400000000000之间的表示;这是 2^46 个不同的值。

    在 10^100 和 10^100 + 1 之间没有双打。这些数字中的任何一个都不能用双精度表示,并且它们之间没有双精度数。最接近的两个双精度数是:

    99999999999999982163600188718701095...
    

    10000000000000000159028911097599180...
    

    【讨论】:

    • +1,以获得得到充分支持的准确答案。 (如果您对端点计数很挑剔,请记住 +0.0 和 -0.0 具有不同的表示形式。)
    • +1,这样一个扭曲的结局!感觉就像我在读 M. Night Shyamalan 的剧本!
    【解决方案3】:

    其他人已经解释过 [0.0, 1.0] 范围内大约有 2^62 个双精度数。
    (不足为奇:几乎有 2^64 个不同的有限双精度数;其中一半是正数,大约一半 那些

    但是您提到了随机数生成器:请注意,生成介于 0.0 和 1.0 之间的数字的随机数生成器通常无法生成所有这些数字;通常它只会产生 n/2^53 形式的数字,其中 n 为整数(参见例如nextDouble 的 Java 文档)。因此,random() 输出通常只有大约 2^53(+/-1,取决于包含哪些端点)可能的值。这意味着 [0.0, 1.0] 中的大多数双精度数将永远不会生成。

    【讨论】:

      【解决方案4】:

      IBM 的文章 Java's new math, Part 2: Floating-point numbers 提供了以下代码 sn-p 来解决这个问题(在浮点数中,但我怀疑它也适用于双精度数):

      public class FloatCounter {
      
          public static void main(String[] args) {
              float x = 1.0F;
              int numFloats = 0;
              while (x <= 2.0) {
                  numFloats++;
                  System.out.println(x);
                  x = Math.nextUp(x);
              }
              System.out.println(numFloats);
          }
      }
      

      他们对此有这样的评论:

      事实证明,在 1.0 和 2.0(含)之间恰好有 8,388,609 个浮点数;大,但几乎没有这个范围内存在的无数个实数。连续的数字相距约 0.0000001。该距离称为 ULP,表示精度最低的单位或最后的单位。

      【讨论】:

      • 是的,但那是 floatnot double -- floats 有 23 位的分数,所以 2**23 -&gt; 8388608 相邻之间的值不同2 的幂(“包容性”部分当然意味着你必须再数一个,下一个是 2 的幂)。 doubles 有 52 位小数!
      • @Alex:我想我必须让程序(修改为双打)运行到宇宙的尽头左右才能得到结果...... :(
      • 我觉得自己很笨;我刚刚写了double 等价物并想“嘿,我会在大约 5 分钟内回答我自己的问题……”
      • @polygene:这感觉就像一个欧拉计划问题,显而易见的方法是不可行的计算,但必须有一些非常简单的公式来解决任意情况......
      • 也许不是真正的超级计算机:在一台机器上运行内循环只需一纳秒,在相邻的两个幂之间计算 double 大约需要 52 天(println 的当然,无论如何,非常不太可能跑得那么快,所以让我们假设一个语句消失了;-)。我认为在功能强大但现实的机器上花一年或更短的时间是可行的;-)。
      【解决方案5】:
      1. 2^53 - 64 位浮点数的有效位/尾数的大小,包括隐藏位。
      2. 大约是的,因为有效数字是固定的,但指数会发生变化。

      请参阅wikipedia article 了解更多信息。

      【讨论】:

      • 您对 2 的回答与我对 FP 工作原理的理解相矛盾。
      • 我认为1 是错误的,因为隐藏位始终为一——因此,2^52not 2^53 distinct 值(在两个相邻的幂之间,包含一个,排除下一个 - not 介于 0.0 和 1.0 之间!)。
      【解决方案6】:

      Java double 是一个 IEEE 754 binary64 数字。

      这意味着我们需要考虑:

      1. 尾数是 52 位
      2. 指数是 11 位数字,偏差为 1023(即添加了 1023)
      3. 如果指数全为 0 且尾数不为零,则称该数字未归一化

      这基本上意味着总共有 2^62-2^52+1 个可能的双重表示,根据标准在 0 和 1 之间。请注意,2^52+1 是为了删除非标准化数字。

      请记住,如果尾数为正但指数为负数为正但小于 1 :-)

      对于其他数字,这有点困难,因为边缘整数可能无法在 IEEE 754 表示中以精确的方式表示,并且因为指数中使用了其他位来表示数字,所以越大数字越低,不同的值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-15
        • 2018-04-03
        • 1970-01-01
        • 1970-01-01
        • 2012-05-19
        • 2022-07-08
        • 2016-12-12
        相关资源
        最近更新 更多