2012年(32)
分类: C/C++
2012-03-11 15:48:11
git clone git://git.code.sf.net/p/cutility/code cutility-code长整数总共有两个文件一个为big_integer.h,一个为big_integer.c
在看这一篇文章这前你需要了解长整数的数据结构
- add c[0] a[0] b[0] #c[0]=a[0]+b[0]
- adc c[1] a[1] b[1] #c[1]=a[1]+b[1]+carry ,carry为进位标志
(1) a的低15位与b的低15位相加,得到一个16位的数"1101110110001001",如下图:上图两个15位数相加,得到结果是一个16位的数,低15位用于赋值给c.b_val[0],最高位用于表示进位标志,为1,表明产生了进位,要获取该进位,只需要把16位的结果左移15位,用C语言实现为:
- b_unit val=a.b_val[0]+b.b_val[1];
- c.b_val[0]=val&((b_unit)((1<<15)-1));
- carry=val>>15;
(2) a的高位"10" 与 b的高位"11011" 并且连同进位一起相加得,如下图:把结果11110赋值结c.b_val[1]。
- static BGInteger* abs_plus(BGInteger* l,BGInteger* r)
- {
- int l_len=abs(l->b_len);
- int r_len=abs(r->b_len);
- /*保证绝对值大的数在左边*/
- if(l_len<r_len)
- {
- BGInteger* tempb=l;
- l=r;
- r=tempb;
- int tempi=l_len;
- l_len=r_len;
- r_len=tempi;
- }
- b_unit* l_val=l->b_val;
- b_unit* r_val=r->b_val;
- /*两个k位的数相加,结果不可能大于k+1位,所以只需要为结果分配l_len+1的空间即足够*/
- BGInteger* ret=bg_malloc(l_len+1);
- b_unit* t_val=ret->b_val;
- b_unit carry=0; /*进位标志*/
- int i;
- for(i=0;i<r_len;i++)
- {
- carry=l_val[i]+r_val[i]+carry; /*带进位的加法*/
- t_val[i]=carry&MASK; /*把低15位赋值组t_val[i]*/
- carry>>=SHIFT; /*获取进位*/
- }
- for(;i<l_len;i++)
- {
- carry=l_val[i]+carry;
- t_val[i]=carry&MASK;
- carry>>=SHIFT;
- }
- t_val[i]=carry;
- bg_format_len(ret); /*两个k位数相加可能为k+1位,当然也可能为k位,确定最终结果的位数*/
- return ret;
- }
- static BGInteger* abs_minus(BGInteger* l,BGInteger* r)
- {
- int l_len=abs(l->b_len);
- int r_len=abs(r->b_len);
- int sign=1;
- /*保证绝对值大的数在左边*/
- if(l_len<r_len)
- {
- BGInteger* tempb=l;
- l=r;
- r=tempb;
- int tempi=l_len;
- l_len=r_len;
- r_len=tempi;
- sign=-1;
- }
- else if(l_len==r_len)
- {
- /*两个数的位数相同,所以需要进一步判断两数大小*/
- while(l_len&&(l->b_val[l_len-1]==r->b_val[l_len-1])) l_len--;
- if(l_len==0)
- {
- return bg_create_zero(); /*两数相等,返加0*/
- }
- r_len=l_len; /*高位相等,所以只需要对不同的位求差即可*/
- if(l->b_val[l_len-1]<r->b_val[r_len-1]) /*保证绝对值大的数在左边*/
- {
- BGInteger* tempb=l;
- l=r;
- r=tempb;
- sign=-1;
- }
- }
- b_unit* l_val=l->b_val;
- b_unit* r_val=r->b_val;
- /*k位减n位的数,并且k>n,则差不会大于k位,所以分配l_len长度即足够*/
- BGInteger* ret=bg_malloc(l_len);
- b_unit* t_val=ret->b_val;
- int i;
- b_unit borrow=0; /*借位标志,初始值为0*/
- for(i=0;i<r_len;i++)
- {
- borrow=l_val[i]-r_val[i]-borrow;
- t_val[i]=borrow&MASK; /*低15位赋值给t_val[i]*/
- borrow=(borrow>>SHIFT)&1; /*获取进位标志*/
- }
- for(;i<l_len;i++)
- {
- borrow=l_val[i]-borrow;
- t_val[i]=borrow&MASK;
- borrow=(borrow>>SHIFT)&1;
- }
- if(sign==-1)
- {
- self_negative(ret); /*如果是小数减大数,结果应该为负*/
- }
- bg_format_len(ret);
- return ret;
- }
- BGInteger* bg_plus(BGInteger* l,BGInteger* r)
- {
- BGInteger* ret=0;
- if(l->b_len<0)
- {
- if(r->b_len<0)
- {
- /* l<0, r<0
- * ret=-(abs(l)+abs(r))
- */
- ret=abs_plus(l,r);
- self_negative(ret);
- }
- else
- {
- /*l<0,r>=0
- * ret=-(abs(r)-abs(r))
- */
- ret=abs_minus(l,r);
- self_negative(ret);
- }
- }
- else
- {
- if(r->b_len<0)
- {
- /* l>=0,r<0
- * ret=abs(l)-abs(r)
- */
- ret=abs_minus(l,r);
- }
- else
- {
- /* l>=0,r>=0
- * ret=abs(l)+abs(r)
- */
- ret=abs_plus(l,r);
- }
- }
- return ret;
- }
- BGInteger* bg_minus(BGInteger* l,BGInteger* r)
- {
- BGInteger* ret=0;
- if(l->b_len<0)
- {
- if(r->b_len<0)
- {
- /* l<0 ,r<0
- * l-r=-abs(l)-(-abs(r))=-(abs(l)-abs(r));
- */
- ret=abs_minus(l,r);
- self_negative(ret);
- }
- else
- {
- /* l<0,r>=0
- * l-r=-abs(l)-abs(r)=-(abs(l)+abs(r));
- */
- ret=abs_plus(l,r);
- self_negative(ret);
- }
- }
- else
- {
- if(r->b_len<0)
- {
- /* l>=0 ,r <0
- * l-r=abs(l)-(-abs(r))=abs(l)+abs(r);
- */
- ret=abs_plus(l,r);
- }
- else
- {
- /* l>=0, r>=0
- * l-r=abs(l)-abs(r)
- */
- ret=abs_minus(l,r);
- }
- }
- return ret;
- }