现在的位置: 首页 > 综合 > 正文

高精度bign

2013年04月19日 ⁄ 综合 ⁄ 共 2657字 ⁄ 字号 评论关闭


第5章  基础题目选解 
第 119 页 
struct bign { 
    int len,s[maxn]; 
    bign() { memset(s, 0, sizeof(s)); len = 1; } }; 
其中,len表示位数,而s数组就是具体的各个数字。 
上面的结构体中有一个函数,称为构造函数(Constructor)。构造函数是C++中特有的,作用是进行初始化。 
说明:(1)C++语言对C语言的struct进行了改造,使其也可以像class那样支持成员函数的定义,从而使struct变成真正的抽象数据类型(ADT,Abstract Data Type)。 
(2)在C++语言中,如果不特别指明,struct的成员的默认访问说明符为public,而class的成员的默认访问说明符为private。实际上就C++语言来讲,struct和class除了“默认的成员访问说明符”这一点外,没有任何区别。 
(3)C++的struct和class差别很小,其实class就是从struct发展出来的。struct定义的结构体在C++中也是一个类,结构体可以有class的任何东西。 
    现在来重新定义赋值运算(注意,下面的函数要写在bign结构体定义的内部,千万不
要写在外面): 
bign operator = (const char* num) {     len = strlen(num); 
    for(int i = 0; i < len; i++) s[i] = num[len-i-1] - '0';     return *this; } 
说明:每个类实例化一个对象后,就会有一个this指针,指向当前实例本身。this 是由编译器自动产生的,在类的成员函数中有效。this 是一个常量,不允许对其赋值。 
可以用x= "1234567898765432123456789"给x赋值,它会也这个字符串转化为“逆序数组+长度”的内部表示法。为了支持x=1234的赋值方式,再定义另外一种赋值运算(定义在结构体内部): 
bign operator = (int num) {     char s[maxn]; 
    sprintf(s, "%d", num);     *this = s;     return *this;   } 
可以用“bign x; x=100;”来声明一个x并给它赋值,却不能写成“bign x=100;”。原因在于,bign x=100是初始化,而非普通的赋值操作。为了让代码支持“初始化”操作,需要增加两个函数(定义在结构体内部): 
bign(int num) { *this = num; } 
bign(const char* num) { *this = num; } 下面需要提供一个函数把它转化为字符串: string str() const {     string res = ""; 
    for(int i = 0; i < len; i++) res = (char)(s[i] + '0') + res;     if(res == "") res = "0";     return res; }  
说明:任何不会修改数据成员(即函数中的变量)的函数都应该声明为const 类型。如果在编写const 成员函数时,不慎修改了数据成员,或者调用了其它非const 成员函数,编译器将指出错误,这无疑会提高程序的健壮性。 

第5章  基础题目选解 
第 120 页 
接下来,重新定义<<和>>运算符,让输入输入出流直接支持bign结构体(这两个孙函数要定义在结构体bign的外边,不在写在里面): 
istream& operator >> (istream &in, bign& x) {   string s;   in >> s; 
  x = s.c_str();   return in; }  
ostream& operator << (ostream &out, const bign& x) {   out << x.str();   return out; } 
5.2.4  重载bign的常用运算符 加法写成函数(定义在结构体内部): 
bign operator + (const bign& b) const{     bign c;     c.len = 0; 
    for(int i = 0, g = 0; g || i < max(len, b.len); i++) {       int x = g; 
      if(i < len) x += s[i];       if(i < b.len) x += b.s[i];       c.s[c.len++] = x % 10;       g = x / 10;     } 
    return c; } 
两个数中只要任何一个数还有数字,加法就要继续,即使两个数都加完了,也不要忘记处理进位。注意,上面的算法并没有假设s数组中“当前没有用到的数字都是0”。如果事先已经清零,就可以把循环体的前3行简化为int x=s[i]+b.s[i]=g。甚至可以直接把循环次数设置max(len,b.len)+1,然后检查最终结果是否有前导零。如果有,则把len减1。为了让使用简单,可以重新定义+=运算符(定义在结构体内部): 
bign operator += (const bign& b) {     *this = *this + b;     return *this; } 
接下来,实现“比较”操作(定义在结构体内部): bool operator < (const bign& b) const{     if(len != b.len) return len < b.len;     for(int i = len-1; i >= 0; i--) 
      if(s[i] != b.s[i]) return s[i] < b.s[i];     return false; } 
一开始就比较两个bign的位数,如果不相等则直接返回,否则比较两个数组的逆序的字典序。注意,这样做的前提是两个数都没有前导零,如果不注意的话,很可能出现“运算结果都没有问题,但一比较就错”的情况。 
用“小于(<)”符号,就可用它来定义其他所有比较运算符: bool operator > (const bign& b) const{     return b < *this; }  

第5章  基础题目选解 
第 121 页 
bool operator <= (const bign& b) {     return !(b > *this); }  
bool operator >= (const bign& b) const{     return !(*this< b ); }  
bool operator != (const bign& b) {    return  b < *this) || *this < b; }   
bool operator == (const bign& b) { 
   return !(b < *this) && !(*this < b); } 
后面如果要用到高精度运算的题目中,将直接使用bign类中的所有运算。

抱歉!评论已关闭.