首先将之前使用的内部函数一一说明实现
输入、输出:
/*
大整数扩大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等)
同时欢迎各位客官的批评指正!