280 likes | 400 Views
主題 : Big number ( 大數 ). 解題技巧 什麼是大數? 大數運算 加法 減法 乘法 例題講解 : H.91.4 歷年題目. 什麼是大數?. 怎麼存下面的數字 100000 : int (-2 31 ~ 2 31 -1) 10000000000 : __int64 (-2 63 ~ 2 63 -1) 1000000000000000000000 : 怎麼存? 目前 C 只能用 64 bit 儲存整數, 64 bit 存不下的數字就稱為大數. 如何儲存大數. 正確評估 max_len
E N D
主題: Big number (大數) • 解題技巧 • 什麼是大數? • 大數運算 • 加法 • 減法 • 乘法 • 例題講解: H.91.4 • 歷年題目
什麼是大數? • 怎麼存下面的數字 • 100000 : int (-231 ~ 231-1) • 10000000000 : __int64 (-263 ~263-1) • 1000000000000000000000 : 怎麼存? • 目前 C 只能用 64 bit 儲存整數,64 bit 存不下的數字就稱為大數
如何儲存大數 • 正確評估 max_len • 最大數要多少位元 (10 進位),保證不會 overflow • 5 位數 + 4 位數 <= 6 位數 • 5 位數 × 4 位數 <= 9 位數 • 用 string 來儲存 • char x[max_len+1] • x = “684597315274” • 將每個位數用一個字元來儲存,運算時再轉換回數字
如何儲存大數 • 用整數陣列來儲存 (for 運算,較容易) • int num[max_len] = { 4, 7, 2, 5, 1, 3, 7, 9, 5, 4, 8, 6, 0, ..., 0} • 要記得補 0 • 不補 0 要記有效位元長度,速度快但程式不好寫 個位數 0 0 0 0 0 0 0 2 3 4 × 0 0 0 0 0 0 0 0 5 6
大數運算 • 大數運算 • 加法 • 乘法 • 減法
大數加法 • 原理 • 既然 C 程式內建的加法不能用,那就用最原始的加法 • 要注意進位的動作 1 1 4 1 7 8 + 4 2 5 4 6 0 3
資料結構 • int num1[max_len], num2[max_len] • 用來儲存數字 • int answer[max_len] • 用來儲存結果 • int carry
大數加法 • 123456789 + 987654321 ? • 把 123456789 存在 num1 之中,987654321 存在 num2,結果存在 answer 中 carry 1 1 1 1 1 1 1 1 1 0 num1 0 1 2 3 4 5 6 7 8 9 num2 + 0 9 8 7 6 5 4 3 2 1 answer 1 1 1 1 1 1 1 1 1 0
C code void big_add( int *num1, int *num2, int *answer ){ int i; carry = 0; for ( i = 0 ; i < max_len ; i++) { answer[ i] = (num1[ i] + num2[ i] + carry) % 10; carry = (num1[ i] + num2[ i] + carry) / 10; } if (carry != 0) printf(“Overflow!!!\n”); }
大數乘法 • 原理 • 乘法其實就是很多個加法 • 注意進位和位數 4 1 7 8 × 4 2 5 4 2 0 3 2 0 8 9 0 1 0 1 8 3 5 6 3 1 0 3 1 6 7 1 2 1 0 0 0 1 1 1 7 7 5 6 5 0
資料結構 • num1, num2, carry 和加法一樣 • 中間的過程要用二維陣列來儲存? • 不用,和加法一樣只需要一個一維陣列 answer • 每次有新的值乘出來之後,就把它加到適當的位置去
0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 1 7 8 4 1 7 8 0 0 0 0 × 4 2 5 × 4 2 5 4 2 0 3 0 0 2 0 8 9 0 2 0 8 9 0 0 1 1 0 0 8 3 5 6 + 8 3 5 6 3 1 0 3 + 1 6 7 1 2 0 1 0 4 4 5 0 1 0 0 0 1 1 1 7 7 5 6 5 0 + 1 6 7 1 2 1 7 7 5 6 5 0
C code void big_mul( int *num1, int *num2, int *answer ){ int i, j; for (i = 0; i < max_len) ; i++){ carry = 0; for (j = 0; j < max_len ; j++){ if (( i + j ) < max_len) answer[i+j] = (answer[i+j] + num1[j] * num2[i] + carry) % 10; carry= (answer[i+j] + num1[j] * num2[i] + carry) / 10; } } }
小技巧 • 在做大數運算時,可以將數個位數當成同一個位數來運算 • 之前的例子都是十進位,若換成百進位的話結果會如何? 4 1 7 8 × 4 2 5 10 19 1 0 4 4 5 0 3 1 1 6 7 1 2 1 7 7 5 6 5 0
當每一次運算所使用的位數增加時,總共所需要計算的次數就會減少,所要開的陣列大小也跟著變少當每一次運算所使用的位數增加時,總共所需要計算的次數就會減少,所要開的陣列大小也跟著變少 • 若陣列的型態為整數的話,則最多只能以萬進位為計算的單位 • 10000*10000 < 2^32
大數減法 • 原理 • 跟加法、乘法差不多 • 要注意借位 • 可以先判斷減數或被減數大,拿大的去減小的,最後再補正負號即可
大數減法 • 425 – 4178 = – (4178 – 425 ) = –3753 -1 4 1 7 8 – 4 2 5 3 7 5 3 –
C code /* 假設 num1 比 num2 大 */ void big_sub( int * num1, int *num2, int *answer ){ int i; carry = 0; for (i = 0; i < max_len ; i++) { answer[ i] = num1[ i] – num2[ i] + carry; if (answer[ i] < 0) { answer[ i] = answer[ i] + 10; // 若是百進位則加100 carry = -1; } else carry = 0; } if (carry != 0) printf(“Underflow!!!\n”); }
例題講解: H.91.4http://www.cs.tku.edu.tw/info_race2002/codeq.htm • [a0, a1, …, an],其中每一個 ai 都是 0 到 9之間的整數,而且 n 50 (最多有 51 個數字) …
Example • 將連分數轉成分數
Sample input/output Sample input: 1,1,1,2 Sample 5 8 a0,a1,a2,a3 分子 分母
分析 = = = =
分析 • 所需的動作 • 乘法 • 加法 • 分子分母對調 • Easy?
分析 • 每個 ai 最大有可能到 9,最多可能有 51 個 9 連乘 • 9^51 >> 2^63 • 需要大數加法和大數乘法
需要的資料結構 • int num[51] • 儲存 a0到 an,最多有 51 個數 • int x[51] // 分子 • 9^51 位數最多只會有 51 位 • int y[51] // 分母
Program structure intial_分子_分母(); for (i = n – 1; i >= 0; i++){ count_new分子_new分母(); }
C code int x[51], y[51], newx[51], newy[51]; x[0] = 1; y[0] = an; for (i = n – 1; i >= 0; i++){ newx y; newy big_add ( big_mul ( y , ai) , x ) ; /* newy = y × ai + x; */ x newx; y newy; } 這裡的大數乘法是 一個大數乘以一個整數,較簡單
歷年題目 • 練習題 • A. 495 Fibonacci Freeze • http://acm.uva.es/p/v4/495.html • A. 623 500! • http://acm.uva.es/p/v6/623.html • A. 338 Long Multiplication • http://acm.uva.es/p/v3/338.html • A. 619 Numerically Speaking • http://acm.uva.es/p/v6/619.html • 挑戰題 • 2004兩岸清華學生程式比賽 Problem D • http://venus.cs.nthu.edu.tw/~jous/NTHU2004-Problems.doc • http://venus.cs.nthu.edu.tw/~jous/pd.exe • A. 288 Arithmetic Operation with Large Integers • http://acm.uva.es/p/v2/288.html • 其它歷年題目 • 無