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

时间:2013-07-30 14:27:00

标签: c# floating-point ieee-754

我想另一种表达这个问题的方法是使用float只能在0到1之间的小数位?

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

但是,如果我这样做:

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

写出9.949219E-44

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

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

5 个答案:

答案 0 :(得分:30)

  

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

这不是您想要答案的问题,但答案是,不包括01本身,有2**23 - 1次正规数和{{1}此范围内的正常数字,总计126 * 2**23127 * 2**23 - 1

但请注意,这些数字<{>> 均匀分布在1,065,353,2150之间。在11f / 1065353215f的循环中使用0f的“delta”对您无效。

如果你想从(十进制)形式0.00 ... 01的步长为0.0到1.0,也许你应该使用 1f 而不是{{1} }。它将代表完全相同的数字。

如果您坚持使用decimal,请尝试使用float(比您建议的值大十倍),但请注意,在使用不可表示的数字执行大量添加时,错误可能会累积。< / p>

另请注意:有一些“域名”,您甚至无法依靠float的前七个有效十进制数字。尝试将值0.000001float保存到0.000986f变量(确保优化不会将值保存在“更宽”的存储位置)并写出该变量。前七位数字与0.000987f resp不同。 float。如果您想使用小数扩展为“短”的数字,您可以再次使用0.0009860000

修改:如果您可以为循环使用“二进制”步骤,请尝试使用:

0.0009870000

或等效地作为文字:

decimal

这个增量的好处在于,你通过循环所包含的所有值都可以在float delta = (float)Math.Pow(2, -24); 中完全表示。就在const float delta = 5.96046448e-8f; 之前(下),您将尽可能采取尽可能短的步骤。

答案 1 :(得分:16)

这是7个重要的位数,也就是说,当用指数表示法写入时,你忽略了指数。

0.0000000000000000001234567与12345670000000000000具有相同的有效数字位数,只是用不同的指数表示。这就是允许浮点数存储非常小且非常大的数字的神奇之处。

至于(0,1)中float究竟有多少可能的数字,我现在不能说完。你有一个23位的尾数,所以2 23 可能的状态。然后有一个8位指数,如果我不是非常错误,它的一半可能值将导致0到1之间的数字。这应该会给你带来大约2 23 + 7 = 2 30 该范围内的可能值。如果有什么可能是上限而不是确切的值。我需要查阅有关精确细节的文档才能确切了解(并且可能重新考虑上面的数学,可能会遗漏几点)。

答案 2 :(得分:13)

我写了这个非常愚蠢的程序,它给出了答案1065353217,这实际上只是2 30 (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();
    }
}

答案 3 :(得分:9)

正浮点值的排序与其编码相同。 0.0f0x000000001.0f0x3f800000。因此,0x3f800000 - 1个浮点值严格地介于两者之间,或者是1,065,353,215。

如果您想在计数中包含端点,请记住有两种编码为零。

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

答案 4 :(得分:0)

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

附言取决于个人计算机,代码执行最多可能需要2-3分钟

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
    }