直接计算的最小正浮点值与<float.h>中的FLT_MIN不同

时间:2017-08-15 12:27:43

标签: c floating-point

我想直接计算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。谁错了?

2 个答案:

答案 0 :(得分:41)

虽然此问题已被多次提出并回答过,但我认为没有任何答案是正确的。关键是FLT_MIN是可以表示的最小规范化值。回到过去那些重要的事情。然后英特尔出现并引入次正常值,这会降低精度以表示接近0的值。次正规是具有最小指数的值和高位全为零的分数。由此得出,最小的非零次正规值除了最低位(即1)之外都有一个全零的分数。这是可以表示的最小值,但是当你在那里时,在这里改变一下并且值的变化,因此必须非常小心地使用这些东西。

编辑,澄清“正常化”:

假设我们正在写小数值:6.02x10 ^ 23,.602 * 10 ^ 24,60.2 * 10 ^ 22。这些都代表相同的价值,但它们显然看起来不同。因此,让我们引入一个写十​​进制值的规则:每个值必须在小数点左边只有一个非零数字。所以该值的“标准化”形式为6.02x10 ^ 23,如果我们有一个以非标准化形式写的值,我们可以移动小数点并调整指数以保留该值并将其置于标准化形式。 / p>

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.这也是浮点数subnormals工作:当你越远越低于最小标准化值时,你得到的有效位越来越少,直到你用完了比特并得到0。

编辑:为澄清术语,IEEE-754标准将那些大于0且小于最小标准化值的值称为非正规;最新版本的IEEE-754将它们称为 subnormals 。他们的意思是一样的。

答案 1 :(得分:16)

您的结果Private Sub MoveThem() Dim sws As Worksheet Dim tws As Worksheet Dim cel As Range Set sws = Sheets("ALLSelections") Dim selectionTop, selectionBottom As Integer Dim sNm As String Dim lCol As Long Dim currentRow As Long selectionTop = 0 selectionBottom = 0 '~~> Get the last row and last column lRow = sws.Range("C" & sws.Rows.Count).End(xlUp).Row lCol = sws.Cells(1, sws.Columns.Count).End(xlToLeft).Column For currentRow = 2 To lRow If sws.Cells(currentRow, 1) > 1 Then If selectionTop = 0 Then selectionTop = currentRow ' Get the new sheet name sNm = sws.Cells(currentRow, 2).Value If Not WksExists(sNm) Then ' If not already created then add to Misc sNm = "Misc" End If Set tws = Sheets(sNm) End If End If ' Check out the next row If Len(sws.Cells(currentRow, 1).Offset(1)) <> 0 Then If selectionTop <> 0 And selectionBottom = 0 Then selectionBottom = currentRow End If If currentRow = lRow Then selectionBottom = currentRow If selectionTop <> 0 And selectionBottom <> 0 Then ' We know know the range of rows sws.Range("A" & selectionTop, "I" & selectionBottom).Copy tws.Range("A" & tws.Range("C" & Rows.Count).End(xlUp).Offset(1).Row) selectionTop = 0 selectionBottom = 0 Else End If Next MsgBox ("Complete") End Sub 是非正规最小正浮点值,也称为1.4013e-45,等于FLT_TRUE_MIN

1.401298464e-45F是规范化的最小正浮点值(FLT_MIN