我想直接计算float类型的最小值,下面是我的算法(假设浮点数的编码符合ieee 754标准):

#include <math.h>
#include <limits.h>
#include <float.h>
#include <stdio.h>

float float_min()
{
    int exp_bit = CHAR_BIT * sizeof(float) - FLT_MANT_DIG;
    float exp = 2 - pow(2, exp_bit - 1);

    float m = pow(2, -(FLT_MANT_DIG - 1));

    return m * pow(2, exp);
}

int main()
{
    printf("%g\n", float_min());
}

输出为1.4013e-45。但是,我发现FLT_MINC:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\float.h的值是1.175494351e-38F。谁错了?

最佳答案

虽然这个问题以前已经问过好几次了,但我看不出任何真正正确的答案。关键是FLT_MIN是可以表示的最小规范化值。回到过去,一切都很重要。然后,英特尔推出了次标准值,这会降低精度,以便表示接近0的值。次正规是指指数最小的值和一个分数,其高位都是零。由此可知,最小的非零次正规值有一个分数,除最低位(1)外,其余均为零。这是可以表示的最小值,但是当你在下面的时候,这里和那里的变化会使值发生很大的变化,所以这些东西必须非常小心地使用。
编辑,澄清“规范化”:
假设我们写的是十进制值:6.02x10^23,.602*10^24,60.2*10^22。这些都代表着相同的价值,但它们看起来显然不同。所以,让我们介绍一个写十进制值的规则:每个值在小数点的左边必须正好有一个非零数字。所以这个值的“标准化”形式是6.02x10^23,如果我们有一个用非标准化形式写的值,我们可以移动小数点,调整指数来保持这个值,并把它变成标准化形式。
ieee浮点也做了同样的事情:规则是分数的高位必须始终为1,任何计算都必须调整分数及其结果的指数以满足该规则。
当我们写非常接近0的十进制值时,这不是问题:我们可以使指数尽可能小,这样我们就可以写6.02*10^-16384这样的数字。对于浮点值,我们不能这样做:有一个最小的指数,我们不能低于。为了允许更小的值,ieee的要求是当指数是最小的可表示值时,分数不必被规范化,也就是说,它的高位不必有1。在写十进制值时,这就好像我们可以在小数点的左边有一个0。因此,如果我们的十进制规则是允许的最低指数是-100,那么最小的规范化值是1.00x10^-100,但是较小的值可以表示为非规范化:0.10*10^-100,0.01*10^-100,等等。
现在给我们的十进制规则增加一个要求,我们只能有三个数字:一个在小数点的左边,两个在右边。就像浮点数一样,它有固定的位数。所以对于小的正常值,我们有三个数字可以使用:1.23*10^-100。对于较小的值,我们使用前导零,其余数字的精度较低:0.12*10^-100有两位数,而0.01*10^-100只有1位数。这也是浮点次正规化的工作原理:当你越来越远地低于最小正规化值时,你得到的有效位越来越少,直到你用完位,得到0。
编辑:为了澄清术语,ieee-754标准将大于0且小于最小规范值的值称为非规范值;ieee-754的最新版本将其称为次规范值。他们的意思是一样的。

关于c - 通过直接计算得出的最小正浮点值与<float.h>中的FLT_MIN不同,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45692834/

10-11 22:50
查看更多