大數四則運算——C++實現


大數處理——c++實現

  本課題來自我的c++編程作業,文章利用大數處理類,類名:hugeNumber來對大數(編譯器自定義的數值類型無法處理的數)進行四則運算(大數加法、大數減法及大數乘法的運算,除暫時沒實現)和按精度四舍五入,自定義科學計數法等。內容廣泛涉及運算符重載、字符連接、字符加減和字符乘除等作者原創函數。重要提示:本文涉及的所有函數使用的進制皆為10進制。(備注:已將該博客搬遷至CSDN)

一、解題思路

1 核心思想

文章用hugeNumber類對大數進行操作。前提假設,處理的數都使用科學計數法(未用科學計數法表示的大數,指數默認為0),hugeNumber類數據成員如下:

class hugeNumber{                  //定義大數,10進制

private:

       /*char deciNum[MAXSIZE];  */          

       char *deciNum;                 //尾數

       long  exponent;               //指數

       short  sign;                       //符號位,取-1或1

       int  set_dot;                     //小數點位置,-1表示沒有小數點

我將科學計數法分解為各個組成部分如圖 1所示,其中:

①deciNum,科學計數法中的尾數,我用最大512字節表示該數;

②exponent,科學計數法中的指數,我用long int 表示;

③sign,整個數據的正負號;

④set_dot,當前尾數小數點真實位置,從0開始計數。

 

圖 1

當從cin輸入流獲得一串字符,首先判斷其是否為數值

       if(!isNumber(nptr))

       {

              cout<<"This is not a number! " ;

              exit(EXIT_FAILURE);                         //非正常退出

     }

確定為數值后,hugeNumber類接受該字符串,並將其轉換成如上所示4個屬性,其構造函數原型為:

hugeNumber::hugeNumber(const char *nptr);

也可按提示,分別錄入尾數部分、指數部分和正負號。其函數實現:

istream& operator>>(istream &in,hugeNumber &obj) //該函數聲明為hugeNumber類友員函數

{

       char ch;

       in>>ch;

       if(ch = '-')obj.sign = -1;

       else obj.sign = 1;

       in>>obj.deciNum;

       in>>obj.exponent;

       return in;

}

當我們獲得某一hugeNumber類對象的各個屬性值,便可以對該對象進行操作了。

 

2 大數按精度四舍五入

函數原型及方法如下:

void my_round(hugeNumber &hu ,int prec)  //precision,規定的精度位

首先,對hugeNumber類的對象hu按指定自定義規格化。

norm(hu, -hu. exponent - prec);

該語句表示,將hu對象按指定精度規格化,並保持數值大小不變。例如,hu為3.14159e2,現在要求精確度為2,那么先將hu規格化為31415.9e-2。

接下來,判斷小數點后一位是否大於0.5,如果大於0.5,給尾數個位加1,否則不加1,並且將小數點位的 ’.’ 修改為字符串結束符 ‘\0’,因為尾數使用字符串表示,所以規格化后的小數全部被截斷。如圖2所示

 

圖2

2 大數加法運算

函數原型及基本算法思想描述:

2.1 兩個整數大數相加

字符串a與字符串b整數字符串相加,加法考慮到進位,因為較大字符串a的2倍也只能產生1個進位,所有只預留1個進位給最終結果字符串c。

加法算法過程:

首先,判斷a、b皆為整數,當hugeNumber類對象的數據成員set_dot為-1,表示該大數為整數;a、b對介后相加;c的指數為a、b對介后的指數。

其次,strlen(a)、strlen(b)獲得a、b字符串長度,並確定保存結果的字符串長度,c字符串長度為a、b最長的長度加1(假設a是較長的大數)clength = strlen(a) + 1;

最后,從a、b字符串尾部開始從后往前相加,相當於從數的個位開始相加,如有進位,設置int變量 flag表述進位,flag最大為1,你知道為什么不能為2嗎?待短字符串相加結束,將a(假設a是較長的大數)剩余的部位復制到c中,但仍然考慮與b累加的進位,如果a余下的是9999,切好又有進位,那么就要一直進位到數的最高位。如圖 3所示。

 

 

圖 3

2.2整數大數與帶小數大數相加

整數大數與帶小數大數相加,又分為兩種情況:整數大數的整數部分大於帶小數大數的整數部分和整數大數的整數部分小於帶小數大數的整數部分。無論如何,a、b對介后才能相加;c的指數為a、b對介后的指數。所有這里尾數出現的整數和小數都是相當而已的,你完全可以把a、b都規格化成大整數,再相加。分別見圖4 、圖 5 。

 

圖 4 整數大數的整數部分大於帶小數大數的整數部分

 

 

圖 5整數大數的整數部分小於帶小數大數的整數部分

由圖 4 所知,c字符串(保存最終結果)小數部分為b字符串小數部分,直接復制,b小數點前半段(b字符串整數部分)與整數大數a字符串相加同圖 3 所示。

c的整個長度 = a 的整個長度 + b的小數長度 + 1 ;

5表示整數大數b的整數部分小於帶小數大數a的整數部分,c的整個長度 = a 的整個長度 + 1 ;a的小數點后半段直接復制到c字符串中,a整數部分與整數大數b相加算法同圖 3 所示。

2.3 兩個帶小數的大數相加

兩個帶小數的大數相加,分兩張情況討論:一種是a的整數部分大於b的整數部分,但a的小數部分短於b的小數部分,如圖 6 所示。另一種情況,a無論是整數部分還是小數部分,都長於等於b,如圖 7 所示。無論如何,a、b對介后才能相加;c的指數為a、b對介后的指數。所有這里尾數出現的整數和小數都是相當而已的,你完全可以把a、b都規格化成大整數,再相加。

 

圖 6 字符串a的整數部分大於b的整數部分,但a的小數部分短於b的小數部分

 

圖 6-1 補0處理,a、b字符可以從個位向高位依次相加

 

 

圖 7 a無論是整數部分還是小數部分,都長於等於b

 

圖 7-1 補0處理小數,a、b字符可以從個位向高位依次相加

 

3 大數減法運算

前提:無論如何,a、b對介后才能相減;c的指數為a、b對介后的指數。

3.1 兩個整數大數相減

減法雖然沒有溢出,但是會有正負,我用sign返回兩個大數相減后的正負。因此,在做減法運算時,先判斷結果的正負,在用較大的數減去較小的數。假設c = a – b;a > b,sign為正;當a < b,sign為負,如圖 8 所示。

 

圖 8兩個整數大數相減

3.2 一個整數大數與另一個帶小數大數間相減

減法雖然沒有溢出,但是會有正負,同樣用sign返回兩個大數相減后的正負。此處有兩種情形:一種是整數大數大於帶小數的大數,另一種情形是整數大數小於帶小數的大數。假設a是整數大數,b是帶小數的大數。

 

9 整數大數大於帶小數的大數

 

 

圖 9-1 整數大數大於帶小數的大數處理

第一種情形整數大數大於帶小數的大數,先將整數大數a整數減 1,其小數 設為0.999+0.001;分別將0.999與b的小數相減,整數-1后與b的整數相減。見圖9-1。

 

圖 10整數大數小於帶小數的大數

 

圖 10-1 整數大數小於帶小數的大數處理后相減

第二種情形整數大數小於帶小數的大數,sign取-1,c = a – b變換為 c = -(b - a);

b 小數位直接復制給c,整數部分按照兩個整數大數相減處理。

3.3 帶小數大數間相減

有下列四種情形:

 

圖 11 a的整數大於b,a的小數短於b

 

圖 12 a的整數、小數都短於b

 

圖 13 a的整數、小數都長於b

 

圖 14 a的整數小於b,a的小數長於b

 

3 大數乘法運算

首先將a、b規格化為尾數為整數的大數,c的指數等於a、b規格化后的指數相加。有效位數長的做被乘數,位短的做乘數。假設a的長度大於b;

 

 

