超长整数的基础运算 之小结

首先将之前使用的内部函数一一说明实现

输入、输出:

/*
大整数扩大radix倍
大整数的每一位都要乘以radix
*/
int hbi_mul_radix(HBigInt *a, int radix){
<span style="white-space:pre">	</span>long i;
<span style="white-space:pre">	</span>unsigned int carry=0,result;
<span style="white-space:pre">	</span>if(0 == a->length){
<span style="white-space:pre">	</span>return RETURN_OK_BINT;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>for(i=0; i<a->length; i++){
<span style="white-space:pre">		</span>result = a->pBigInt[i] * radix + carry;
<span style="white-space:pre">		</span>a->pBigInt[i] = (result & 0xffff) ; // it equals : result % CARRY_RADIX
<span style="white-space:pre">		</span>carry = result >> BIT_PRE_WORD; // it equals : result / CARRY_RADIX
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>if(carry){
<span style="white-space:pre">		</span>a->pBigInt[i] = carry;
<span style="white-space:pre">		</span>a->length = i+1;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>return RETURN_OK_BINT;
}

/*
大整数值增加data (一位十进制数)
*/
int hbi_add_int(HBigInt *a, int data){
<span style="white-space:pre">	</span>long i;
<span style="white-space:pre">	</span>unsigned int carry=0,result;
<span style="white-space:pre">	</span>a->pBigInt[0] += data;
<span style="white-space:pre">	</span>if(0 == a->length){
<span style="white-space:pre">		</span>a->length = 1;
<span style="white-space:pre">		</span>return RETURN_OK_BINT;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>for(i=0; i<a->length; i++){
<span style="white-space:pre">		</span>result = a->pBigInt[i] + carry;
<span style="white-space:pre">		</span>a->pBigInt[i] = (result & 0xffff);
<span style="white-space:pre">		</span>carry = result >> BIT_PRE_WORD;
<span style="white-space:pre">		</span>if(0 == carry) break;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>if(carry){
<span style="white-space:pre">		</span>a->pBigInt[i] = carry;
<span style="white-space:pre">		</span>a->length = i+1;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>return RETURN_OK_BINT;
}
/*
大整数的输入,是指将字符串数组的转换成大整数表示,
从高位向低位输入,其中数组元素是0、1、2、3、4、5、6、7、8、9.
即可以将数组里面数看出十进制数的一位。第一个参数是大整数的指针,第二个是存储十进制的数组
*/
int readHBInt(HBigInt *a,const char *str){
	int y,res=0,neg;
	if(*str=='-'){
		++str;
		neg=-1;
	}
	else neg=1;
	
	setZeroHBInt(a); // 对a清0
	y=*str-48;	 // asc码转换,由字符变成数字
	a->pBigInt[0]=y;
	a->length=1;
	str++;
	//循环读入十进制的各位
	while(*str!='\0') {   
		y=*str-48;
		if(y < RADIX) {
			// 对大整数各位数乘以radix
			if((res=hbi_mul_radix(a,RADIX))!=RETURN_OK_BINT) {
				return res;
			}
			// 向大整数加上一位
			if((res=hbi_add_int(a,y))!=RETURN_OK_BINT) {
				return res;
			}
		}
		else break;
		++str;
	}
    a->sign=neg;
	trimHBInt(a);

	return RETURN_OK_BINT;
}

/*
大整数的输出,表示将B进制的大整数表示成十进制的字符数组输出。
数组每位元素是十进制的一位,从高位在前低位在后输出。
*/
int writeHBInt(HBigInt *a, char *str) {
	unsigned int result1=0,result2=0;
	char *p=str;
	long i,j,len,tmp;
	un_short mark=0;
	HBigInt *dst=(HBigInt *)malloc(sizeof(HBigInt));

	initHBInt(dst,INITIAL_BINT);
	extendHBInt(dst,a->length);
	assignHBInt(dst,a);
	len = a->length;
	i = len-1;

	if(0 == len) *p++='0';

	while(len) {
		len=dst->length;
		if(dst->pBigInt[i] < RADIX) {
			mark=dst->pBigInt[i];
			dst->pBigInt[i]=0;
			--i;
			len--;
			dst->length=len;
			if(0 == dst->length) {
				*p++=(char)(mark+48);
				goto LAST;
			}
		}
		//对大整数进行%10得出十进制的一位
		for(j=len-1;j>=0;j--) {
			tmp = mark*CARRY_RADIX+dst->pBigInt[j]+result1*CARRY_RADIX;
			result2 = tmp / RADIX;
			result1 = tmp % RADIX;
			dst->pBigInt[j] = result2;
			mark=0;
		}
		*p++=(char)(result1+48);
		result1=0;
		trimHBInt(dst);
	}
LAST:
	if(dst->sign==-1) *p++='-'; //添加大整数的符号
	*p='\0';
	reverStr(str);     //反转数组元素,使十进制高位在前
	deleteHBInt(dst);
	return RETURN_OK_BINT;
}
移位

/*
左移一个bit位
即: 扩大2倍
*/
int Left_shift_bit(HBigInt *dst, HBigInt *src) {
	long len = 0;
	long i = 0;
	unsigned int carry = 0;
	int result = 0;

	un_short *pDst = dst->pBigInt;
	un_short *pSrc = src->pBigInt;
	
	// 确保目的大整数能够容纳移位后的结果
	if(dst->alloclen < src->length+1 ) {	
		// 扩大大整数空间,保证能够存储
		if((result = extendHBInt(dst,src->length+1) != RETURN_OK_BINT)) {
			return result;
		}
		pDst = dst->pBigInt;
	}
	// 记录目的操作数原来的已用空间,方便后面处理
	len = dst->length; 
	dst->length = src->length;
	//pSrc = src->pBigInt;

	// 大整数数组元素分别左移一位,并赋给目的大整数
	for(i = 0; i < src->length; ++i) {
		pDst[i] = (un_short)(carry = ((pSrc[i]) << 1) | (carry >> BIT_PRE_WORD));
	}

	// 若最高数位左移后溢出,则将溢出的比特存到下一个字 
	if((carry >> BIT_PRE_WORD) != 0) {  
		pDst[src->length] = (un_short)(carry >>BIT_PRE_WORD);
		++(dst->length);
	}
	for(i=dst->length; i<len; ++i) pDst[i] = 0;	// 清除可能残留的旧数据
		
	dst->sign = src->sign;  // 更改符号

	return RETURN_OK_BINT;
}

/*
右移一个bit位
即: 缩小2倍
*/
int Right_shift_bit(HBigInt *dst,HBigInt *src) {
	long oldlen = 0;    //保存目的大整数的原来长度
	long i = 0;
	unsigned int carry = 0;
	int result = 0;

	un_short temp = 0;     
	un_short *pDst = dst->pBigInt;
	un_short *pSrc = src->pBigInt;

	// 确保目的大整数能够容纳移位后的结果
	if(dst->alloclen < src->length)	{
		// 扩展目的大整数长度
		if((result = extendHBInt(dst,src->length) != RETURN_OK_BINT)) 
			return result; 
		pDst = dst->pBigInt;
	}

	oldlen = dst->length;
	dst->length = src->length;
	pSrc = src->pBigInt;
	for(i=src->length-1; i >= 0; --i) {	/* 分别右移一位*/
		temp = (un_short)((pSrc[i] >> 1) | (un_short)(carry << (BIT_PRE_WORD-1)));
		carry = (un_short)(pSrc[i] & (un_short)1);
		pDst[i] = temp;
	}
	for(i=dst->length; i<oldlen; ++i) pDst[i] = 0;	// 清除可能残留的旧数据
	
	dst->sign = src->sign;
	oldlen=dst->alloclen;
	pDst=dst->pBigInt+dst->alloclen-1;
	
	while(0 == *pDst--) oldlen--;  //重新计算出目的大整数的长度

	dst->length=oldlen;
	return RETURN_OK_BINT;
}
赋值:

/* 给大整数赋值 */
// 前提:dst被合理的initHBInt(即size要与src相同)
void assignHBInt(HBigInt *dst,HBigInt *src) {
	dst->length = src->length;
	dst->sign = src->sign;
 	memcpy(dst->pBigInt,src->pBigInt,sizeof(int)*src->alloclen);
}
互换:

//交换两个大整数
void swapHBInt(HBigInt *biA,HBigInt *biB) {
	un_short *tmp=NULL;
	biA->alloclen ^= biB->alloclen;
	biB->alloclen ^= biA->alloclen;
	biA->alloclen ^= biB->alloclen;

	biA->length ^= biB->length;
	biB->length ^= biA->length;
	biA->length ^= biB->length;

	biA->sign ^= biB->sign;
	biB->sign ^= biA->sign;
	biA->sign ^= biB->sign;
	
	tmp = biA->pBigInt ;
	biA->pBigInt = biB->pBigInt;
	biB->pBigInt = tmp;
}
最后是头文件定义:

typedef unsigned int un_short;			/*16位数的声明符号*/	
typedef unsigned long un_long;			/*32位数的声明符号*/

#define RADIX			10		/* 进制数 */
#define CARRY_RADIX		65536		/* 每个pBigInt位所能表示的最大值 */
#define SIGNED_ZERO_BINT	0		/* 初始化大整数时的符号位 */

#define BIT_PRE_WORD		16		/* 每个单精度数字含有的bit数 */

#define RETURN_OK_BINT		0		/* 正常返回 */
#define RETURN_FAILE_BINT       1           <span style="white-space:pre">	</span>/* 错误返回 */
#define FAILE_MEMORY_BINT   <span style="white-space:pre">	</span>2		/* 分配堆空间失败返回值 */

#define INITIAL_BINT        <span style="white-space:pre">	</span>49		/* 默认分配的大小 */
#define STEP_BINT           <span style="white-space:pre">	</span>16		/* 起跳值 */

/* 定义大整数的结构 */
typedef struct	{
	long alloclen;		/* 记录数组已经分配总的空间大小 */
	long length;		/* 记录大整数的长度,即实际使用空间大小 */
	int sign;	       	/* 记录大整数的符号 */
	un_short *pBigInt;	/* 记录大整数的实际数据位上的数值 */
} HBigInt;

在写这段小程序的时间里个人觉得数学功底的实用性还是很重要的,在早期的算法实现里其实就是在与数学方法在“较量”。

后期工作:

1、改进算法,使能够并行化

2、完善已有功能(主要是从现有的实现上加以求精),扩展未有功能

     比如:自平方算法的实现(使普通的n^2效率降低到(n+n^2/2)级别)、求常用的对数(log2、ln、lg等

同时欢迎各位客官的批评指正!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值