硬造的輪子趟過的坑--浮點型轉字符串函數


浮點型轉字符串是最常見的一個功能了,對於弱類型語言來說更是幾乎感覺不到。但現在問個問題?用C語言寫一個浮點數轉字符串的函數,有多難呢?

一開始寫這個函數的時候是大二的時候,那時候在學C51單片機,用到1602顯示屏,就是下圖這貨,通常遇到的情況就是要想要在屏幕上顯示整數或者浮點數,1602封裝的字庫里面接口規范里接收的是字符串,所以在寫程序時必須先把整數和浮點數轉換成字符串。當時我就找到好像說 itoa , ftoa 這樣的方法,但是那兩個方法需要使用 stdlib.h 庫,而Keil C51 IDE里面沒有提供這個庫,網上找了很久也沒有找到答案,於是就自己着手寫了。后來才知道,在stdio.h里面有一個sprintf函數可以做這種轉換的事情,這已經是一年多后畢業求職時在某家公司面試的時候被告知的。

下面開始介紹浮點型轉字符串的基本思路:

1、判斷是否為負數,若是負數則作標記,在最后字符串合成時加上負號“-”,並取其絕對值;

  例:-999.98,則設定負數標記位置1,並取其絕對值999.98

2、把浮點串拆分為整數部分和小數部分;

  例:999.98拆分成 999 和 0.98

3、先處理小數部分還是整數部分?答案是小數部分,因為小數部分可能會四舍五入進位,對整數部分造成影響;

4.1、小數部分,假設這里要保留兩位小數,取最后一位數字是到哪位呢?實踐證明答案是三位,如果取兩位,很可能會得到不可思議的結果;

  例:0.98乘以100后得到的結果可能不是98而是97,而乘以1000后得到的結果可能不是980而是979

  因為計算機記錄小數是不精確的,在運算時可能會有細小誤差,所以我們要取多一位進行四舍五入

4.2、因為可能進位的原因,從最低位開始逐步獲取數字,並使用進位標置判斷更新數字;

  例:0.98乘以1000=>979,取最后一位數得到 '9',9>=5,所以標記進位;下一個得到 '7',加上進位標記變成 '8',復位進位標記;再下一個得到 '9';整理起來小數部分得到的字符串就是 '9'、'8';

  Tips:整型數字要加上0x30(十進制48)轉為其對應的ASCII字符,如:9+0x30='9'

4.3、為了說明前面有所提及的整數進位情況,從這里假設為保留一位小數再來演示一次;

  例:0.98乘以100=>97,取最后一位得到 '7',7>=5,所以標記進位;下一個得到 '9',加上進位標記變成 10,所以取得數字 '0', 標記位繼續有效,因為這個是小數的最大一位了,所以這個進位要進到整數中去,這里要做好標記

5.1、整數部分,假設最高支持5位,從高位到低位分別取出數字;

  例:999取得 '0'、'0'、'9'、'9'、'9'

5.2、整數部分,處理小數進位到整數來的標記,從最低到最高位逐級進位

  例:這里的 9 一直進位,直到最高一位從 0 變成了 1,'0'、'0'、'9'、'9'、'9'變成了 '0'、'1'、'0'、'0'、'0'

5.3、整數部分,從高位到低位判斷非0第一次出現的位置,定為整數部分的字符串,前面的0忽略;

  例:01000的真正字符串是'1'、'0'、'0'、'0',前的一個'0'忽略

6、拼裝小數部分、整數部分、小數點和可能的負號;

  例:保留一位小數得到了 "-1000.0"

 

陷阱總結:

1、小數部分一定要取到保留的下一位,即使看起來保留的下一位就是0,否則可能會 1.8 變成 "1.7" 而實際是 1.79...

2、小數部分不能直接向整數部分一樣乘以一個數然后去掉前面的0,否則會使像 1.02 變成 "1.2",把小數中的前面的0吃掉了;

3、記得取出的數字要轉成字符,更要注意大小比較時,數字要與數字相比較,字符要與字符相比較,不可混用,兩者大小相差48;

4、留意每一步的進位,小數到整數部分的進位最容易被忽視;

 

