編寫Java代碼實現求1001的803次方除以137的餘數

問題

編寫Java代碼,求 1001803 mod 137 的值。

分析

求餘運算是Java的基本功能,可以直接使用 (int)Math.power(a,b) % p 進行計算,但是由於指數運算增長太快,非常容易就超出 Integer 的數據類型,即便我們使用 Long,其最大值也不過是 264-1,約爲 1.84X1019,遠遠小於 1001803,所以顯然是無法直接求的。

爲了解決問題,我們首先分析一下餘數的性質。根據餘數 性質3: 給定 a,b,c,rZa, b, c, r \in \mathbb{Z}c00rcc \neq 0,0 \leq r \leq c,則(a×c) mod b=(a mod b)×(b mod b)(a \times c) \ \mathrm{mod} \ b = (a \ \mathrm{mod} \ b) \times (b \ \mathrm{mod} \ b)。比如,(7 ×\times 9) mod 5 = 3,而((7 mod 5) ×\times (9 mod 5)) mod 5 = (2 ×\times 4) mod 5 = 3。

根據這個性質,我們可以把問題變爲1001對137取餘後的乘積再餘,即:
1001803 mod 137=((1001 mod 137)(1001 mod 137)(1001 mod 137)803次取餘再相乘) mod 137將乘積再對137取餘 1001^{803} \ \mathrm{mod} \ 137 = \underbrace{\underbrace{ ((1001 \ \mathrm{mod} \ 137) * (1001 \ \mathrm{mod} \ 137) * \cdots * (1001 \ \mathrm{mod} \ 137) }_{\text{803次取餘再相乘}} ) \ \mathrm{mod} \ 137}_\text{將乘積再對137取餘}

實現

根據以上分析,我們可以根據這個思路編寫以下代碼:

public static void main(String[] args){
	int base = 1001;
	int x = 803;
	int p = 137;
	int result = 1;
	
	for (int i = 0; i < x; i++) 
		result *= base % p;
	result %= p;

	System.out.println("Result = " + result);
}

然而在執行時,仍然結果不正確,會報數據溢出的錯誤。經檢查,發現溢出錯誤是發生在循環中的 result *= base % p 語句,即 result 仍然會超出數據範圍,原因應該是多次乘法的值過大導致的,所以我們代碼可以再優化一下,最終結果如下:

public static void main(String[] args){
	int base = 1001;
	int x = 803;
	int p = 137;
	int result = 1;
	
	for (int i = 0; i < x; i++){
		 // 防溢出,一定要寫在 result *= base % p; 的上面,讀者可以思考下這是爲什麼。
		if (result > 46340) // 注1
			result %= p;
		result *= base % p;
	}
	result %= p;
	System.out.println("Result = " + result);
}

注1:在程序中進行乘法運算時,兩個數的乘積可能會超出其數據類型所能表示的範圍,所以此處的取到此類型所能表示的最大值開根的值。當前類型爲int,其最大的正值爲 2^31-1,所以可選的最大值爲 (int) Math.sqrt(2^31 - 1),即46,340。即底能取到最大值爲 46,340,如果想取更大的值可以使用 long,計算範圍的方法一樣,其值爲3,037,000,499。

運行計算後,結果爲:

Result = 104

擴展

我們可以進一步對其進行擴展,將這個計算抽象出一個函數,以方便利用,其定義如下:

/**
 * Return base^x % p.
 * @param base The base of the exponential function.
 * @param x A variable of the exponential function.
 * @param p The divider.
 * @return
 */
public static int getMod(int base, int x, int p) {
	int r = 1;
	for (int i = 0; i < x; i++){
		if (result > 46340)
			result %= p;
		result *= base % p;
	}
	return r % p;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章