代码之家  ›  专栏  ›  技术社区  ›  polygenelubricants

在0.0和1.0之间有多少个双数?

  •  89
  • polygenelubricants  · 技术社区  · 14 年前

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

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

    所以问题是:

    1. 究竟有多少 双重的 数字在0.0和1.0之间?
    2. 在1和2之间有同样多的数字吗?100到101?在10^100和10^100+1之间?

    注意:如果它有所不同,我对Java的定义感兴趣。 双重的 特别地。

    6 回复  |  直到 14 年前
        1
  •  64
  •   Alex Martelli    14 年前

    爪哇 double S在 IEEE-754 格式,因此它们有52位的分数;在两个相邻的两个幂之间(包括一个,不包括下一个),因此第52个幂将有2个不同 双重的 S(即其中4503599627370496)。例如,这是 双重的 S介于0.5和1.0之间,确切地说,许多也位于1.0和2.0之间,等等。

    计数 doubles 在0.0和1.0之间要比在两个幂之间做起来困难,因为在这个范围内包含了两个幂的许多幂,而且,还有一个涉及到非正规化数字的棘手问题。11位指数中的10位涵盖了所讨论的范围,因此,包括非规范化的数字(我认为有几种 NaN )你有1024倍的 双重的 在两种力量之间——不超过 2**62 总之。不包括非规范化的&C,我相信计数是1023次 2**52 .

    对于“100到100.1”这样的任意范围,更难实现,因为上限不能精确表示为 双重的 (不是任何二次方的精确倍数)。作为一个方便的近似,由于二次幂之间的级数是线性的,所以可以说该范围是 0.1 / 64 在两个(64和128)的周围幂之间的跨度的第八个,所以你可以预期

    (0.1 / 64) * 2**52
    

    不同的 双重的 S——说到 7036874417766.4004 …给予或接受一个或两个;-)。

        2
  •  38
  •   Stephen Canon    14 年前

    每个 double 表示介于 0x0000000000000000 0x3ff0000000000000 位于间隔[0.0,1.0]。这是(2^62-2^52)不同的值(加或减一对取决于是否计算端点)。

    间隔[1.0,2.0]对应于 0x3f00000000000万 0x400000000000000 这是2^52个不同的值。

    间隔[100.0,101.0]对应于 0x4059000000000000 0x4059400000000000 ;这是2^46个不同的值。

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

    99999999999999982163600188718701095...
    

    10000000000000000159028911097599180...
    
        3
  •  6
  •   Mark Dickinson Alexandru    14 年前

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

    但是你提到了随机数生成器:注意,随机数生成器生成的数字介于0.0和1.0之间 不能 一般来说,产生所有这些数字;通常它只产生n个/n 2个数n的整数(参见例如Java文档)。 nextDouble )所以通常只有2^53(+/-1,取决于包括哪些端点)的可能值 random() 输出。这意味着在[0.0,1.0]中的大多数双精度将永远不会生成。

        4
  •  3
  •   Mark Rushakoff    14 年前

    文章 Java's new math, Part 2: Floating-point numbers IBM提供了以下代码片段来解决这个问题(在float中,但我怀疑它也适用于double):

    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之间(含1.0和2.0)正好有8388609个浮点数;很大,但很难是存在于这个范围内的不可数无穷大的实数。连续的数字间隔约为0.0000001。这个距离被称为ULP(最小精度单位)或最后一个单位。

        5
  •  2
  •   Yann Ramin    14 年前
    1. 2^53-64位浮点数的有效位/尾数的大小,包括隐藏位。
    2. 大致是的,因为sifnicand是固定的,但是指数会改变。

    wikipedia article 更多信息。

        6
  •  1
  •   njsf    14 年前

    Java双是IEEE 754二进制数。

    这意味着我们需要考虑:

    1. 尾数是52位
    2. 指数是11位数字,有1023个偏差(即增加了1023个)
    3. 如果指数均为0,尾数非零,则称该数为非规范化数。

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

    记住,如果尾数是正数,而指数是负数,则尾数是正数,但小于1:-)

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