float格式简谈 以及自己编写的一段读写浮点数的代码

这是以前收集的资料,忘了出处了。

float格式简谈
Inter 80386/80387
及以上型号CPU有三种浮点类型,即短实数、长实数和80位临时实数,分别占用4字节、8字节和10字节,对应着C/C++中的floatdoublelong double[1],我以 Real4Real8Real0表示之。
每种浮点格式皆应符合IEEE标准,称为规格化数,不符合IEEE标准的浮点格式称为非格式化数(NAN),我以最简单的float格式举例。
Float
格式数据长32 bits,最高位为符号位:0为正,1为负;紧接着的8位为阶码:为了便于比较大小,其固定偏移7FH长,即0实际表示-7FH7FH实际表示00FFH实际表示80H;余下的低23位为尾数(有效数字),为了使有效数字达到最大精度,这23个有效数字隐含着固定位1[2],比如尾数10000000000000000000001其实就是1.100000000000000000000011被省略,而小数点固定在首位。
根据以上规则可以知道float所能表示的绝对值大小范围是
0 000,0000,0 000,0000,0000,0000,0000,0000 B

0 111,1111,1 111,1111,1111,1111,1111,1111 B
±1.00000000000000000000000B×2(0x00-0x7F) ±1.11111111111111111111111B×2(0xFF-0x7F)
然而事实上并不是这样,因为从这个范围可以看出它并不能表示0.0,而0.0为常用数字,所以特别规定±1.00000000000000000000000B×200为零,规定指数为0xFF的数字为非法数字,因此float实际的绝对值范围(除去0以外)是
0 000,0000,0 000,0000,0000,0000,0000,0001 B

0 111,1111,0 111,1111,1111,1111,1111,1111 B
0 并上 ±1.00000000000000000000001B×2(0x00-0x7F) ±1.11111111111111111111111B×2(0xFE-0x7F)
可能的格式状态:
+
不支持
+
非有效数
-
不支持
-
非有效数
+
规格化
+∞
-
规格化
-∞
+0
+

-0
-

+
不能规格化
-
不能规格化
可能的异常:
无效操作
上溢
下溢
除零
不可规格化操作数
精度不足
注意事项
a.
可以看出0可以用+0表示,也可以用-0表示,为此,CPU在比较零值时作了特殊处理,结果是±0虽然在存储器上格式不同,但比较值相同,然而如果是用字节来比较float类型大小时却需要注意这一点。
b.
运算上溢的值不是实际值,而是特值 0 111,1111,1 000,0000,0000,0000,0000,0000 B,例如 1.0×2127 + 1.5×2127 不等于 1.5×2128,虽然它有能力表示1.5×2128
c.
C++中的部分解决方案及遗留问题

5.参考资料
Inter 80X86/80387 汇编指南》

6.附录
[
1]M$认为double精度已足够,故在MVC++5.0及以后取消80位了临时实数,令long double等同于double,但在本文中的long double还是指80位临时实数。
[
2]:各种浮点类型格式类似,double指数偏移基数3FFHlong double指数偏移基数3FFFH,但long double特殊在无有效数字隐含位。
real04
:符号位1,阶码08(固定偏移  7F),尾数23,固定隐含位有;
real08
:符号位1,阶码11(固定偏移 3FF),尾数52,固定隐含位有;
real10
:符号位1,阶码15(固定偏移3FFF),尾数64,固定隐含位无;

以下是我用VC6编的一段从文件中读取写入浮点数的代码。

// 将浮点数写入文件
void CTestFloatDlg::WriteToFile(const CString & fileName)
{

 UpdateData();
 CFile dataFile;
 CFileException e;
 try
 {
  if(!dataFile.Open(fileName, CFile::modeWrite | CFile::modeCreate | CFile::shareExclusive, &e))
  {
   DWORD ERR = ::GetLastError();
   return;
  }
  dataFile.SeekToBegin();
  dataFile.Write(&m_fEdit1, MAX_READ);
  dataFile.Close();
 }
 catch(CFileException* pEx )
 {
  pEx->Delete();
 }
}

 

// 从文件中读取浮点数
void CTestFloatDlg::ReadFromFile(const CString & fileName)
{
 unsigned char byteArrB[8];
 byteArrB[0] = 1;
 byteArrB[1] = 2;
 byteArrB[2] = 4;
 byteArrB[3] = 0X8;
 byteArrB[4] = 0X10;
 byteArrB[5] = 0X20;
 byteArrB[6] = 0X40;
 byteArrB[7] = 0X80;
 
 CFile dataFile;
 CFileException e;
 try
 {
  if(!dataFile.Open(fileName, CFile::modeRead | CFile::shareExclusive, &e))
  {
   DWORD ERR = ::GetLastError();
   return;
  }
  dataFile.SeekToBegin();
  
  char data[MAX_READ];
  memset(data, 0, sizeof(char) * MAX_READ);
  dataFile.Read(data, MAX_READ);
  dataFile.Close();
  
  // 取出符号位,判断正负号
  int iSign = data[3] >> 7 > 0 ? -1 : 1;
  if ( -1 == iSign )
  {
   data[3] &= 0x7F;
  }
  
  // 计算 8位阶码
  int iExp = data[3] << 1;
  int iTemp = (data[2] >> 7) & 0X1;

  // float型固定偏移为0x7F, 所以需要减去该数
  iExp = iExp + iTemp - 0x7F;

  // 若指数在有效范围内
  if (iExp > -127 && iExp < 128)
  {
   // 计算隐含位
   m_fEdit2 = pow(2, iExp);
   double dTemp = 0;


   // 取低7位
   data[2] &= 0x7F;
   for (int i = 6; i >= 0; i--)
   {
    iExp--;
    int iTemp = data[2] & byteArrB[i];
    iTemp >>= i;
    m_fEdit2 += iTemp * pow(2, iExp);
   }

   for (i = 1; i >= 0; i--)
   {
    for (int j = 7; j >= 0; j--)
    {
     iExp--;
     int iTemp = data[i] & byteArrB[j];
     iTemp >>= j;
     m_fEdit2 += iTemp * pow(2, iExp);
    }
   }
  }
  else
  {
   m_fEdit2 = 0;
  }
  UpdateData(FALSE);
 }
 catch(CFileException* pEx )
 {
  pEx->Delete();
 }
}

 

// 读写的例子

 CString strFileName = "C://Read.txt";
 WriteToFile(strFileName);

 

 CString strFileName = "C://Read.txt";
 ReadFromFile(strFileName);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值