我想直接计算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_MIN
中C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\float.h
的值为1.175494351e-38F
。谁错了?
答案 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
)