标准浮点数的 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
本身,在这个范围内有2**23 - 1
次正规数和126 * 2**23
正常数,总共 127 * 2**23 - 1
或1,065,353,215
。
但请注意,这些数字在0
和1
之间的间隔上分布不均匀。在从0f
到1f
的循环中使用1f / 1065353215f
的"增量"对您不起作用。
形式的(十进制(长步长从 0.0 步到 1.0...01,也许你应该使用 decimal
而不是 float
。它将准确地表示这样的数字。
如果您坚持使用 float
,请尝试使用0.000001
(比建议的值大十倍(,但请注意,当使用不可表示的数字执行非常多的加法时,可能会累积错误。
另请注意:有一些"域"您甚至无法计算float
的前七个有效的十进制数字。例如,尝试将值0.000986f
或0.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.0f
是0x3f800000
. 因此,有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
}