 圖 15

整個乘法過程,仿真實數據相乘,將所有中間結果累加到c中,如 c = tmp1 + tmp2 + tmp3 + … ;得到最終結果,由於博主比較懶,具體看算法實現。見圖 15所示。

 

二、具體算法實現

  1 #include <iostream>
  2 #include <string>
  3 #include <float.h>
  4 
  5 #include "strSub.h"
  6 #include "strMul.h"
  7 #include "strAdd.h"
  8 
  9 #define isdigit(c)    ('0' <= (c) && (c) <= '9')
 10 using namespace std;
 11 const int MAXSIZE = 512;
 12 
 13 class hugeNumber{            //定義大數,10進制
 14 private:
 15     /*char deciNum[MAXSIZE];    */        //尾數
 16     char *deciNum;
 17     long  exponent;            //指數
 18     short sign;                //符號位,取-1或1
 19     int set_dot;            //小數點位置,-1表示沒有小數點
 20 public:
 21     hugeNumber()
 22     {
 23         this->deciNum = new char [MAXSIZE];        //開辟尾數空間
 24         if(!this->deciNum )
 25         {
 26             cout<<"allocation failure!"<<endl;
 27             exit(EXIT_FAILURE);
 28         }
 29     }
 30     hugeNumber(char deciNum[], long  exponent, int set_dot = -1);
 31     hugeNumber(const char *nptr);
 32     hugeNumber(hugeNumber &b);      //拷貝構造函數
 33     ~hugeNumber(){delete deciNum;}
 34     int getsign(){return sign;}
 35     int getdot(){return set_dot;}
 36     char *getdeciNum(){return deciNum;}
 37     long getexponent(){return exponent;}
 38     hugeNumber operator +(hugeNumber &b);
 39     hugeNumber operator +(char str[]);  
 40     hugeNumber operator -(hugeNumber &b);
 41     hugeNumber operator -(char str[]); 
 42     hugeNumber operator *(hugeNumber &b);
 43     hugeNumber operator *(char str[]);  
 44     hugeNumber operator /(hugeNumber &b);
 45     hugeNumber operator /(char str[]);  
 46     friend ostream& operator<<(ostream &out,hugeNumber &b);
 47     friend istream& operator>>(istream &in,hugeNumber &b);
 48     friend void norm(hugeNumber &hu);                //按科學計數規格化,如12.34e5,規格化后1.234e6
 49     friend void norm(hugeNumber &hu,  long exp );    //按exp介規格化
 50     friend void my_round(hugeNumber &hu ,int prec);    //按精度四舍五入
 51     
 52 
 53 };
 54 
 55 extern char * strAdd(char *c , const char *a, const char *b);//數值型字符串相加
 56 extern void integerAdd(char *c,const char *a,const char *b,int k,int i,int j,int flag);//整數字符串數組相加
 57 int isNumber(const char *nptr);//判斷字符串是否符號數據特征
 58 void expandArray(char a[], int n);//n表示數組頭插入的元素個數
 59 void jumpZero(char * nptr);//跳過尾數前面的無用的0,除了小數點前的
 60 int findDot(const char *nptr);//返回小數點位
 61 
 62 void expandArray(char a[], int n)//n表示數組頭插入的元素個數
 63 {
 64     char *tmp = new char[MAXSIZE];
 65     if(!tmp)
 66     {
 67         cout<<"allocation failure!"<<endl;
 68         exit(EXIT_FAILURE);
 69     }
 70     int j = 0;
 71     for(; a[j] != '\0'; j++)
 72         tmp[j+n] = a[j];
 73     tmp[j+1] = '\0';
 74 //    tmp[0] = '1';
 75     for(j = 0; tmp[j] != '\0'; j++)
 76         a[j] = tmp[j];
 77     delete tmp;
 78 }
 79 
 80 //跳過尾數前面的無用的0,除小數點前的0,【ps】數值小數點后尾部無效0暫時無法剔除
 81 void jumpZero(char * nptr)
 82 {
 83     char *tmp = new char[MAXSIZE];
 84     if(!tmp)
 85     {
 86         cout<<"allocation failure!"<<endl;
 87         exit(EXIT_FAILURE);
 88     }
 89     char *s = nptr;
 90     while (*s == '0') 
 91         ++s;
 92     int got_digit = 0;    //得到1-9數字
 93     int i = 0;
 94     for(; *s != '\0' &&  *s - '0' < 10 && *s - '0' >= 0;)//從第一個不是0的數開始記錄
 95     {
 96         tmp[i++] = *s++; 
 97         got_digit = 1;
 98     }
 99     if (*s == '.')
100     {
101         if (!got_digit)  //  if (!i)  尾數的整數部分全是0或沒有
102         {
103             tmp[0] = '0';
104             i = 1;
105         }
106         tmp[i] = '.'; 
107         s++;
108         i++;
109         
110         while ( *s != '\0' &&  *s - '0' < 10 && *s - '0' >= 0)//提取尾數的小數
111         {
112             tmp[i++] = *s++; 
113         }
114     }
115     tmp[i] = '\0';            //標記尾數結束
116     i = 0;                    //回頭
117     while(tmp[i] != '\0')    //復制字符數組
118         nptr[i++] = tmp[i];
119     nptr[i] = '\0';            //標記結束位
120     delete []tmp;
121 }
122 
123 //返回小數點真實數組下標的位置
124 int findDot(const char *nptr)
125 {
126     const char *s = nptr;
127     int count = -1;
128     while(*s != '\0')
129     {
130         count++;
131         if(*s== '.')
132             return count;
133         s++;
134     }
135     return -1;//標識未找到小數點
136 }
137 
138 ////返回一個對應的小寫字母
139 char TOLOWER(const char *s)            //傳入字符指針,地址
140 {
141     char tmp;
142     if(*s >= 'A' && *s <= 'Z')
143         tmp = *s + 'a' - 'A';
144     else if(*s >= 'a' && *s <= 'z')
145         ;
146     else
147         errno = EINVAL;   //#define  EINVAL  22  無效值異常
148     return tmp;
149 }
150 
151 //判斷是否是實數,此處僅僅處理10進制
152 int isNumber(const char *nptr)
153 {
154     const char *s = nptr;
155 
156     if (nptr == NULL) //判斷字符串是否為空
157     {
158         
159          goto noNumber; 
160     }
161     s = nptr;
162      while (*s == 32) //跳過前面的空格,正確
163         ++s;
164     if (*s == '-' || *s == '+')  //碰到正負號,取下一個字符元素
165         ++s;
166 
167     int flag = 1;        //遇到非數值字符標記
168     int got_dot = 0;  //獲得圓點個數
169     int got_digit = 0;//0-9數字
170 
171     for(; (*s != '\0') ;++s)
172     {
173         //if( (*s - '0'< 10) && (*s - '0'>= 0))    //是否是字符型數字
174         if(isdigit(*s))
175             got_digit = 1 ;
176         else if (!got_dot && *s == '.')            //沒有遍歷到小數點,又剛好碰到小數點時,設置函數狀態
177              got_dot = 1;
178         else
179             break;                //這個字符不是數值型的字符,可能碰見e
180         
181     }
182     
183     if (!got_digit )                    //沒有收集到數字
184          goto noNumber;                                        
185     if( *s != '\0' && *s != 'e' && *s != 'E')//判斷異常字符
186         goto noNumber;    
187     if( *s == 'e'||*s == 'E')//沒有遍歷到E,又剛好碰到E時,設置函數狀態
188     {
189         s++;
190         if (*s == '-' || *s == '+')  //碰到正負號,取下一個字符元素
191         ++s;
192         for(;*s != '\0';++s)           //指數是否合法
193         {
194             //if( (*s - '0'< 10) && (*s - '0'>= 0))    //是否是字符型數字
195             if(isdigit(*s))
196                 ;
197             else
198                 goto noNumber;    
199         }
200 
201     }
202     return 1;
203 noNumber:
204      errno = EINVAL;   //#define  EINVAL  22
205      return 0;
206 }
207 
208 //按科學計數規格化,如12.34e5,規格化后1.234e6
209 void norm(hugeNumber &hu) //大染缸
210 {
211     int i = findDot(hu.deciNum);    //小數點位置
212     int k = 0;                        //標記首個非0數字位置,
213 
214     char *s = hu.deciNum;
215     for(; *s - '0'== 0 || *s == '.';)    // 跳過首字符0或小數點,直到掃描到第一個非0
216     {
217             ++s;++k;
218     }
219     //k++;//首個即非0也不是小數點,***k不能再加***
220     if(i == -1)//尾數為整數
221     {
222         i++;
223         while(hu.deciNum[i])i++;//記錄尾數長度
224         hu.deciNum[i] = '.';
225         hu.deciNum[i+1] = '\0';
226         while(i > 1)
227         {
228             hu.deciNum[i] = hu.deciNum[i-1];
229             hu.deciNum[i-1] = '.';            //小數點前一位向右移一位
230             i--;
231             hu.exponent++;
232         }
233 
234     }
235     else if (i-1 > k)
236     {
237         while(i-1 > k  && i > 1)//小數點在首個非0數字后
238         {
239             hu.deciNum[i] = hu.deciNum[i-1];
240             hu.deciNum[i-1] = '.';            //小數點前一位向右移一位
241             i--;
242             hu.exponent++;
243         }
244     }
245     else if(i < k)
246     {
247         
248         while(i < k  )//小數點在首個非0數字前
249         {
250             hu.deciNum[i] = hu.deciNum[i+1];//小數點與后一個數據交換位置
251             hu.deciNum[++i] = '.';
252             hu.exponent--;
253         }
254         
255     }
256     else
257         ;
258     jumpZero(hu.deciNum);
259     //==========================================
260     //剔除末尾是小數點
261     //==========================================
262     int j = 0;
263     while(hu.deciNum[j]!= '\0')  //有效字符長度
264         j++;
265     if(hu.deciNum[j-1] == '.' ) //最后一位是小數點
266     {
267         hu.deciNum[--j] = '\0';
268         hu.set_dot = -1;      //沒有小數點啦!
269     }
270     else
271         hu.set_dot = findDot(hu.deciNum);//找到小數點位置
272 }
273 
274 //按exp介規格化
275 void  norm(hugeNumber &hu, long exp ) //按exp介規格化
276 {
277     int i = hu.getdot(); //小數點位置
278     if(exp == hu.exponent)return;
279     else if(exp > hu.exponent)//小數點左移
280     {
281         while(exp > hu.exponent)//小數點左移
282         {
283             hu.exponent++;
284             if(i == -1)//沒有小數點
285             {
286                 int j = 0;
287                 while(hu.deciNum[j]!= '\0')  //有效字符長度
288                     j++;
289                 hu.deciNum[j] = '.';
290                 i=j;//記錄小數點位置
291                 hu.deciNum[++j] = '\0';
292             }
293             if(i == 1) //例如1.234時
294             {
295                 //char *tmp = new char [512];
296                 //int j = 0;
297                 //for(; hu.deciNum[j] != '\0'; j++)
298                 //    tmp[j+1] = hu.deciNum[j];
299                 //tmp[j+1] = '\0';
300                 //tmp[0] = '0';
301                 //for(j = 0; tmp[j] != '\0'; j++)
302                 //    hu.deciNum[j] = tmp[j];
303                 //delete tmp;
304                 expandArray(hu.deciNum,1);//數組頭插入1個元素0
305                 hu.deciNum[0] = '0';
306                 i++;//復制的小數點向右移動一位
307             }
308             hu.deciNum[i] = hu.deciNum[i-1];
309             hu.deciNum[--i] = '.';            //小數點前一位向右移一位
310             
311         }
312     }
313     else          //當exp < hu.exponent 時,小數點右移
314     {
315         if(i == -1)//沒有小數點
316         {
317             int j = 0;
318             while(hu.deciNum[j]!= '\0')  //有效字符長度
319                 j++;
320             while(exp < hu.exponent)  //尾數*10,即尾數添加0
321             {
322                 hu.deciNum[j++] = '0';
323                 hu.exponent--;
324             }
325             hu.deciNum[j] = '\0';
326         }
327         else
328         {
329 
330             while(exp < hu.exponent)  //有小數點,尾數*10,小數點右移
331             {
332                 
333                 hu.exponent--;
334             
335                 if(hu.deciNum[i+1] == '\0') //一次右移
336                 {
337                     hu.deciNum[i+1] = '0';
338                     hu.deciNum[i+2] = '\0';
339                     
340                 }
341                 hu.deciNum[i] = hu.deciNum[i+1];
342                 hu.deciNum[++i] = '.';
343             }
344             jumpZero(hu.deciNum);
345         }
346         
347     }
348     //==========================================
349     //剔除末尾是小數點
350     //==========================================
351     int j = 0;
352     while(hu.deciNum[j]!= '\0')  //有效字符長度
353         j++;
354     if(hu.deciNum[j-1] == '.' ) //最后一位是小數點
355     {
356         hu.deciNum[--j] = '\0';
357         hu.set_dot = -1;      //沒有小數點啦!
358     }
359     else
360         hu.set_dot =  findDot(hu.deciNum);//找到小數點位置
361 }
362 
363 //對大數按規定精度,四舍五入
364 void my_round(hugeNumber &hu ,int prec)  //precision,規定的精度位(不能再是大數)
365 {
366     int i = -1;                            //標記小數位,默認-1表示沒有小數點
367     int k = 0;        //標記首個非0數字位置,
368     norm(hu ,0);    //按精度規整大數,數值大小不變
369     //cout<<"niming   "<<hu<<endl;//正確
370     norm(hu , -prec);
371     //cout<<"niming   "<<hu<<endl;//正確
372 
373     char *s = hu.deciNum;
374     for(; *s - '0'== 0 || *s == '.';)    // 跳過首字符0,掃描到第一個非0
375     {
376         ++s;++k;    
377     }
378     i = findDot(hu.deciNum);            //找到小數點位置
379     if(i == -1)            //沒有小數點
380     {
381         norm(hu);        //大數規格化
382         return;            //不需要處理,精度達不到
383     }
384     if(i < k )            // 首個出現的非0字符在小數點位后
385     {
386         errno = ERANGE;            //數據下溢
387         hu.deciNum[0] = '0';
388         hu.deciNum[1] = '\0';    //設置結束標識
389         hu.exponent = 0;
390         hu.set_dot = -1;
391         return;
392     }
393     else         // 首個出現的非0字符在小數點位前
394     {
395         
396         if(hu.deciNum[i+1] - '0' < 5)  
397         {
398             hu.deciNum[i] = '\0';//小數點變結束位
399             hu.deciNum[i+1] = '\0';
400         }
401         else   //考慮進位
402         {
403             int j = i-1;            //小數點的前一位(最后一個保留位)
404             hu.deciNum[i] = '\0';    //小數點變結束位
405             hu.deciNum[i+1] = '\0';
406             int flag = 1;            //進位標識
407             //if(hu.deciNum[j] > '9')
408             //    flag = 1;
409             //    hu.deciNum[j] %= 10;
410             //    j--;
411             //    while(flag)
412             //    {
413             //        if(hu.deciNum[j] > '9')
414             //        flag = 1;
415             //        hu.deciNum[j] %= 10;
416             //        j--;
417             //    }
418             
419                 do{
420                     hu.deciNum[j] += flag;
421                     if(hu.deciNum[j] <= '9')
422                     {
423                         flag = 0;
424                     }
425                     else
426                     {
427                         hu.deciNum[j] -= 10;
428                         flag = 1;
429                         j--;
430                     }
431                 }while(flag && j >= 0);
432 
433                 if(flag && j < 0)  //數據溢出最高位
434                 {
435                     //char *tmp = new char [512];
436                     //int j = 0;
437                     //for(; hu.deciNum[j] != '\0'; j++)
438                     //    tmp[j+1] = hu.deciNum[j];
439                     //tmp[j+1] = '\0';
440                     //tmp[0] = '1';
441                     //for(j = 0; tmp[j] != '\0'; j++)
442                     //    hu.deciNum[j] = tmp[j];
443                     //delete tmp;
444                     expandArray(hu.deciNum, 1);//數組頭插入1個元素
445                     hu.deciNum[0] = '1';
446                 }
447             
448         }
449         //norm(hu);//大數規格化
450     }
451     
452 }
453 
454 hugeNumber::hugeNumber(hugeNumber &b)      //拷貝構造函數
455 {
456         
457     this->deciNum = new char [MAXSIZE];        //開辟尾數空間
458     if(!this->deciNum )
459     {
460         cout<<"allocation failure!"<<endl;
461         exit(EXIT_FAILURE);
462     }
463     strcpy(this->deciNum, b.deciNum);
464     this->exponent = b.exponent;
465     this->sign = b.sign;
466     this->set_dot = b.set_dot;
467     //cout<<"你調用了復制構造函數"<<endl;
468 }
469 hugeNumber::hugeNumber(char deciNum[], long  exponent,int set_dot)
470 {
471     if(!isNumber(deciNum))
472     {
473         cout<<"This is not a number! " ;
474         exit(EXIT_FAILURE);                //非正常退出
475     }
476     this->deciNum = new char [MAXSIZE];        //開辟尾數空間
477     if(!this->deciNum )
478     {
479         cout<<"allocation failure!"<<endl;
480         exit(EXIT_FAILURE);
481     }
482 
483     const char *s = deciNum;
484     s = deciNum;
485     while (*s == 32) //跳過前面的空格,正確
486         ++s;
487     this->sign = *s == '-' ? -1 : 1;    //保存正負號
488     if (*s == '-' || *s == '+')            //碰到正負號,取下一個字符元素
489         ++s;
490     int i = 0;
491     for(; *s != '\0' && *s - '0' < 10 ; i++)//遇到第一個不是數字的字符,停止
492         *++s;
493     if (*s == '.')
494     {
495         int set_dot = i;
496     }
497     strcpy(this->deciNum , deciNum);
498     this->exponent = exponent;
499 
500 }
501 //==========================
502 //核心構造函數
503 //==========================
504 hugeNumber::hugeNumber(const char *nptr)
505 {
506     
507     if(!isNumber(nptr))
508     {
509         cout<<"This is not a number! " ;
510         exit(EXIT_FAILURE);                //非正常退出
511     }
512     this->deciNum = new char [MAXSIZE];        //開辟尾數空間
513     if(!this->deciNum )
514     {
515         cout<<"allocation failure!"<<endl;
516         exit(EXIT_FAILURE);
517     }
518     const char *s = nptr;
519         
520     s = nptr;
521     while (*s == 32) //跳過前面的空格,正確
522         ++s;
523     sign = *s == '-' ? -1 : 1;   //保存正負號
524     if (*s == '-' || *s == '+')  //碰到正負號,取下一個字符元素
525         ++s;
526     while (*s == '0') //跳過前面的無用的0,除了小數點前的
527         ++s;
528     exponent = 0;        //指數,默認指數為0
529     set_dot = -1;        //獲得圓點位置
530     int got_digit = 0;    //得到0-9數字
531     int i = 0;
532 
533     //while(*s - '0' < 10 && *s != '\0') //提取尾數的整數
534     //{
535     //    deciNum = deciNum*10 + (*s++ - '0');
536     //}
537     //deciNum *= sign ;
538     for(; *s != '\0' && *s - '0' < 10 && *s - '0' >= 0; )//提取尾數的整數部分 for(; *s != '\0' && isdigit(*s) ; i++) ; for(; *s != '\0' && *s - '0' < 10 && *s != '.'; i++)
539     {
540         deciNum[i++] = *s++; 
541         got_digit = 1;
542     }
543 
544     //提取尾數的小數部分
545     if (*s == '.')
546     {
547         if (!got_digit)  //  if (!i)  尾數整數部分全是0或沒有
548         {
549             deciNum[0] = '0';
550             set_dot = 1;    //小數點在第二位
551             i = 1;
552         }
553         else
554         {
555             set_dot = i;        //小數點在i位
556         }
557         deciNum[set_dot] = '.'; 
558         s++;
559         i++;
560         
561         while ( *s != '\0' && *s - '0' < 10 && *s - '0' >= 0)//提取尾數的小數    for(; *s != '\0' && *s - '0' < 10 && TOLOWER(*s) != 'e'; i++)
562         {
563             deciNum[i++] = *s++; 
564         }
565     }
566     deciNum[i] = '\0';            //標記尾數結束
567     //提取指數
568     if( *s == 'e'||*s == 'E')//剛好碰到E時,設置函數狀態
569     {
570         s++;
571         int sign2 = 1 ;        //指數可能是負數
572         sign2 = (*s == '-') ? -1 : 1;   //保存正負號
573         if (*s == '-' || *s == '+')  //碰到正負號,取下一個字符元素
574             ++s;
575         while( *s != '\0' ) //提取指數的整數
576         {
577             exponent = exponent*10 + (*s++ - '0');
578         }
579         exponent *= sign2;
580     }
581 
582 }
583 
584 ostream& operator<<(ostream &out,hugeNumber &obj)  //輸出
585 {
586     if(obj.sign < 0)out<<"-";
587     out<<obj.deciNum<<"e"<<obj.exponent<<endl;
588     return out;
589 }
590 
591 istream& operator>>(istream &in,hugeNumber &obj)  //輸入
592 {
593     char ch;
594     in>>ch;
595     if(ch = '-')obj.sign = -1;
596     else obj.sign = 1;
597     in>>obj.deciNum;
598     in>>obj.exponent;
599     return in;
600 }
601 
602 //大數相加運算
603 hugeNumber  hugeNumber::operator +(hugeNumber &b)
604 {
605 
606     if((exponent < b.exponent))    // 對介
607         norm(b,this->exponent);
608     else
609         norm(*this,b.exponent);
610 
611 
612     //cout<<"b符號=    "<<b.getsign()<<endl;
613     //cout<<"尾數=    "<<b.getdeciNum()<<endl;
614     //cout<<"小數點位置=    "<<b.getdot()<<endl;
615     //cout<<"指數=    "<<b.getexponent()<<endl;
616 
617 
618     hugeNumber c; //返回該對象
619     if(this->sign > 0 && b.sign > 0)//判斷正負號
620     {
621         c.sign = 1;
622         strAdd(c.deciNum, this->deciNum, b.deciNum);
623     }
624     else if (this->sign < 0 && b.sign < 0)
625     {
626         c.sign = -1;
627         strAdd(c.deciNum, this->deciNum, b.deciNum);
628     }
629     else if(this->sign > 0 && b.sign < 0)
630     {
631         /*if(this->sign < 0)
632             c = b - *this;
633         if(b.sign < 0)
634             c = *this - b;*/
635         int sgn = 1;
636         strSub(c.deciNum, this->deciNum, b.deciNum, sgn);
637         c.sign = 1;
638     }
639     else
640     {
641         int sgn = 1;
642         strSub(c.deciNum, b.deciNum, this->deciNum, sgn);
643         c.sign = -1;
644     }
645     
646     //cout<<c.getdeciNum()<<endl;
647     c.exponent = this->exponent;
648     c.set_dot = findDot(c.deciNum);
649     
650     return c;
651 }
652 
653 //大數相加運算2
654 hugeNumber hugeNumber::operator +(char str[])
655 {
656     if(!isNumber(str))
657     {
658         cout<<"This is not a number! " ;
659         exit(EXIT_FAILURE);                //非正常退出
660     }
661     hugeNumber b (str);
662     return(*this + b);
663 }
664 //大數相減運算
665 hugeNumber    hugeNumber:: operator -(hugeNumber &b)
666 {
667     if((exponent < b.exponent))    // 對介
668     {
669         norm(b,this->exponent);
670     }
671     else
672         norm(*this,b.exponent);
673 
674     hugeNumber c; //返回該對象
675     if(this->sign > 0 && b.sign > 0)//判斷正負號
676     {
677         int sgn = 1;        
678         strSub(c.deciNum, this->deciNum, b.deciNum,sgn);
679         c.sign =sgn;
680     }
681     else if (this->sign < 0 && b.sign < 0)
682     {
683         int sgn = 1;
684         strSub(c.deciNum, this->deciNum, b.deciNum,sgn);
685         c.sign = -sgn;
686     }
687     else if(this->sign > 0 && b.sign < 0)
688     {
689         strAdd(c.deciNum, this->deciNum, b.deciNum);
690         c.sign = 1;
691     }
692     else
693     {
694         strAdd(c.deciNum, this->deciNum, b.deciNum);
695         c.sign = -1;
696     }
697     
698     //cout<<c.getdeciNum()<<endl;
699     c.exponent = this->exponent;
700     c.set_dot = findDot(c.deciNum);
701     
702     return c;
703 
704 }
705 //大數相減運算2
706 hugeNumber    hugeNumber:: operator -(char str[])
707 {
708     if(!isNumber(str))
709     {
710         cout<<"This is not a number! " ;
711         exit(EXIT_FAILURE);                //非正常退出
712     }
713     hugeNumber b (str);
714     return(*this - b);
715 }
716 
717 //大數相乘運算
718 hugeNumber    hugeNumber:: operator *(hugeNumber &b)
719 {
720     //if((exponent != b.exponent))    // 對介
721     //    norm(b,this->exponent);
722     hugeNumber c; //返回該對象
723     int clen = strlen(this->deciNum)+strlen(b.deciNum)+1;
724     int i = 0;
725     for(; i<clen;i++)
726     {
727         c.deciNum[i] = '0'; 
728     }
729     c.deciNum[i] = '\0';
730     c.exponent = this->exponent + b.exponent;
731     int cexp = 0;
732     if(this->sign > 0 && b.sign > 0)//判斷正負號
733     {            
734         strMul(c.deciNum, this->deciNum, b.deciNum, cexp, clen);
735         c.sign = 1;c.exponent += cexp;
736     }
737     else if (this->sign < 0 && b.sign < 0)
738     {
739         strMul(c.deciNum, this->deciNum, b.deciNum, cexp, clen);
740         c.sign = 1;c.exponent += cexp;
741     }
742     else if(this->sign > 0 && b.sign < 0)
743     {
744         strMul(c.deciNum, this->deciNum, b.deciNum, cexp, clen);
745         c.sign = -1;c.exponent += cexp;
746     }
747     else
748     {
749         strMul(c.deciNum, this->deciNum, b.deciNum, cexp, clen);
750         c.sign = -1;c.exponent += cexp;
751     }
752     
753     //cout<<c.getdeciNum()<<endl;
754     
755     c.set_dot = findDot(c.deciNum);
756     
757     return c;
758 
759 }
760 //大數相乘運算2
761 hugeNumber    hugeNumber:: operator *(char str[])
762 {
763     if(!isNumber(str))
764     {
765         cout<<"This is not a number! " ;
766         exit(EXIT_FAILURE);                //非正常退出
767     }
768     hugeNumber b (str);
769     return((*this) * b);
770 } 
771 
772 ////大數相加運算
773 //hugeNumber hugeNumber::operator +(hugeNumber &b)
774 //{
775 //    if((exponent != b.exponent))                        //以*this對象為基准,規格化對象b
776 //        norm(b,this->exponent);
777 //    hugeNumber c;
778 //    int i = findDot(this->deciNum);//*this對象的尾數小數點位
779 //    int j = findDot(b.deciNum);//b對象的尾數小數點位
780 //    int k = c.set_dot = (i > j) ? i : j;//k取最長的整數位
781 //    int min = (i < j) ? i -1 : j - 1;            //短的整數位
782 //    //尾數整數部分
783 //    c.deciNum[k] = '.';                    //確定小數點
784 //    k--;
785 //    while(k > 0)
786 //    {
787 //        int flag = 0;
788 //        int j = k; 
789 //        
790 //            c.deciNum[k] = this->deciNum[k] + (b.deciNum[k] - '0');  //錯誤
791 //            if(c.deciNum[j] > '9')        //考慮進位
792 //            {
793 //                while(flag && j >= 0)
794 //                {
795 //                    c.deciNum[j] -= 10;
796 //                    flag = 1;
797 //                    j--;
798 //                }
799 //                if(flag && j < 0)  //數據溢出最高位
800 //                {
801 //                    expandArray(c.deciNum, 1);//數組頭插入1個元素
802 //                    c.deciNum[0] = '1';
803 //                }
804 //            }
805 //        k--;
806 //    }
807 //    return c;
808 //}
809 
810 //大數相加運算2
811 //hugeNumber hugeNumber::operator +(char str[])
812 //{
813 //    if(!isNumber(str))
814 //    {
815 //        cout<<"This is not a number! " ;
816 //        exit(EXIT_FAILURE);                //非正常退出
817 //    }
818 //    hugeNumber b (str);
819 //    if((exponent != b.exponent))                        //以*this對象為基准,規格化對象b
820 //        norm(b,this->exponent);
821 //    hugeNumber c(*this);
822 //    int i = findDot(this->deciNum);//*this對象的尾數小數點位
823 //    int j = findDot(b.deciNum);//b對象的尾數小數點位
824 //    int k = c.set_dot = (i > j) ? i : j;//k取最長的整數位
825 //    int min = (i < j) ? i -1 : j - 1;            //短的整數位
826 //    //尾數整數部分
827 //    c.deciNum[k] = '.';                    //確定小數點
828 //    k--;
829 //    while(k > 0)
830 //    {
831 //        int flag = 0;
832 //        int j = k; 
833 //        
834 //            c.deciNum[k] += (b.deciNum[k] - '0');
835 //            if(c.deciNum[j] > '9')        //考慮進位
836 //            {
837 //                while(flag && j >= 0)
838 //                {
839 //                    c.deciNum[j] -= 10;
840 //                    flag = 1;
841 //                    j--;
842 //                }
843 //                if(flag && j < 0)  //數據溢出最高位
844 //                {
845 //                    expandArray(c.deciNum, 1);//數組頭插入1個元素
846 //                    c.deciNum[0] = '1';
847 //                }
848 //            }
849 //        k--;
850 //    }
851 //    return c;
852 //}
853 
854 //ostream& operator<<(ostream &out,hugeNumber &obj)  //輸出  發在此文件提示無法訪問對象.元素
855 //{
856 //    if(obj.sign < 0)out<<"-";
857 //    out<<obj.deciNum<<"e"<<obj.exponent<<endl;
858 //    return out;
859 //}
860 //
861 //istream& operator>>(istream &in,hugeNumber &obj)  //輸入
862 //{
863 //    char ch;
864 //    in>>ch;
865 //    if(ch = '-')obj.sign = -1;
866 //    else obj.sign = 1;
867 //    in>>obj.deciNum;
868 //    in>>obj.exponent;
869 //    return in;
870 //}
871 
872 //void isSPACE(const char *nptr)
873 //{
874 //    const char *s = nptr;
875 //        s = nptr;
876 //     while (*s == 32) //跳過前面的空格
877 //        ++s;
878 //     while(*s != '\0')
879 //         printf("%c",*s++);
880 //
881 //}
882 //void TOLOWER(char &s)         //傳入字符
883 //{
884 //    if(s >= 'A' && s <= 'Z')
885 //        s += 'a' - 'A';
886 //    else if(s >= 'a' && s <= 'z')
887 //        ;
888 //    else
889 //        errno = EINVAL;   //#define  EINVAL  22  無效值異常
890 //}
891 
892 
893 
894     //if(!isNumber(nptr))return ;
895     //if(my_strtod(nptr,NULL) < 1e15)return;
896 //
897 //long double 
898 //strToDouble(const char str[],char ** endptr)
899 //{
900 //    register const char *s;
901 //    short int sign;     //符號位
902 //    
903 //    int got_dot;            //n. 點,小圓點;
904 //    int got_digit;            //n. 數字; 手指,足趾; 一指寬;
905 //    long double decimalNum;    //十進制小數,尾數
906 //    long int exponent;        //指數,階碼
907 //
908 //    if (str == NULL)   //字符串為空,作異常處理
909 //    {
910 //         errno = EINVAL;   //#define  EINVAL  22
911 //         goto noconv; 
912 //    }
913 //    s = str;
914 //    //while (ISSPACE (*s)) //跳過前面的空格
915 //    //    ++s;
916 //    while (*s == 32)++s;
917 //
918 //    //取數據首位符號位
919 //    if (*s == '-' || *s == '+')
920 //        sign = *s++ == '-' ? -1 : 1;
921 //
922 //    decimalNum = 0.0;
923 //    got_dot = 0;  //是否有圓點句號
924 //    got_digit = 0;//是否是0-9數字
925 //    exponent = 0; //指數實際大小
926 //
927 //     //處理e之前的實數
928 //    for (;; ++s)                 
929 //    {
930 //         if( (*s - '0'< 10) && (*s - '0'>= 0))  //是否是字符型數字
931 //        {
932 //             got_digit = 1;
933 //
934 //            if (decimalNum > DBL_MAX * 0.1)  //DBL_MAX為double最大正數
935 //                 ++exponent;
936 //            else
937 //                decimalNum = (decimalNum * 10.0) + (*s - '0'); //累加數值
938 //
939 //            if (got_dot)
940 //                --exponent;
941 //        }
942 //        else if (!got_dot && *s == '.')   //沒有遍歷到小數點,又剛好碰到小數點
943 //             got_dot = 1;
944 //        else
945 //             break;
946 //    }
947 //    if (!got_digit)                    //沒有收集到數字
948 //    goto noconv;                        //報錯處理
949 //
950 //
951 //}

 

三、算法測試

1 測試按精度四舍五入

