(壓位)高精 思路 程式碼實現
看到了一篇不錯的高精教程:(devillaw_zhc)
1.加法
就是 從個位開始 兩個數字相加,如果有進位,就加到十位,再算十位相加,……
2.減法
也是從個位開始 兩個數字相減,如果得到的數字小於 0,那麼就加上 10,並且把被減數的十位減一,……
3.乘法
第一個數乘以第二個數的個位,寫下來,右邊與個位對齊,再與第二個數的十位相乘,右邊與十位對齊,……
仔細想一想,會發現其實 第一個數 從右數起的第 i 位,不妨設為 2 乘以 第二個數從右數起的第 j 位,不妨設為 8,就相當於 2*10^(i-1) * 8*10^(j-1)
這個乘積所貢獻的就是 答案從右數起的 第 i+j-1 位, 即 16 *10^(i+j-2) ,把 1 進位到 從右數起的第 i+j 位上,留下 6 . 即可。
4.除法
除法其實是減法的延伸,打個比方,24723 除以 123 。
按照人的做法,從高位開始一位一位取出被除數的數字
先是 2,判斷是否小於 123, 小於那答案這一位就置 0
再取一位,24, 還是小於,答案這一位置0
再取一位,247,這時候比 123 大了,那就看能減多少個 123, 發現減 2 次之後比 123 小了,那麼答案的第 3 位上就是2, 減剩下的數是 1
重複那個過程,取一位,12, 小於 123 ,答案這一位置 0
再取一位, 123, 不小於 123 了, 看能減多少個, 發現能減一個, 那麼答案第 5 位就是 1
剩下的數為 0 , 而被除數的數也被取光了,運算結束。
答案為 00201 ,整理一下即為 201。
壓位本質其實是一樣的,只不過儲存方式與輸出方式有不同。
比如數 103
用十位的高精度存 a[0] = 3, a[1] = 3, a[2] = 0, a[3] = 1
用百位的高精度存 a[0] = 2, a[1] = 3, a[2] = 1
要注意的是輸出的時候 a[1] 不能只輸出一個 3, 而要輸出 03.
程式碼實現
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int power = 1; //每次運算的位數為10的power次方,在這裡定義為了方便程式實現const int base = 10; //10的power次方。 //要壓位的時候,只需改power 和 base即可,如壓萬位高精,那麼power = 4, base = 10000 const int MAXL = 1001; //陣列的長度。 char a[MAXL], b[MAXL]; struct num { int a[MAXL]; num() { memset(a, 0, sizeof(a)); } //初始化 num(char *s) //將一個字串初始化為高精度數 { memset(a, 0, sizeof(a)); int len = strlen(s); a[0] = (len+power-1) / power; //數的長度 for (int i=0, t=0, w; i < len ;w *= 10, ++i) { if (i % power == 0) { w = 1, ++t; } a[t] += w * (s[i]-'0'); } //初始化陣列,這裡自己模擬一下,應該很容易懂的~ } void add(int k) { if (k || a[0]) a[ ++a[0] ] = k; } //在末尾新增一個數,除法的時候要用到 void re() { reverse(a+1, a+a[0]+1); } //把數反過來,除法的時候要用到 void print() //列印此高精度數 { printf("%d", a[ a[0] ]); //先列印最高位,為了壓位 或者 該高精度數為0 考慮 for (int i = a[0]-1;i > 0;--i) printf("%0*d", power, a[i]); //這裡"%0*d", power的意思是,必須輸出power位,不夠則前面用0補足 printf("\n"); } } p,q,ans; bool operator < (const num &p, const num &q) //判斷小於關係,除法的時候有用 { if (p.a[0] < q.a[0]) return true; if (p.a[0] > q.a[0]) return false; for (int i = p.a[0];i > 0;--i) { if (p.a[i] != q.a[i]) return p.a[i] < q.a[i]; } return false; } num operator + (const num &p, const num &q) //加法,不用多說了吧,模擬一遍,很容易懂 { num c; c.a[0] = max(p.a[0], q.a[0]); for (int i = 1;i <= c.a[0];++i) { c.a[i] += p.a[i] + q.a[i]; c.a[i+1] += c.a[i] / base; c.a[i] %= base; } if (c.a[ c.a[0]+1 ]) ++c.a[0]; return c; } num operator - (const num &p, const num &q) //減法,也不用多說,模擬一遍,很容易懂 { num c = p; for (int i = 1;i <= c.a[0];++i) { c.a[i] -= q.a[i]; if (c.a[i] < 0) { c.a[i] += base; --c.a[i+1]; } } while (c.a[0] > 0 && !c.a[ c.a[0] ]) --c.a[0]; //我的習慣是如果該數為0,那麼他的長度也是0,方便比較大小和在末尾新增數時的判斷。 return c; } num operator * (const num &p, const num &q) //乘法,還是模擬一遍。。其實高精度就是模擬人工四則運算! { num c; c.a[0] = p.a[0]+q.a[0]-1; for (int i = 1;i <= p.a[0];++i) for (int j = 1;j <= q.a[0];++j) { c.a[i+j-1] += p.a[i]*q.a[j]; c.a[i+j] += c.a[i+j-1] / base; c.a[i+j-1] %= base; } if (c.a[ c.a[0]+1 ]) ++c.a[0]; return c; } num operator / (const num &p, const num &q) //除法,這裡我稍微講解一下 { num x, y; for (int i = p.a[0];i >= 1;--i) //從最高位開始取數 { y.add(p.a[i]); //把數添到末尾(最低位),這時候是高位在前,低位在後 y.re(); //把數反過來,變為統一的儲存方式:低位在前,高位在後 while ( !(y < q) ) //大於等於除數的時候,如果小於的話,其實答案上的該位就是初始的“0” y = y - q, ++x.a[i]; //看能減幾個除數,減幾次,答案上該位就加幾次。 y.re(); //將數反過來,為下一次添數做準備 } x.a[0] = p.a[0]; while (x.a[0] > 0 && !x.a[x.a[0]]) --x.a[0]; return x; } int main() { scanf("%s", a); scanf("%s", b); reverse(a, a+strlen(a)); reverse(b, b+strlen(b)); p = num(a), q = num(b); ans = p + q; ans.print(); ans = p - q; ans.print(); ans = p * q; ans.print(); ans = p / q; ans.print(); }