// from NTUCPC Guide for (int y = 1; y * y <= x; y++) { if (x % y == 0) { // x = y * (x / y) // y 是 x 的因數 // x / y 是 x 的因數 // y 跟 x / y 可能是相同的,如果不能重複處理的話要特別注意 } }
不要把 y * y <= x 寫成 y <= sqrt(x),因為 sqrt(x) 的結果是浮點數,可能會有浮點數誤差。
而至於質數部分,具體程式碼實現如下:
1 2 3 4 5 6 7 8 9
// from NTUCPC Guide boolis_prime(int x){ for (int y = 2; y * y <= x; y++) { // 起始值是 2 if (x % y == 0) { // x = y * (x / y) returnfalse; } } returntrue; }
大數四則運算
因為 C++ 的資料型態都設有一定的範圍限制,所以在做一些「大數」運算的時候,難免會出現 overflow 的問題,因此就要自己手刻運算程式。
儲存大數
利用陣列儲存每一個數字的位數:
1 2
int a[len] = {1,2,3,4,5,6,7,8,9}; // 123456789 int b[len] = {3,2,7,1,2,6,5,4,9,0,9,0,0,1,1,2,2,3,4,2,7,5}; // 3271265490900112234275
加法
兩數相加時會用直式去計算,直式就是從最右邊開始用每一位相加、進位的計算。
如果兩數的某位數相加起來超過 10,就進位 1。
若 10 -> 往左邊進位 + 1,本身變成 0。
若 11 -> 往左邊進位 + 1,本身變成 1。
1 2 3 4 5 6 7 8 9 10 11
// from NTUCPC Guide constint len = 10; // 數字的最大位數(答案也不能超過這個位數) voidbig_plus(int a[len], int b[len], int c[len]){ // c = a + b int carry = 0; // 上一個位數進位到這一位數 for (int i = 0; i < len; i++) { int sum = a[i] + b[i] + carry; // 兩個數字的這一位數相加,再加上進位 c[i] = sum % 10; // 總和的個位數就是答案 carry = sum / 10; // 超出個位數的部分要進位到下一個位數 } }
// from NTUCPC Guide voidbig_minus(int a[len], int b[len], int c[len]){ // c = a - b int carry = 0; // 上一個位數進(借)位到這一位數 for (int i = 0; i < len; i++) { int sum = a[i] - b[i] + carry; // -10 <= sum <= 9 if (sum < 0) carry = -1, sum += 10; // 變負的要借位 else carry = 0; c[i] = sum; // 現在 0 <= sum <= 9 } }
乘法
乘法與加法的程式設計幾乎差不多,一樣向左進位。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// from NTUCPC Guide voidbig_multiplies(int a[len], int b[len], int c[len]){ // c = a * b for (int i = 0; i < len; i++) c[i] = 0; for (int i = 0; i < len; i++) { int carry = 0; for (int j = 0; i + j < len; j++) { // 從低位做到高位就能好好處理進位 // (a[i] * 10^i) * (b[j] * 10^j) = (a[i] * b[j]) * 10^(i+j) int sum = c[i + j] + a[i] * b[j] + carry; c[i + j] = sum % 10; carry = sum / 10; } } }
除法
比大小函數:
1 2 3 4 5 6 7 8
// from NTUCPC Guide intcomp(int a[len], int b[len]){ // -1: a < b, 0: a = b, 1: a > b for (int i = len - 1; i >= 0; i--) { if (a[i] < b[i]) return-1; elseif (a[i] > b[i]) return1; } return0; }
除法與其他運算不同,除法是從最高位數(最左邊)開始運算,其他都是從最低位數(最右邊)。
a / b 的最高位數,就是「b 乘上它不會超過 a」的最大的數字,而這個數字也不是很好找,對人類而言只能猜猜看,好在電腦要一個一個慢慢試沒有那麼困難。在找到最高位數後,就把 a 減去 b 乘上它,接下來再找下一個位數。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
voidbig_divides(int a[len], int b[len], int c[len], int r[len]){ // a / b = c ... r int t = len - 1; for (; t >= 0 && b[t] == 0; t--); // 找到 b 的最高非 0 位數 int tmp[len]; for (int i = 0; i < len; i++) r[i] = a[i], c[i] = 0; for (int i = len - t - 1; i >= 0; i--) { // 從最大的位數開始找,要確保 b * 10^i 位數不會超過 len int d = 0; for (int j = 0; j < len; j++) tmp[j] = 0; for (int j = 0; j <= t; j++) tmp[i + j] = b[j]; // tmp = b * 10^i while (comp(r, tmp) >= 0) { // r >= tmp big_minus(r, tmp, r); // r = tmp - r d++; } c[i] = d; } }
// 計算多項式函數值(秦九韶算法) doublepoly(const vector<int>& coeff, double x){ double result = 0; for (int i = 0; i < 6; i++) { result = result * x + coeff[i]; } return result; }