 1 int main()
 2 {
 3     char str[MAXSIZE];
 4     do{
 5         cout<<"請輸入一個實數(退出請輸入esc):"<<endl;
 6         cin.clear(); //cin.fail()返回0;
 7         cin.sync();  //清空流
 8         cin.getline(str,sizeof(str));
 9         if(strcmp(str,"esc") == 0)exit(0);
10     }while(!isNumber(str) );
11         
12     hugeNumber a(str);
13     int prec = 0;
14     do{
15         cout<<"\n請輸入要保留的有效位數:"<<endl;
16         cin.clear(); //cin.fail()返回0;
17         cin.sync();  //清空流
18         cin.getline(str,sizeof(str));
19         prec = atoi(str);
20     }while(!isNumber(str) && prec >= 0 );
21 
22     my_round(a,prec);
23     cout<<a<<endl;
24     
25     //hugeNumber a("1234567890000000000e-4");
26     //norm(a);
27     //cout<<a<<endl;
28     return 0;
29 }

 

該主函數的實驗結果如圖 16 所示:

圖 16 大數按精度四舍五入

2 測試大數四則運算

//測試大數四則運算
int main()
{
    char str[MAXSIZE];
    do{
        cout<<"請輸入第一個實數(退出請輸入esc):"<<endl;
        cin.clear(); //cin.fail()返回0;
        cin.sync();  //清空流
        cin.getline(str,sizeof(str));
        if(strcmp(str,"esc") == 0)exit(0);
    }while(!isNumber(str) );
        
    hugeNumber a(str);

    do{
        cout<<"請輸入第二個實數(退出請輸入esc):"<<endl;
        cin.clear(); //cin.fail()返回0;
        cin.sync();  //清空流
        cin.getline(str,sizeof(str));
        if(strcmp(str,"esc") == 0)exit(0);
    }while(!isNumber(str) );
        
    hugeNumber b(str);
    hugeNumber c = a + b;//只能初始化調用復制構造函數
    cout<<"輸出結果為:"<<endl;    
    cout<<"a + b = "<<(a + b)<<endl;
    cout<<"a - b = "<<(a - b)<<endl;
    cout<<"a * b = "<<(a * b)<<endl;
}

 

實驗結果如圖 17 所示

圖17 大數四則運算實驗結果

該文為作者原創,版權歸雲南師范大學信息學院所有,引用請注明出處!索取全部源碼,請加 qq: 292729249

若編譯出現下列錯誤:error C4996: 'strcat': This function or variable may be unsafe.

屬兼容問題,請參照:http://heyunhuan513.blog.163.com/blog/static/160204220153894725887/

 


免責聲明!

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



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