超長整數的基礎運算 算法實現之模、模冪篇

模運算

整數取模實際是基於除法運算的結果,即求餘數的過程,把商排除在外後得到的結果。根據已經得到的除法運算結果進行篩選結果即可。

/*
模數運算
a 被模數
b 模數
c 模值
*/
int modHBInt(HBigInt *a, HBigInt *b, HBigInt *c){
	HBigInt tc;
	//模數不能爲0
	if(0 == b->length || (1 == b->length && 0 == b->pBigInt[0])) return -1; 
	//模數爲1,則模值等於被模數
	if(1 == b->length && 1 == b->pBigInt[0]) {
		setZeroHBInt(c);
		hbi_add_int(c,0);
		return RETURN_OK_BINT;
	}
	if(-1 == compareHBInt(a,b)) { //模數大於被模數,模值爲被模數
		assignHBInt(c,a);
		return RETURN_OK_BINT;
	}
	//初始化臨時變量
	initHBInt(&tc,INITIAL_BINT);
	divHBInt(a, b, &tc, c);
	// 回收臨時變量空間
	deleteHBInt(&tc); 
	return RETURN_OK_BINT;
}

模冪運算

由於底數和指數都是大整數,所以採用一般的計算方式(計算冪值後利用除法進行取模)存在嚴重的效率地下問題,因此在選擇算法時必須考慮快速和已處理兩部分的因素。在處理該算法時,最核心的部分是降冪運算,所以採用了平方乘取模的原理。

算法流程如下:

輸入:3個B進制(位數n、t、p)的大整數x(底數)、y(冪數)、z(模數)

輸出:B進制的模值r(初始化r=1)

1.      判斷非一般情況下模冪結果:

1.1  z == 0,則返回錯誤碼 RETURN_FAILE_BINT

1.2  z == 1,則r = 0,實際上r = xy ,因爲這樣的計算失去取模的意義

1.3  y == 1,則r = x % z,即普通的取模運算

1.4  y == 0,則r=1

2.      i從t到0

2.1  y是奇數,則r = r * x % z

2.2  x = x2 % z

2.3  y = y / 2

2.4  根據當前y的長度(位數)來遞減i的值

3. 返回r

/*
模數運算
a 被模數
p 指數
b 模數
c 模值
*/
int modPowerHBInt(HBigInt *a, HBigInt *p, HBigInt *b, HBigInt *c){
	HBigInt ta,ta_1,tp,tc,tc_1,demo_one;	
	// 模數爲0
	if(0 == b->length || (1 == b->length && 0 == b->pBigInt[0])) return -1; 
	// 模數爲1,則模值等於被模數,因爲沒有計算的意義,所以自定義爲0
	if(1 == b->length && 1 == b->pBigInt[0]) {
		setZeroHBInt(c);
		hbi_add_int(c,0);
		return RETURN_OK_BINT;
	}
	if( 1 == p->length && 1 == p->pBigInt[0] ) return modHBInt(a,b,c);
	else if ( (1 == p->length && 0 == p->pBigInt[0]) || 0 == p->length) {
		// 指數爲0
		setZeroHBInt(c);
		hbi_add_int(c,1);
		return RETURN_OK_BINT;
	} else {
		setZeroHBInt(c);
		hbi_add_int(c,1);		
		initHBInt(&ta,INITIAL_BINT);
		initHBInt(&ta_1,INITIAL_BINT);
		initHBInt(&tp,INITIAL_BINT);
		initHBInt(&tc,INITIAL_BINT);
		initHBInt(&tc_1,INITIAL_BINT);
		initHBInt(&demo_one,INITIAL_BINT);
		initHBInt(&tp,INITIAL_BINT);
		extendHBInt(&tc,c->length);
		extendHBInt(&ta_1,c->length);
		// 初始化單位1
		setZeroHBInt(&demo_one);
		hbi_add_int(&demo_one,1);
		// 賦值臨時變量
		assignHBInt(&tp,p);
		assignHBInt(&ta,a);
		extendHBInt(&tc,c->length);
		extendHBInt(&ta_1,ta.length + ta.length);
		// 平方乘取摸
		while(tp.length){
			if (tp.pBigInt[0] & 0x1){
				mulHBInt(c,c,&ta);
				assignHBInt(&tc,c);
				modHBInt(&tc,b,c);
			}
			mulHBInt(&ta_1,&ta,&ta);
			modHBInt(&ta_1,b,&ta);
			// 降冪
			Right_shift_bit(&tc_1, &tp);
			assignHBInt(&tp,&tc_1);
			trimHBInt(&tp); //去除高位無效的0
		}
	}
	// 回收臨時變量空間
	deleteHBInt(&ta);
	deleteHBInt(&ta_1);
	deleteHBInt(&tp);
	deleteHBInt(&tc);
	deleteHBInt(&tc_1);
	deleteHBInt(&demo_one); 
	return RETURN_OK_BINT;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章