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);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章