Chinaunix首页 | 论坛 | 博客
  • 博客访问: 318018
  • 博文数量: 32
  • 博客积分: 424
  • 博客等级: 准尉
  • 技术积分: 465
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-02 10:23
文章分类

全部博文(32)

文章存档

2012年(32)

分类: C/C++

2012-03-12 15:38:32

代码下载:
git clone git://git.code.sf.net/p/cutility/code cutility-code
长整数总共有两个文件一个为big_integer.h,一个为big_integer.c

在看这一篇文章这前你需要了解长整数的数据结构

(一)简介

BGInteger内部采用二进制的方式来存储数值,移位运算相对来说比其它的运算简单一点。主要的问题是在计算机内部,数据是采用补码的形式存储,而BGInteger采用的编码方式为原码。如果BGInteger为正,原码与补码相等,可以直接对BGInteger中的数值移位;但如果是负数,则需要把原码转换为补码后才能进行移位操作,转换公式如下:
补码=反码+1                                    

(二)补码与原码的转换

原码转换为补码的代码为:

  1. /* translate original code to complement */
  2. static void units_invert_complement(b_unit* d,b_unit* s,int size)
  3. {
  4.     b_unit carry=1;
  5.     int i;
  6.     for(i=0;i<size;i++)  /*补码= ~原码 +1 */
  7.     {
  8.         carry=(~s[i]&MASK)+carry;
  9.         d[i]=carry&MASK;
  10.         carry>>=SHIFT;
  11.     }

  12.     assert(carry==0);
  13. }

补码转换为原码的代码为:

  1. /* translate complement to original */
  2. static void units_invert_origin(b_unit* d,b_unit* s,int size)
  3. {
  4.     b_unit carry=1;
  5.     int i;
  6.     for(i=0;i<size;i++) /*原码=~(补码-1) */
  7.     {
  8.         carry=s[i]-carry;
  9.         d[i]=(~carry)&MASK;
  10.         carry>>=SHIFT;
  11.     }
  12.     assert(carry==0);
  13. }

(三)左移与右移

(1)左移:

BGInteger最多支持对一个数左移2^31位,并且位移量必须为正数。因为负数的左移与右移都是补0,所以在左移负数时,可以直接使用原码。

  1. BGInteger* bg_lshift(BGInteger* l,BGInteger* r)
  2. {
  3.     if(r->b_len<0) /*判断r是否为负,如果是则反加为NULL*/
  4.     {
  5.         WARN("Negative Shift Value");
  6.         return NULL;
  7.     }
  8.     if(r->b_len==0)/*如果位移量为0,直接复制l,并返回*/
  9.     {
  10.         return bg_clone(l);
  11.     }
  12.     int shift_value=bg_to_abs_int(r); /*把r的绝对值转换为整型,如果|r|>2^31,返回值为负1*/

  13.     if(shift_value<0) /*位移量太大,不能处理*/
  14.     {
  15.         WARN("Shift Value Is Too BIG");
  16.         return NULL;
  17.     }
  18.     BGInteger* ret=abs_lshift(l,shift_value); /*绝对值左移,函数如下*/
  19.     if(l->b_len<0)
  20.     {
  21.         self_negative(ret); /*如果l为负,则位移后的结果也为负*/
  22.     }
  23.     return ret;
  24. }

  1. static inline BGInteger* abs_lshift(BGInteger* l,int shift_value)
  2. {

  3.     int l_len=abs(l->b_len); /*l的长度*/
  4.     b_unit* l_val=l->b_val;

  5.     int t_len=l_len+shift_value/SHIFT+1; /*计算位移后的长度*/
  6.     BGInteger* ret=bg_malloc(t_len);   /*分配空间*/
  7.     b_unit carry;
  8.     /*把数组位移,函数如下*/
  9.     carry=units_lshift(ret->b_val+shift_value/SHIFT,l_val,l_len,shift_value%SHIFT);
  10.     ret->b_val[shift_value/SHIFT+l_len]=carry; /*保存移出位*/

  11.     bg_format_len(ret);
  12.     return ret;
  13. }

  1. static b_unit units_lshift(b_unit* d,b_unit* s,int size, int shift_value)
  2. {
  3.     /*把数组s位移shift_value位到数组d*/
  4.     /*shift_value必须小于SHIFT,SHIFT的值为15*/
  5.     assert(size>=0&&shift_value<SHIFT);
  6.     twob_unit t=0;
  7.     int i;
  8.     for(i=0;i<size;i++)
  9.     {
  10.         d[i]=(s[i]<<shift_value|t)&MASK;
  11.         t=(s[i]>>(SHIFT-shift_value))&MASK;
  12.     }
  13.     return t;  /*返回溢出位*/
  14. }

