标准浮点数的 0 到 1 之间有多少个唯一值

本文关键字:多少 唯一 之间 浮点数 标准 | 更新日期: 2023-09-27 18:25:28

我想这个问题的另一种措辞方式是,使用仅在 0 到 1 之间的float,您可以去小数点后位吗?

我试图通过查看MSDN来解决这个问题。这表示精度为 7 位。我认为这意味着它只能跟踪0.0000001的变化。

但是,如果我这样做:

float test = 0.00000000000000000000000000000000000000000001f;
Console.WriteLine(test);

它写出了9.949219E-44

如果我再添加零,它将输出0.

我很确定我在这里遗漏了一些东西,因为这种准确性似乎非常错误。主要是因为浮点数的大小为 32 位,在该精度级别上仅从 0-1 包含 1e+44 个可能的数字......

标准浮点数的 0 到 1 之间有多少个唯一值

标准浮点数的 0 到 1 之间有多少个唯一值?

这不是你想要答案的问题,但答案是,不包括01本身,在这个范围内有2**23 - 1次正规数和126 * 2**23正常数,总共 127 * 2**23 - 11,065,353,215

但请注意,这些数字在01之间的间隔上分布不均匀。在从0f1f的循环中使用1f / 1065353215f的"增量"对您不起作用。

如果你想用(十进制(

形式的(十进制(长步长从 0.0 步到 1.0...01,也许你应该使用 decimal 而不是 float 。它将准确地表示这样的数字。

如果您坚持使用 float ,请尝试使用0.000001(比建议的值大十倍(,但请注意,当使用不可表示的数字执行非常多的加法时,可能会累积错误。

另请注意:有一些"域"您甚至无法计算float的前七个有效的十进制数字。例如,尝试将值0.000986f0.000987f保存到float变量(确保优化不会将值保存在"更宽"的存储位置(并写出该变量。前七位数字与0.0009860000不同。 0.0009870000 .同样,如果您想使用十进制扩展为"短"的数字,您可以使用decimal

编辑:如果可以为循环使用"二进制"步骤,请尝试使用:

float delta = (float)Math.Pow(2, -24);

或等效为文字:

const float delta = 5.96046448e-8f;

这个增量的好处是,你通过循环输入的所有值都可以在你的float中精确地表示。就在(低于(1f之前,您将为该量级采取尽可能短的步骤。

它是 7 位有效数字,也就是说,当以指数表示法编写它时,您会忽略指数。

0.0000000000000000001234567 的有效位数与 12345670000000000000 相同,只是指数不同。这就是允许浮点数存储非常小和非常大的数字的魔力。

至于(0,1(中一个float究竟有多少个可能的数字,我现在不能确切地说。你有一个 23 位尾数,所以 223 种可能的状态。然后有一个 8 位指数,如果我没有弄错的话,大约一半的可能值将导致一个介于 0 和 1 之间的数字。这应该给您留下大约 223 + 7 = 230 个可能的值。如果有的话,这可能是一个上限,而不是确切的值。我需要查阅有关更精细细节的文档才能确切了解(并且可能会重新考虑上面的数学,这可能会遗漏几点(。

我写了这个非常愚蠢的程序,它给出了答案1065353217,这确实只有230(1073741824(。如果您正在寻找不包括 0 和 1 的所有数字,请从该数字中减去 2。顺便说一下,最小的非零数似乎是 1.401298E-45。

class Program
{
    public unsafe static int Search()
    {
        int i = 0;
        float* f = (float*)&i;
        while (*f >= 0 && *f <= 1)
        {
            f = (float*)&i;
            i++;
        }
        return i;
    }
    static void Main(string[] args)
    {
        Console.WriteLine(Search());
        Console.ReadLine();
    }
}

正浮点值的排序与其编码相同。 0.0f 0x00000000. 1.0f0x3f800000. 因此,有0x3f800000 - 1浮点值严格介于两者之间,即 1,065,353,215。

如果要在计数中包含终结点,请记住,有两种编码为零。

还要记住,浮点值的间距不均匀。 1.0f和下一个较小数之间的差是2**-24,而0.0f和下一个较大数之间的差是2**-149。 如果要以统一步长将浮点数从 0 增加到 1,则可以使用的最小步长为 2**-24

由于浮点型有 4 个字节数据,我们可以使用以下代码检查所有 4 字节 (0-255( 的所有可能变体,并计算其中有多少在 [0,1] 范围内 - 包括
所以答案将是1065353218

附言代码执行最多可能需要 2-3 分钟,具体取决于 PC

public static void Main()
    {
        long count = 0;
        //byte checking sub/method
        void CheckThisBytes(byte ii, byte jj, byte kk, byte ll)
        {
            var data = new[] {ii, jj, kk, ll};
            var f = BitConverter.ToSingle(data, 0);
            //is f in range ?
            if (f >= 0.0 && f <= 1.0)
            {
                count++;
            }
        }
        const int max = 255;
        // generate all possible cases 
        for (var i = 0; i <= max; i++)
        {
            for (var j = 0; j <= max; j++)
            {
                for (var k = 0; k <=max; k++)
                {
                    for (var l = 0; l <= max; l++)
                    {
                        //check if current float is in range
                        CheckThisBytes((byte) i, (byte) j, (byte) k, (byte) l);
                    }
                }
            }
        }
        Console.WriteLine("'n Count:" + count);
        Console.ReadLine();
        //result will be  1065353218
    }