大数四则运算——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/

 

posted @ 2016-04-11 07:16  倪明  阅读(9797)  评论(0编辑  收藏  举报