Language agnostic 在[0.0,1.0]范围内,双精度计数器的唯一值总数是多少?

Language agnostic 在[0.0,1.0]范围内,双精度计数器的唯一值总数是多少?,language-agnostic,random,floating-point,discrete-mathematics,Language Agnostic,Random,Floating Point,Discrete Mathematics,Random.NextDouble()(范围[0.0,1.0]中的一个双精度)有时会与一个大的Int64相乘(让Int64 big=900000000l),然后对结果进行汇总,以获得一个大于从Random.Next()中获得的值的随机Int64值(范围[0,Int32.MaxValue]中的一个Int32) 在我看来,在[0.0,1.0]范围内的一个Double的唯一值的总数为它可能生成的唯一Int64的数量提供了一个上限。一个松散的上限,实际上,许多不同的Double将映射到同一个Int64

Random.NextDouble()(范围[0.0,1.0]中的一个双精度)有时会与一个大的Int64相乘(让Int64 big=900000000l),然后对结果进行汇总,以获得一个大于从Random.Next()中获得的值的随机Int64值(范围[0,Int32.MaxValue]中的一个Int32)

在我看来,在[0.0,1.0]范围内的一个Double的唯一值的总数为它可能生成的唯一Int64的数量提供了一个上限。一个松散的上限,实际上,许多不同的Double将映射到同一个Int64

因此,我想知道:在[0.0,1.0]范围内,双精度的唯一值总数是多少

如果您可以告诉我“big”可以取的最大值是什么,以便“answer”可以是范围[0,big]中的值,并且假设Random.NextDouble()是一致的,则更好

编辑:这里的Double(Double)表示IEEE 754浮点Double,而Int64(long)和Int32(int)分别表示64位和32位有符号2的补码


受到这个问题的启发:


虽然我使用了C#,但这个问题与语言无关,更多的是关于离散数学而不是编程,但它困扰我的主要原因不是数学上的好奇,而是一个程序员想要使用一个公式,只要它做了它应该做的事情,并且从安全的角度来看。

唯一值的总数对于[0.0,1.0]范围内的
double
,取决于特定环境中
double
的表示


最常见的表示形式之一是由指定的。该格式是由and强制执行的(参见1.3类型和变量了解后者)。

作为您问题的推论,我将告诉您,
Random
C#生成器在内部使用一个“给他”的生成器介于
0…Int32.MaxValue-1
之间的数字。然后它将该数字除以
Int32.MaxValue
(从技术上讲,它乘以该数字的倒数)以返回一个双精度。因此在C#中,只有
Int32.MaxValue
可能返回的双精度(
0…Int32.MaxValue-1

这取决于
double
的实现。有些实现不允许非规范化值,而忽略了前导值;在这里确定可能值的数量很容易:

  • 有一些“特殊”值(0、+0、-0、+∞, -∞, 无声的NaN,发出信号的NaN)通常会让您损失一个可能的指数
  • 移动尾数和修改指数不可能得到相等的数字

如果您的实现允许非规范化的值,那么确定这个数字就变得有点困难,但是我首先要将这个表示中的可能值映射到具有固定前导值的等价表示(这将在尾数中使用更少的一位);如果您找到了一个合适的映射,这将是,并且您已经将问题简化为一个更简单的问题。

IEEE-754有11个指数位和52个尾数位。假设符号位为0(正),如果指数范围为0x001到0x3FE,则该值是0到1之间的标准浮点数。尾数用未存储的前导1进行解释。对于指数的这些0x3FE值中的每一个,都有2^52个尾数值。此外,如果指数为0x000,则在解释尾数时不使用该前导ing值,但如果指数为0x001,则在所有尾数有效的情况下,总共0x3FF=1023个指数。这是总共1023*2^52个值。此外,负0可能会计数,这是另一个值


如果从所有值统一生成随机双精度,那么在乘法生成Int64时确实会产生偏差。但是,任何合理的随机库都会近似于[0,1]上的均匀分布,并且在将其转换为Int64时不会产生偏差。“big”的最大值这将允许[0,big]中的所有整数生成为2^53——1/2和1之间的2^52数字的分辨率为2^(-53)。然而,通常情况下,这些数字是通过将随机整数除以整数范围(通常为Int32)生成的意味着你不能产生比这个源更多的数字。考虑直接组合两个因特32,例如通过一个32位的移位并将它们组合成一个In64。(尽管要小心,发生器的状态空间可能只有32位。)

< P> IEEE74在双倍精度上是很清楚的:

您有52位精度加上一个额外的假定位

指数从-1022到1023,大约11位,包括一个符号

第64位是数字的总符号

我们将忽略未标准化的数字

您询问的是-1022和0之间的指数。这意味着您可以使用11位指数中的10位

您有52+1位尾数可用

这大约是62位可用精度,用于表示2**62个不同的值


@wnoise几乎成功了,但这是我的两分钱

IEEE浮点可以比较并作为整数递增,但有一些限制,请参阅以了解详细信息。因此,如果我们将+0.0和1.0转换为64位整数,我们将得到介于0和1之间的步数:

#include <iostream>

int main()
{
        double zero = 0.0;
        double one = 1.0;
        unsigned long long z = *reinterpret_cast<unsigned long long*>(&zero);
        unsigned long long o = *reinterpret_cast<unsigned long long*>(&one);
        std::cout << z << std::endl;
        std::cout << o << std::endl;
}
#包括
int main()
{
双零=0.0;
双一=1.0;
无符号长z=*重新解释强制转换(&0);
无符号长o=*重新解释强制转换(&1);

std::cout实际上,这个问题更多的是关于浮点表示法。
Random.NextDouble
实际上生成一个随机整数并除以
MAXINT
,所以你的问题有点没有意义
#include <iostream>

int main()
{
        double zero = 0.0;
        double one = 1.0;
        unsigned long long z = *reinterpret_cast<unsigned long long*>(&zero);
        unsigned long long o = *reinterpret_cast<unsigned long long*>(&one);
        std::cout << z << std::endl;
        std::cout << o << std::endl;
}