这是我多年来一直想到的事情,但我从来没有花时间问过。
许多(伪)随机数生成器生成介于0.0和1.0之间的随机数。在数学上,此范围内存在无限数,但double
是浮点数,因此具有有限的精度。
所以问题是:
double
个数字?注意:如果它有所不同,我特别感兴趣的是Java对double
的定义。
答案 0 :(得分:64)
Java double
采用IEEE-754格式,因此它们具有52位分数;在任何两个相邻的2的幂之间(包括一个并且不包括下一个),因此将存在2到52次幂不同的double
s(即,其中的4503599627370496)。例如,这是包括在0.5和1.0之间的不同double
的数量,并且恰好许多也包括在1.0和2.0之间,等等。
在0.0和1.0之间计算doubles
比在2的幂之间计算要困难,因为在该范围内包含许多2的幂,并且还有一个涉及非规范化数字的棘手问题。指数的11位中的10位覆盖了所讨论的范围,因此,包括非规范化数字(我认为有几种NaN
),你有double
次的1024次幂两个 - 总共不超过2**62
。不包括非规范化& c,我相信计数将是2**52
的1023倍。
对于像“100到100.1”这样的任意范围,它甚至更难,因为上限不能精确地表示为double
(不是两个幂的精确倍数)。作为一个方便的近似,由于2的幂之间的进展是线性的,你可以说所述范围是2(64和128)的周围幂之间的跨度的0.1 / 64
,所以你期望< / p>
(0.1 / 64) * 2**52
distinct double
s - 来7036874417766.4004
...给或拿一两个; - )。
答案 1 :(得分:39)
表示在double
和0x0000000000000000
之间的每个0x3ff0000000000000
值位于区间[0.0,1.0]中。那是(2 ^ 62 - 2 ^ 52)个不同的值(加上或减去一对,取决于你是否计算端点)。
区间[1.0,2.0]对应于0x3ff0000000000000
和0x400000000000000
之间的表示;这是2 ^ 52个不同的值。
区间[100.0,101.0]对应于0x4059000000000000
和0x4059400000000000
之间的表示;这是2 ^ 46个不同的值。
10 ^ 100和10 ^ 100 + 1 之间没有双打。这些数字中的任何一个都不能以双精度表示,并且它们之间没有双精度数。最接近的两个双精度数是:
99999999999999982163600188718701095...
和
10000000000000000159028911097599180...
答案 2 :(得分:6)
其他人已经解释过在[0.0,1.0]范围内有大约2 ^ 62个双打 (并不奇怪:有近2 ^ 64个不同的有限双打;其中一半是正数,而那些的大约一半都是<1.0。)
但是你提到了随机数生成器:请注意,生成0.0到1.0之间的数字的随机数生成器通常不会生成所有这些数字;通常它只产生n / 2 ^ 53形式的数字,其中n为整数(参见例如nextDouble的Java文档)。因此,random()
输出通常只有大约2 ^ 53(+/- 1,具体取决于包含哪些端点)的可能值。这意味着永远不会生成[0.0,1.0]中的大多数双打。
答案 3 :(得分:3)
来自IBM的文章Java's new math, Part 2: Floating-point numbers提供了以下代码片段来解决这个问题(在浮点数中,但我怀疑它也适用于双打):
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);
}
}
他们对此发表了评论:
事实证明,正好有8,388,609个浮点数介于1.0和2.0之间;很大但很难在这个范围内存在无数的实数无穷大。连续数字相差约0.0000001。该距离在最后一个位置称为ULP,用于最小精度或单位的单位。
答案 4 :(得分:2)
有关详细信息,请参阅wikipedia article。
答案 5 :(得分:1)
Java double是IEEE 754二进制64号。
这意味着我们需要考虑:
这基本上意味着总共有2 ^ 62-2 ^ 52 + 1个可能的双重表示,根据标准在0和1之间。注意2 ^ 52 + 1是去除案例的非标准化数字。
请记住,如果尾数为正,但指数为负数,则为正数但小于1: - )
对于其他数字,它有点难,因为边缘整数在IEEE 754表示中可能无法以精确的方式表示,并且因为指数中使用的其他位能够表示数字,所以越大数字越低,不同的值。