如果沒做,真的沒想到一個如此基礎的函數其間要處理問題是如此之多,很感謝那些算法大牛們為我們鋪好一條條康庄大道,讓我們在編程的世界里更加輕松地馳騁。下面是我一年前大學三年級時用C語言寫的實現代碼,跟上面說的思路在細節上稍有順序不同,可能看起來非常冗余,可能還有一些尚未發現的BUG,可能大家會有更高明的實現算法。還請多多交流。

 1 //浮點型轉字符串
 2 void float2Str(double fda,char *pString,uint8 dNum){  3  uint8 i;  4     bit negative=0;    //負數標志位
 5     bit X999        = 0;        //小數部分四舍五入進位標志
 6     bit XtoZ        = 0;        //小數到整數的進位標志
 7     uint8 intLen=5;  8     uint8 cdat[6]={0};        //分部分時的字符串
 9     uint8 whole[18]={0};    //整個數的字符串,其中留多一位為0x00 
 10 
 11     int ida;                //整數部分
 12     double dec;                //小數部分
 13     
 14     if (fda < 0){                //若為負數取絕對值
 15         fda = -fda;  16         negative = 1;  17  }  18     ida = (int) (fda) ;  19     dec = fda - ida;  20     
 21 ///////////////////小數部分轉換////////////// 
 22     if (dNum >= 6)            //小數最多顯示5位
 23         dNum = 5;  24     switch (dNum +1){  25         case 6:{  26             cdat[5] = (char)  (((long) (dec *1000000l))%10);    //0.0000001位 
 27             whole[15+ 6-dNum] = cdat[5] + 0x30;  28             //四舍五入算法
 29             if (X999 == 1){  30                 if (whole[15+ 6-dNum] < '9'){        //小於9就加1
 31                     whole[15+ 6-dNum] += 1;  32                     X999 = 0;  33                 }else{            //否則繼續進位,本位置0
 34                     whole[15+ 6-dNum] = '0';  35  }  36  }  37             
 38             if ( dNum==5){  39                 if (whole[15+ 6-dNum] >= '5')  40                     X999 = 1;  41                 whole[15+ 6-dNum] = 0x00;  42  }  43             //////////////////////////
 44             
 45  }  46         case 5:{  47             cdat[4] = (char)  (((long) (dec *100000l))%10);        //0.000001位 
 48             whole[15+ 5-dNum] = cdat[4] + 0x30;  49             //四舍五入算法
 50             if (X999 == 1){  51                 if (whole[15+ 5-dNum] < '9'){        //小於9就加1
 52                     whole[15+ 5-dNum] += 1;  53                     X999 = 0;  54                 }else{            //否則繼續進位,本位置0
 55                     whole[15+ 5-dNum]  = '0';  56  }  57  }  58             
 59             if ( dNum==4){  60                 if (whole[15+ 5-dNum] >= '5')  61                     X999 = 1;  62                 whole[15+ 5-dNum] = 0x00;  63  }  64             //////////////////////////
 65     
 66  }  67         case 4:{  68             cdat[3] = (char)  (((long) (dec *10000l))%10);        //0.00001位
 69             whole[15+ 4-dNum] = cdat[3] + 0x30;  70             //四舍五入算法
 71             if (X999 == 1){  72                 if (whole[15+ 4-dNum] < 0x39){        //小於9就加1
 73                     whole[15+ 4-dNum] += 1;  74                     X999 = 0;  75                 }else{            //否則繼續進位,本位置0
 76                     whole[15+ 4-dNum]  = '0';  77  }  78  }  79             
 80             if ( dNum==3){  81                 if (whole[15+ 4-dNum] >= '5')  82                     X999 = 1;  83                 whole[15+ 4-dNum] = 0x00;  84  }  85             //////////////////////////
 86 
 87  }  88         case 3: {  89             cdat[2] = (char)  (((long) (dec *1000l))%10);            //0.001位
 90             whole[15+ 3-dNum] = cdat[2] + 0x30;  91             //四舍五入算法
 92             if (X999 == 1){  93                 if (whole[15+ 3-dNum] < 0x39){        //小於9就加1
 94                     whole[15+ 3-dNum] += 1;  95                     X999 = 0;  96                 }else{            //否則繼續進位,本位置0
 97                     whole[15+ 3-dNum]  = '0';  98  }  99  } 100             if ( dNum==2){ 101                 if (whole[15+ 3-dNum] >= '5') 102                     X999 = 1; 103                 whole[15+ 3-dNum] = 0x00; 104  } 105             //////////////////////////
106             
107  } 108         case 2:{ 109             cdat[1] = (char)  (((long) (dec *100l))%10);            //0.01位
110             whole[15+ 2-dNum] = cdat[1] + 0x30; 111             //四舍五入算法
112             if (X999 == 1) { 113                 if (whole[15+ 2-dNum] < 0x39){        //小於9就加1
114                     whole[15+ 2-dNum] += 1; 115                     X999 = 0; 116                 }else{            //否則繼續進位,本位置0
117                     whole[15+ 2-dNum]  = '0'; 118  } 119  } 120             if ( dNum==1){ 121                 if (whole[15+ 2-dNum] >= '5') 122                     X999 = 1; 123                 whole[15+ 2-dNum] = 0x00; 124  } 125             //////////////////////////
126             
127  } 128         case 1:{ 129             cdat[0] = (char)  (((long) (dec *10l))%10);                //0.1位
130             whole[15+ 1-dNum] = cdat[0] + 0x30; 131             //四舍五入算法
132             if (X999 == 1){ 133                 if (whole[15+ 1-dNum] < 0x39) 134                     whole[15+ 1-dNum] += 1; 135                 else{ 136                     XtoZ = 1; 137                     whole[15+ 1-dNum] = '0'; 138  } 139                 X999 = 0; 140  } 141             
142             if ( dNum==0){ 143                 if (whole[15+ 1-dNum] >= '5') 144                     XtoZ = 1; 145                 whole[15+ 1-dNum] = 0x00; 146  } 147             /////////////////////////
148             
149  } 150  } 151     
152 /////////////////////添加小數點//////////////// 
153     whole[15 - dNum] = '.' ; 154     
155 ///////////////////整數部分轉換////////////// 
156     cdat [0] = (char)(ida / 10000 ) ; 157     cdat [1] = (char)((ida % 10000) /1000); 158     cdat [2] = (char)((ida % 1000) /100); 159     cdat [3] = (char)((ida % 100) /10); 160     cdat [4] = (char)((ida % 10) /1); 161     for (i=0;i<5;i++){                        //轉換成ASCII碼
162         cdat[i] = cdat[i] + 48; 163  } 164     
165     //四舍五入算法,整數部分(未完)
166     if (XtoZ == 1){ 167         if (cdat[4] < '9'){                //個位小於9
168             cdat[4] += 1; 169         }else{ 170             cdat[4] = '0'; 171             if (cdat[3] < '9'){            //十位小於9
172                 cdat[3] += 1; 173             }else{ 174                 cdat[3] = '0'; 175                 if (cdat[2] < '9'){        //百位小於9
176                     cdat[2] += 1; 177                 }else{ 178                     cdat[2] = '0'; 179                     if (cdat[1] < '9'){    //千位小於9
180                         cdat[1] += 1; 181                     }else{ 182                         cdat[1] = '0'; 183                         cdat[0] += 1;        //萬位加1
184  } 185  } 186  } 187  } 188         XtoZ = 0; 189  } 190     
191     //////////////////////////////////////////////////// 
192     if (cdat[0] == '0'){ 193         intLen = 4; 194         if (cdat[1] == '0'){ 195             intLen = 3; 196             if (cdat[2] == '0'){ 197                 intLen = 2; 198                 if (cdat[3] == '0') 199                     intLen = 1; 200  } 201  } 202  } 203     
204     for (i=0;i<5;i++){ 205         whole[10 + i - dNum] = cdat[i]; 206  } 207 ///////////////////////拼合符點數/////////////////////////////////    
208     if (negative == 1){ 209         whole [ 14 - intLen - dNum] = '-'; 210         for ( i=(14 - intLen - dNum) ;i<19; i++){ 211             *pString = whole[i]; 212             pString ++; 213  } 214     }else{ 215         for ( i=(15 - intLen - dNum) ;i<19; i++){ 216             *pString = whole[i]; 217             pString ++; 218  } 219  } 220     
221 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM