国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
浮點(diǎn)數(shù)小析
眾所周知,計(jì)算機(jī)中的所有數(shù)據(jù)都是以二進(jìn)制表示的,浮點(diǎn)數(shù)也不例外。然而浮點(diǎn)數(shù)的二進(jìn)制表示法卻不像定點(diǎn)數(shù)那么簡(jiǎn)單了。  
   
  先澄清一個(gè)概念,浮點(diǎn)數(shù)并不一定等于小數(shù),定點(diǎn)數(shù)也并不一定就是整數(shù)。所謂浮點(diǎn)數(shù)就是小數(shù)點(diǎn)在邏輯上是不固定的,而定點(diǎn)數(shù)只能表示小數(shù)點(diǎn)固定的數(shù)值,具用浮點(diǎn)數(shù)或定點(diǎn)數(shù)表示某哪一種數(shù)要看用戶賦予了這個(gè)數(shù)的意義是什么。  
   
  C++中的浮點(diǎn)數(shù)有6種,分別是:  
   
  float:?jiǎn)尉龋?2位  
  unsigned   float:?jiǎn)尉葻o(wú)符號(hào),32位  
  double:雙精度,64位  
  unsigned   double:雙精度無(wú)符號(hào),64位  
  long   double:高雙精度,80位  
  unsigned   long   double:高雙精度無(wú)符號(hào),80位(嚯,應(yīng)該是C++中最長(zhǎng)的內(nèi)置類型了吧?。? 
   
  然而不同的編譯器對(duì)它們的支持也略有不同,據(jù)我所知,很多編譯器都沒(méi)有按照IEEE規(guī)定的標(biāo)準(zhǔn)80位支持后兩種浮點(diǎn)數(shù)的,大多數(shù)編譯器將它們視為double,或許還有極個(gè)別的編譯器將它們視為128位?!對(duì)于128位的long   double我也僅是聽(tīng)說(shuō)過(guò),沒(méi)有求證,哪位高人知道這一細(xì)節(jié)煩勞告知。  
   
  下面我僅以float(帶符號(hào),單精度,32位)類型的浮點(diǎn)數(shù)說(shuō)明C++中的浮點(diǎn)數(shù)是如何在內(nèi)存中表示的。先講一下基礎(chǔ)知識(shí),純小數(shù)的二進(jìn)制表示。(純小數(shù)就是沒(méi)有整數(shù)部分的小數(shù),講給小學(xué)沒(méi)好好學(xué)的人)  
   
  純小數(shù)要想用二進(jìn)制表示,必須先進(jìn)行規(guī)格化,即化為   1.xxxxx   *   (   2   ^   n   )   的形式(“^”代表乘方,2   ^   n表示2的n次方)。對(duì)于一個(gè)純小數(shù)D,求n的公式如下:  
  n   =   1   +   log2(D); //   純小數(shù)求得的n必為負(fù)數(shù)  
  再用   D   /   (   2   ^   n   )   就可以得到規(guī)格化后的小數(shù)了。接下來(lái)就是十進(jìn)制到二進(jìn)制的轉(zhuǎn)化問(wèn)題,為了更好的理解,先來(lái)看一下10進(jìn)制的純小數(shù)是怎么表示的,假設(shè)有純小數(shù)D,它小數(shù)點(diǎn)后的每一位數(shù)字按順序形成一個(gè)集合:  
  {k1,   k2,   k3,   ...   ,   kn}  
  那么D又可以這樣表示:  
  D   =   k1   /   (10   ^   1   )   +   k2   /   (10   ^   2   )   +   k3   /   (10   ^   3   )   +   ...   +   kn   /   (10   ^   n   )  
  推廣到二進(jìn)制中,純小數(shù)的表示法即為:  
  D   =   b1   /   (2   ^   1   )   +   b2   /   (2   ^   2   )   +   b3   /   (2   ^   3   )   +   ...   +   bn   /   (2   ^   n   )  
  現(xiàn)在問(wèn)題就是怎樣求得b1,   b2,   b3,……,bn。算法描述起來(lái)比較復(fù)雜,還是用數(shù)字來(lái)說(shuō)話吧。聲明一下,1   /   (   2   ^   n   )這個(gè)數(shù)比較特殊,我稱之為位階值。  
  例如0.456,第1位,0.456小于位階值0.5故為0;第2位,0.456大于位階值0.25,該位為1,并將0.45減去0.25得0.206進(jìn)下一位;第3位,0.206大于位階值0.125,該位為1,并將0.206減去0.125得0.081進(jìn)下一位;第4位,0.081大于0.0625,為1,并將0.081減去0.0625得0.0185進(jìn)下一位;第5位0.0185小于0.03125……  
  最后把計(jì)算得到的足夠多的1和0按位順序組合起來(lái),就得到了一個(gè)比較精確的用二進(jìn)制表示的純小數(shù)了,同時(shí)精度問(wèn)題也就由此產(chǎn)生,許多數(shù)都是無(wú)法在有限的n內(nèi)完全精確的表示出來(lái)的,我們只能利用更大的n值來(lái)更精確的表示這個(gè)數(shù),這就是為什么在許多領(lǐng)域,程序員都更喜歡用double而不是float。  
   
  float的內(nèi)存結(jié)構(gòu),我用一個(gè)帶位域的結(jié)構(gòu)體描述如下:  
  struct   MYFLOAT  
  {  
  bool   bSign   :   1;     //   符號(hào),表示正負(fù),1位  
  char   cExponent   :   8;     //   指數(shù),8位  
  unsigned   long   ulMantissa   :   23;   //   尾數(shù),23位  
  };  
   
  符號(hào)就不用多說(shuō)了,1表示負(fù),0表示正  
  指數(shù)是以2為底的,范圍是   -128   到   127,實(shí)際數(shù)據(jù)中的指數(shù)是原始指數(shù)加上127得到的,如果超過(guò)了127,則從-128開(kāi)始計(jì),其行為和X86架構(gòu)的CPU處理加減法的溢出是一樣的。比如:127   +   2   =   -127;127   -   2   =   127  
  尾數(shù)都省去了第1位的1,所以在還原時(shí)要先在第一位加上1。它可能包含整數(shù)和純小數(shù)兩部分,也可能只包含其中一部分,視數(shù)字大小而定。對(duì)于帶有整數(shù)部分的浮點(diǎn)數(shù),其整數(shù)的表示法有兩種,當(dāng)整數(shù)大于十進(jìn)制的16777215時(shí)使用的是科學(xué)計(jì)數(shù)法,如果小于或等于則直接采用一般的二進(jìn)制表示法??茖W(xué)計(jì)數(shù)法和小數(shù)的表示法是一樣的。  
  小數(shù)部分則是直接使用科學(xué)計(jì)數(shù)法,但形式不是X   *   (   10   ^   n   ),而是X   *   (   2   ^   n   )。拆開(kāi)來(lái)看。  
   
  0 00000000 0000000000000000000000  
  符號(hào)位 指數(shù)位 尾數(shù)位  
   
   
  下面是一個(gè)分析float類型內(nèi)存數(shù)據(jù)的程序,經(jīng)測(cè)試是完好的,如果發(fā)現(xiàn)有問(wèn)題,請(qǐng)?zhí)岢鰜?lái),我好改進(jìn)。   
 
 
 #include   <iostream>  
  #include   <iomanip>  
  using   namespace   std;  
   
  int   _tmain(   int   argc,   _TCHAR*   argv[]   )  
  {  
  //   有符號(hào)的32位float類型浮點(diǎn)數(shù)變量的定義及數(shù)據(jù)初始化,其值可任意修改  
  float   fDigital   =   0.0f;  
  //   臨時(shí)變量,用于存儲(chǔ)浮點(diǎn)數(shù)的內(nèi)存數(shù)據(jù)  
  unsigned   long   nMem;  
  //   將內(nèi)存按位復(fù)制到臨時(shí)變中,以便取用。  
  nMem   =   *(unsigned   long*)&fDigital;  
   
  //   以小數(shù)點(diǎn)后保留8個(gè)小數(shù)點(diǎn)的精度輸出原始浮點(diǎn)數(shù)  
  cout   <<   setprecision(   8   );  
  cout   <<   "浮點(diǎn)數(shù):"   <<     fDigital   <<   endl;  
  cout   <<   "-----------------------"   <<   endl;  
   
  //   判斷是否為0,全部位都為0的浮點(diǎn)數(shù)據(jù)表示0,無(wú)分析意義  
  if   (   nMem   !=   0   )  
  {  
  //   打印出其符號(hào)。  
  //   最高1位為符號(hào)位。用bool來(lái)表示,true表示負(fù)數(shù),false表示正數(shù)。  
  //   和最高位為1的數(shù)據(jù)0x80000000進(jìn)行按位與,可得到其符號(hào)。  
  bool   bNegative   =   (   (   nMem   &   0x80000000L   )   !=   0   );  
  //   如果是負(fù)數(shù),則輸入負(fù)號(hào),否則輸出空格。  
  cout   <<   "符號(hào):"   <<   (   bNegative   ?   '-'   :   '+'   )   <<   endl;  
   
  //   打印出其指數(shù)。  
  //   第30   -   23位是指數(shù)位,是有正負(fù)的8位整數(shù)數(shù)據(jù),用char來(lái)表示。  
  //   將內(nèi)存右移一位,再左移24位,再硬性截?cái)酁?位即可得到指數(shù)原始數(shù)據(jù)。  
  char   cExponent   =   (char)(   (   nMem   <<   1   )   >>   24   );  
  //   IEEE浮點(diǎn)數(shù)表示法規(guī)定,原指數(shù)加127為內(nèi)存中的指數(shù)。  
  //   將原始指數(shù)數(shù)據(jù)減127得到其真實(shí)指數(shù)(CPU會(huì)自動(dòng)處理上下界溢出)。  
  cExponent   -=   127;  
  //   以10進(jìn)制帶符號(hào)整數(shù)方式輸出指數(shù)數(shù)據(jù)  
  cout   <<   "指數(shù):"   <<   (int)cExponent   <<   endl;  
   
  //   打印出其尾數(shù)。  
  //   第22   -   0位是尾數(shù)位,由于省去了頭一位1,因此應(yīng)該是24位無(wú)符號(hào)數(shù)據(jù)。  
  //   用無(wú)符號(hào)長(zhǎng)整型來(lái)表示。  
  //   和最低22位都是1的數(shù)據(jù)0x7FFFFF進(jìn)行按位與,可得到尾數(shù)原始數(shù)據(jù)  
  unsigned   long   ulMantissa   =   (   nMem   &   0x7FFFFFL   );  
  //   和第23位是1的數(shù)據(jù)0x800000進(jìn)行按位或,可補(bǔ)齊省去的最高位1  
  ulMantissa   |=   0x800000L;  
  //   以16進(jìn)制整數(shù)方式輸出尾數(shù)數(shù)據(jù)  
  cout   <<   "尾數(shù):0x"   <<   setbase(   16   )   <<   setfill(   '0'   )   <<   setw(   8   );  
  cout   <<   setiosflags(   ios_base::uppercase   )   <<     ulMantissa   <<   endl;  
   
  //   完全基于整型算法來(lái)實(shí)現(xiàn)二進(jìn)制小數(shù)到整數(shù)的轉(zhuǎn)換極其復(fù)雜,  
  //   這里借用double簡(jiǎn)單實(shí)現(xiàn),僅說(shuō)明其理論。詳細(xì)算法見(jiàn)說(shuō)明。  
  //   計(jì)算出浮點(diǎn)數(shù)的整數(shù)部分,用雙精度型表示  
  double   dInteger   =   0;  
  //   指數(shù)大于或等于0就代表尾數(shù)中存在整數(shù)部分  
  if   (   cExponent   >=   0   )  
  {  
  //   如果指數(shù)大于23,則說(shuō)明整數(shù)部分以科學(xué)計(jì)數(shù)法表示  
  if   (   cExponent   >   23   )  
  {  
  //   dCurBit用來(lái)計(jì)算和存儲(chǔ)循環(huán)中對(duì)于每一位的位階數(shù)  
  double   dCurBit   =   1.0;  
  //   循環(huán)所有位,計(jì)算科學(xué)計(jì)數(shù)法中的小數(shù)的十進(jìn)制形式  
  for   (   int   nBitIdx   =   0;   nBitIdx   <   24;   nBitIdx++   )  
  {  
  //   將整數(shù)部分左移當(dāng)前位加9,將當(dāng)前位置于最高位;  
  //   再右移31位可得當(dāng)前位,再用當(dāng)前位階乘以該位,  
  //   即得累加數(shù)。累加計(jì)入二進(jìn)制小數(shù)。  
  dInteger   +=   dCurBit   *   (   (   ulMantissa   <<  
  (   8   +   nBitIdx   )   )   >>   31   );  
  //   由當(dāng)前位階除以2得到下次位階。  
  dCurBit   /=   2;  
  }  
  //   將二進(jìn)制表示的科學(xué)計(jì)數(shù)法轉(zhuǎn)換為10進(jìn)制  
  dInteger   *=   pow(   2.0,   (double)cExponent   );  
  }  
  else  
  {  
  //   將尾數(shù)右移小數(shù)部分的長(zhǎng)度,即可得到整數(shù)部分  
  int   nRightShift   =   0;  
  //   如果指數(shù)小于23,則說(shuō)明存在小數(shù)部分,需要右移  
  if   (   cExponent   <   23   )  
  {  
  //   尾數(shù)的原始長(zhǎng)度減去指數(shù)即為小數(shù)部分長(zhǎng)度  
  nRightShift   =   23   -   cExponent;  
  }  
  //   將尾數(shù)數(shù)據(jù)右移小數(shù)部分的長(zhǎng)度,可得到整數(shù)部分。  
  dInteger   =   (double)(   ulMantissa   >>   nRightShift   );  
  }  
  }  
  //   以10進(jìn)制無(wú)符號(hào)整數(shù)方式輸出整數(shù)部分  
  cout   <<   "整數(shù)部分:"   <<   setbase(   10   )   <<   setprecision(   8   );  
  cout   <<   dInteger   <<   endl;  
   
  //   計(jì)算出浮點(diǎn)數(shù)的小數(shù)部分,用無(wú)符號(hào)長(zhǎng)整型表示  
  double   dDecimal   =   0;  
  //   如果指數(shù)小于23,則尾數(shù)中含小數(shù)部分  
  if   (   cExponent   <   23   )  
  {  
  //   指數(shù)與23的差就是小數(shù)部分的長(zhǎng)度,詳見(jiàn)整數(shù)部分的處理。  
  //   將所有位均為1的32位整數(shù)右移32減小數(shù)部分長(zhǎng)度,即指數(shù)加9,  
  //   可得到用于取得小數(shù)部分的mask數(shù)。  
  unsigned   long   ulDecimalMask   =   0xFFFFFFFF;  
  //   如果指數(shù)大于或等于0就代表尾數(shù)中存在整數(shù)部分  
  if   (   cExponent   >=   0   )  
  {  
  ulDecimalMask   >>=   (   9   +   cExponent   );  
  }  
  else  
  {  
  //   如果是純小數(shù),則必須恢復(fù)規(guī)格化時(shí)刪掉的整數(shù)1  
  dDecimal   =   1.0;  
  }  
  //   將尾數(shù)和mask數(shù)進(jìn)行按位與,可得到小數(shù)部分  
  //   二進(jìn)制小數(shù)用無(wú)符號(hào)長(zhǎng)整型表示  
  unsigned   long   ulDecimal   =   ulMantissa   &   ulDecimalMask;  
  //   dCurBit用來(lái)計(jì)算和存儲(chǔ)循環(huán)中對(duì)于每一位的位階數(shù)  
  double   dCurBit   =   0.5;  
  //   循環(huán)所有位,計(jì)算科學(xué)計(jì)數(shù)法中的小數(shù)的十進(jìn)制形式  
  for   (   int   nBitIdx   =   1;   nBitIdx   <   24;   nBitIdx++   )  
  {  
  //   將二進(jìn)制小數(shù)左移當(dāng)前位加9,將當(dāng)前位置于最高位;  
  //   再右移31位可得當(dāng)前位。  
  //   用dCurBit乘以當(dāng)前位,即得累加數(shù)。累加計(jì)入dDecimal。  
  dDecimal   +=   dCurBit   *   (   (   ulDecimal   <<  
  (   8   +   nBitIdx   )   )   >>   31   );  
  //   由當(dāng)前位階除以2得到下次位階。  
  dCurBit   /=   2;  
  }  
  //   將二進(jìn)制表示的科學(xué)計(jì)數(shù)法轉(zhuǎn)換為10進(jìn)制  
  dDecimal   *=   pow(   2.0,   (double)cExponent   );  
  }  
  //   以10進(jìn)制無(wú)符號(hào)整數(shù)方式輸出小數(shù)部分  
  cout   <<   "小數(shù)部分:"   <<   setbase(   10   )   <<   setprecision(   8   );  
  cout   <<   dDecimal   <<   endl;  
  }  
  else  
  {  
  cout   <<   "浮點(diǎn)數(shù)為0,無(wú)分析意義"   <<   endl;  
  }  
   
  cout   <<   "-----------------------"   <<   endl;  
  cout   <<   "分析完畢,程序退出。"   <<   endl   <<   endl;  
   
   
   
  ////////////不可改動(dòng)//////////////  
  system(   "pause"   );  
  // _CrtDumpMemoryLeaks();  
  return   0;  
  ////////////不可改動(dòng)//////////////  
   
  }   

   
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
IEEE浮點(diǎn)數(shù)表示法(zz)
浮點(diǎn)數(shù)的表示與類型轉(zhuǎn)換-追逐理想-博客園
校OJ 11076 浮點(diǎn)數(shù)的分?jǐn)?shù)表達(dá)
階碼、定點(diǎn)整數(shù)
**C/C++中浮點(diǎn)數(shù)的存儲(chǔ)方式
基礎(chǔ)筆記2 —— 不損失精度的前提下浮點(diǎn)數(shù)拆分成整型的方法淺析
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服