右移:

正数的右移用0补全,负数的右移则是用1补全,所以右移负数时,要涉及到编码的转换。和左移一样,位移量不能大于2^31,并且位移量不能为负

  1. /*@condition r>=0
  2. */
  3. BGInteger* bg_rshift(BGInteger* l,BGInteger* r)
  4. {
  5.     int l_len=l->b_len;
  6.     int r_len=r->b_len;

  7.     if(l_len==0) /*如果l为0,则直接返回0*/
  8.     {
  9.         return bg_create_zero();
  10.     }
  11.     if(r_len==0) /*如果位移量为0,直接复制l,并返回*/
  12.     {
  13.         return bg_clone(l);
  14.     }
  15.     if(r_len<0)  /*位称量不能为负*/
  16.     {
  17.         BUG("Shift With Negative Value");
  18.         return NULL;
  19.     }

  20.     int shift_value=bg_to_abs_int(r); /*把r的绝对值转换为整型,如果r>2^31,则返回为-1*/

  21.     /* bits(r)>31, is to big, so return NULL*/
  22.     if(shift_value<0)
  23.     {
  24.         WARN("RSHIFT Right Is Too Big");
  25.         return NULL;
  26.     }
  27.     BGInteger* ret=i_rshift(l,shift_value); /*该函数如下*/
  28.     return ret;
  29. }

  1. static BGInteger* i_rshift(BGInteger* l,int shift_value)
  2. {
  3.     int l_len=abs(l->b_len);
  4.     assert(shift_value>=0);
  5.     BGInteger* ret=0;

  6.     /* bits(l) < shift_value*/
  7.     if(l_len*SHIFT<=shift_value)  /*如果位移量大于l的位数*/
  8.     {
  9.         if(l->b_len<0)           /*如果l为负,返回-1*/
  10.         {
  11.             return bg_create_from_int(-1);
  12.         }
  13.         else
  14.         {
  15.             return bg_create_zero();  /*如果l为正,返回0*/
  16.         }
  17.     }

  18.     int sign=l->b_len<0?1:0;    /*判断l的正负*/

  19.     ret=bg_malloc(l_len-shift_value/SHIFT);  /*为移位后的结果分配空间*/

  20.     int shift_pre=shift_value/SHIFT;
  21.     int shift_pos=shift_value%SHIFT;

  22.     int size=l_len-shift_pre;
  23.     int d=shift_pos;


  24.     b_unit* ivt_l=malloc(sizeof(*ivt_l)*l_len);

  25.     /* if l is negative , translate to complement */
  26.     if(sign)
  27.     {
  28.         /*如果为负,则把l转换为补码后才位移*/
  29.         units_invert_complement(ivt_l,l->b_val,l_len);
  30.     }
  31.     else
  32.     {
  33.         /*正数则不需要转换,直接复制*/
  34.         memcpy(ivt_l,l->b_val,l_len*sizeof(*ivt_l));
  35.     }

  36.     b_unit* src=ivt_l+shift_pre;
  37.     b_unit c_src;
  38.     b_unit oflow=0; /*l为正,高位用0补全*/
  39.     if(sign)
  40.     {
  41.         /* if left is negative, fill high bits 1 */
  42.         /*如果l为负,高位用1补全*/
  43.         oflow=(1<<d)-1;
  44.     }
  45.     oflow=(oflow<<(SHIFT-d))&MASK;
  46.     int i=size;

  47.     /* Right SHIFT */
  48.     while(i--)   /*位移*/
  49.     {
  50.         c_src=src[i];
  51.         src[i]=oflow|((c_src&MASK)>>d);
  52.         oflow=(c_src<<(SHIFT-d))&MASK;
  53.     }

  54.     if(sign)
  55.     {
  56.         /* translate complement to original */
  57.         /*如果为负数,则还需要把补码转换为原码*/
  58.         units_invert_origin(ret->b_val,src,size);
  59.         self_negative(ret);
  60.     }
  61.     else
  62.     {
  63.         memcpy(ret->b_val,src,sizeof(*src)*size);
  64.     }

  65.     free(ivt_l);
  66.     bg_format_len(ret);

  67.     return ret;
  68. }




阅读(4088) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~