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

我想另一种表达这个问题的方法是使用只能在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之间有多少个唯一值?

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

但请注意,这些数字在01之间的间隔上不均匀分布。 在0f1f的循环中使用1f / 1065353215f的“delta”将不适合您。

如果你想从0.0到1.0步长(十进制)forms0.00 … 01的步长,也许你应该使用decimal而不是float 。 它将完全代表这样的数字。

如果坚持float ,请尝试使用0.000001 (比建议值大10倍),但请注意,在使用不可表示的数字执行很多添加时,错误可能会累积。

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

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

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

或等效地作为文字:

 const float delta = 5.96046448e-8f; 

关于这个delta的好处是,你通过循环包含的所有值都可以在float中完全表示。 就在1f之前(下),您将尽可能采取尽可能短的步骤。

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

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

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

我写了这个非常愚蠢的程序,它给出了答案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(); } } 

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

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

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