#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();
}
ACM-高精度模板(综合篇)
能用int表示的数据视为单精度,否则为高精度。所有函数的设计均采用带返回值的形式。
本文包含:1.高精度加法;2.高精度减法;
3.高精度乘法 1)高乘高朴素算法 2)高乘高FFT优化算法 3)高精度乘单精度
4.高精度除法 1)高精度除高精度 2)高精度除单精度
5.高精度取模 1)高精度对高精度取模 2)高精度对单精度取模
6.高精度阶乘;7.高精度幂;8.高精度GCD;9.高精度进制转换;10.高精度求平方根
1.高精度加法
传入参数约定:传入参数均为string类型,返回值为string类型
算法思想:倒置相加再还原。
算法复杂度:o(n)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=110;
string add(string a,string b)//只限两个非负整数相加
{
string ans;
int na[L]={0},nb[L]={0};
int la=a.size(),lb=b.size();
for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';
for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';
int lmax=la>lb?la:lb;
for(int i=0;i<lmax;i++) na[i]+=nb[i],na[i+1]+=na[i]/10,na[i]%=10;
if(na[lmax]) lmax++;
for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
return ans;
}
int main()
{
string a,b;
while(cin>>a>>b) cout<<add(a,b)<<endl;
return 0;
}
2.高精度减法
传入参数约定:传入参数均为string类型,返回值为string类型
算法思想:倒置相减再还原。
算法复杂度:o(n)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=110;
string sub(string a,string b)//只限大的非负整数减小的非负整数
{
string ans;
int na[L]={0},nb[L]={0};
int la=a.size(),lb=b.size();
for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';
for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';
int lmax=la>lb?la:lb;
for(int i=0;i<lmax;i++)
{
na[i]-=nb[i];
if(na[i]<0) na[i]+=10,na[i+1]--;
}
while(!na[--lmax]&&lmax>0) ;lmax++;
for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
return ans;
}
int main()
{
string a,b;
while(cin>>a>>b) cout<<sub(a,b)<<endl;
return 0;
}
3.高精度乘法
1)高精度乘高精度的朴素算法
传入参数约定:传入参数均为string类型,返回值为string类型
算法思想:倒置相乘,然后统一处理进位,再还原。
算法复杂度:o(n^2)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=110;
string mul(string a,string b)//高精度乘法a,b,均为非负整数
{
string s;
int na[L],nb[L],nc[L],La=a.size(),Lb=b.size();//na存储被乘数,nb存储乘数,nc存储积
fill(na,na+L,0);fill(nb,nb+L,0);fill(nc,nc+L,0);//将na,nb,nc都置为0
for(int i=La-1;i>=0;i--) na[La-i]=a[i]-'0';//将字符串表示的大整形数转成i整形数组表示的大整形数
for(int i=Lb-1;i>=0;i--) nb[Lb-i]=b[i]-'0';
for(int i=1;i<=La;i++)
for(int j=1;j<=Lb;j++)
nc[i+j-1]+=na[i]*nb[j];//a的第i位乘以b的第j位为积的第i+j-1位(先不考虑进位)
for(int i=1;i<=La+Lb;i++)
nc[i+1]+=nc[i]/10,nc[i]%=10;//统一处理进位
if(nc[La+Lb]) s+=nc[La+Lb]+'0';//判断第i+j位上的数字是不是0
for(int i=La+Lb-1;i>=1;i--)
s+=nc[i]+'0';//将整形数组转成字符串
return s;
}
int main()
{
string a,b;
while(cin>>a>>b) cout<<mul(a,b)<<endl;
return 0;
}
2)高精度乘高精度FFT优化算法
传入参数约定:传入参数均为string类型,返回值为string类型
算法思想:将两个高精度乘数每个数位上的数视为多项式对应的系数,用o(n*log(n))的复杂度转成点值形式,再利用o(n)的复杂度相乘,最后对点值进行差值,用o(n*log(n))的复杂度还原成多项式的形式,即原来的形式。
算法复杂度:o(n*log(n))
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
#define L(x) (1 << (x))
const double PI = acos(-1.0);
const int Maxn = 133015;
double ax[Maxn], ay[Maxn], bx[Maxn], by[Maxn];
char sa[Maxn/2],sb[Maxn/2];
int sum[Maxn];
int x1[Maxn],x2[Maxn];
int revv(int x, int bits)
{
int ret = 0;
for (int i = 0; i < bits; i++)
{
ret <<= 1;
ret |= x & 1;
x >>= 1;
}
return ret;
}
void fft(double * a, double * b, int n, bool rev)
{
int bits = 0;
while (1 << bits < n) ++bits;
for (int i = 0; i < n; i++)
{
int j = revv(i, bits);
if (i < j)
swap(a[i], a[j]), swap(b[i], b[j]);
}
for (int len = 2; len <= n; len <<= 1)
{
int half = len >> 1;
double wmx = cos(2 * PI / len), wmy = sin(2 * PI / len);
if (rev) wmy = -wmy;
for (int i = 0; i < n; i += len)
{
double wx = 1, wy = 0;
for (int j = 0; j < half; j++)
{
double cx = a[i + j], cy = b[i + j];
double dx = a[i + j + half], dy = b[i + j + half];
double ex = dx * wx - dy * wy, ey = dx * wy + dy * wx;
a[i + j] = cx + ex, b[i + j] = cy + ey;
a[i + j + half] = cx - ex, b[i + j + half] = cy - ey;
double wnx = wx * wmx - wy * wmy, wny = wx * wmy + wy * wmx;
wx = wnx, wy = wny;
}
}
}
if (rev)
{
for (int i = 0; i < n; i++)
a[i] /= n, b[i] /= n;
}
}
int solve(int a[],int na,int b[],int nb,int ans[])
{
int len = max(na, nb), ln;
for(ln=0; L(ln)<len; ++ln);
len=L(++ln);
for (int i = 0; i < len ; ++i)
{
if (i >= na) ax[i] = 0, ay[i] =0;
else ax[i] = a[i], ay[i] = 0;
}
fft(ax, ay, len, 0);
for (int i = 0; i < len; ++i)
{
if (i >= nb) bx[i] = 0, by[i] = 0;
else bx[i] = b[i], by[i] = 0;
}
fft(bx, by, len, 0);
for (int i = 0; i < len; ++i)
{
double cx = ax[i] * bx[i] - ay[i] * by[i];
double cy = ax[i] * by[i] + ay[i] * bx[i];
ax[i] = cx, ay[i] = cy;
}
fft(ax, ay, len, 1);
for (int i = 0; i < len; ++i)
ans[i] = (int)(ax[i] + 0.5);
return len;
}
string mul(string sa,string sb)
{
int l1,l2,l;
int i;
string ans;
memset(sum, 0, sizeof(sum));
l1 = sa.size();
l2 = sb.size();
for(i = 0; i < l1; i++)
x1[i] = sa[l1 - i - 1]-'0';
for(i = 0; i < l2; i++)
x2[i] = sb[l2-i-1]-'0';
l = solve(x1, l1, x2, l2, sum);
for(i = 0; i<l || sum[i] >= 10; i++) // 进位
{
sum[i + 1] += sum[i] / 10;
sum[i] %= 10;
}
l = i;
while(sum[l] <= 0 && l>0) l--; // 检索最高位
for(i = l; i >= 0; i--) ans+=sum[i] + '0'; // 倒序输出
return ans;
}
int main()
{
cin.sync_with_stdio(false);
string a,b;
while(cin>>a>>b) cout<<mul(a,b)<<endl;
return 0;
}
3)高精度乘单精度
传入参数约定:传入第一个参数为string类型,,第二个参数为int型,返回值为string类型
算法思想:倒置相乘,然后统一处理进位,再还原。
算法复杂度:o(n)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=100005;
int na[L];
string mul(string a,int b)//高精度a乘单精度b
{
string ans;
int La=a.size();
fill(na,na+L,0);
for(int i=La-1;i>=0;i--) na[La-i-1]=a[i]-'0';
int w=0;
for(int i=0;i<La;i++) na[i]=na[i]*b+w,w=na[i]/10,na[i]=na[i]%10;
while(w) na[La++]=w%10,w/=10;
La--;
while(La>=0) ans+=na[La--]+'0';
return ans;
}
int main()
{
string a;
int b;
while(cin>>a>>b) cout<<mul(a,b)<<endl;
return 0;
}
C++高精度运算模板
(来自https://blog.csdn.net/code4101/article/details/23020525 膜拜dalao qwq)
另一种版本的高精度类 功能:正整数的加、减、乘、除、取余、大小关系运算。
#include <cassert> // assert
#include <cstdio> // printf,sprintf
#include <cstring> // strlen
#include <iostream> // cin,cout
#include <string> // string类
#include <vector> // vector类
#include <algorithm> // max
using namespace std;
const int maxn = 1000;
struct BigInteger {
typedef unsigned long long LL;
static const int BASE = 100000000;
static const int WIDTH = 8;
vector<int> s;
BigInteger& clean(){while(!s.back()&&s.size()>1)s.pop_back(); return *this;}
BigInteger(LL num = 0) {*this = num;}
BigInteger(string s) {*this = s;}
BigInteger& operator = (long long num) {
s.clear();
do {
s.push_back(num % BASE);
num /= BASE;
} while (num > 0);
return *this;
}
BigInteger& operator = (const string& str) {
s.clear();
int x, len = (str.length() - 1) / WIDTH + 1;
for (int i = 0; i < len; i++) {
int end = str.length() - i*WIDTH;
int start = max(0, end - WIDTH);
sscanf(str.substr(start,end-start).c_str(), "%d", &x);
s.push_back(x);
}
return (*this).clean();
}
BigInteger operator + (const BigInteger& b) const {
BigInteger c; c.s.clear();
for (int i = 0, g = 0; ; i++) {
if (g == 0 && i >= s.size() && i >= b.s.size()) break;
int x = g;
if (i < s.size()) x += s[i];
if (i < b.s.size()) x += b.s[i];
c.s.push_back(x % BASE);
g = x / BASE;
}
return c;
}
BigInteger operator - (const BigInteger& b) const {
assert(b <= *this); // 减数不能大于被减数
BigInteger c; c.s.clear();
for (int i = 0, g = 0; ; i++) {
if (g == 0 && i >= s.size() && i >= b.s.size()) break;
int x = s[i] + g;
if (i < b.s.size()) x -= b.s[i];
if (x < 0) {g = -1; x += BASE;} else g = 0;
c.s.push_back(x);
}
return c.clean();
}
BigInteger operator * (const BigInteger& b) const {
int i, j; LL g;
vector<LL> v(s.size()+b.s.size(), 0);
BigInteger c; c.s.clear();
for(i=0;i<s.size();i++) for(j=0;j<b.s.size();j++) v[i+j]+=LL(s[i])*b.s[j];
for (i = 0, g = 0; ; i++) {
if (g ==0 && i >= v.size()) break;
LL x = v[i] + g;
c.s.push_back(x % BASE);
g = x / BASE;
}
return c.clean();
}
BigInteger operator / (const BigInteger& b) const {
assert(b > 0); // 除数必须大于0
BigInteger c = *this; // 商:主要是让c.s和(*this).s的vector一样大
BigInteger m; // 余数:初始化为0
for (int i = s.size()-1; i >= 0; i--) {
m = m*BASE + s[i];
c.s[i] = bsearch(b, m);
m -= b*c.s[i];
}
return c.clean();
}
BigInteger operator % (const BigInteger& b) const { //方法与除法相同
BigInteger c = *this;
BigInteger m;
for (int i = s.size()-1; i >= 0; i--) {
m = m*BASE + s[i];
c.s[i] = bsearch(b, m);
m -= b*c.s[i];
}
return m;
}
// 二分法找出满足bx<=m的最大的x
int bsearch(const BigInteger& b, const BigInteger& m) const{
int L = 0, R = BASE-1, x;
while (1) {
x = (L+R)>>1;
if (b*x<=m) {if (b*(x+1)>m) return x; else L = x;}
else R = x;
}
}
BigInteger& operator += (const BigInteger& b) {*this = *this + b; return *this;}
BigInteger& operator -= (const BigInteger& b) {*this = *this - b; return *this;}
BigInteger& operator *= (const BigInteger& b) {*this = *this * b; return *this;}
BigInteger& operator /= (const BigInteger& b) {*this = *this / b; return *this;}
BigInteger& operator %= (const BigInteger& b) {*this = *this % b; return *this;}
bool operator < (const BigInteger& b) const {
if (s.size() != b.s.size()) return s.size() < b.s.size();
for (int i = s.size()-1; i >= 0; i--)
if (s[i] != b.s[i]) return s[i] < b.s[i];
return false;
}
bool operator >(const BigInteger& b) const{return b < *this;}
bool operator<=(const BigInteger& b) const{return !(b < *this);}
bool operator>=(const BigInteger& b) const{return !(*this < b);}
bool operator!=(const BigInteger& b) const{return b < *this || *this < b;}
bool operator==(const BigInteger& b) const{return !(b < *this) && !(b > *this);}
};
ostream& operator << (ostream& out, const BigInteger& x) {
out << x.s.back();
for (int i = x.s.size()-2; i >= 0; i--) {
char buf[20];
sprintf(buf, "%08d", x.s[i]);
for (int j = 0; j < strlen(buf); j++) out << buf[j];
}
return out;
}
istream& operator >> (istream& in, BigInteger& x) {
string s;
if (!(in >> s)) return in;
x = s; return in;
}
介绍-1:基本模板 (bign=BigInteger)
说明:注释出现的“[int]”形式,代表这是int类型的变量名或者一个int值。其它[bign]、[char*]同理。
#include <iostream> // 要用cin、cout
#include <string> // 要用string类
#include <cstring> // 要用strlen
#include <cstdio> // 要用sprintf
using namespace std;
const int maxn = 2000; // 大整数的最高位数限制
struct bign{
int d[maxn], len;
// 去掉大数的前导0
void clean() { while(len > 1 && !d[len-1]) len--; }
// 初始化:默认初始化为值0
bign() { memset(d, 0, sizeof(d)); len = 1; }
// 初始化:可以用“bign [bign] = [int];”或“bign [bign]([int]);”
bign(int num) { *this = num; }
// 初始化:可以用“bign [bign] = [char*];”或“bign [bign](char*);”
bign(char* num) { *this = num; }
// 赋值:可以用“[bign] = [char*];”
bign operator = (const char* num){
len = strlen(num);
for(int i = 0; i < len; i++) d[i] = num[len-1-i] - '0';
clean();
return *this;
}
// 赋值:可以用“[bign] = [int];”
bign operator = (int num){
char s[maxn];
sprintf(s, "%d", num);
*this = s;
return *this;
}
// 将int数组存储的值转换为高精度的字符串形式
string str() const{
string res;
for(int i = 0; i < len; i++) res = char(d[i]+'0') + res;
return res;
}
};
// 可以用“cin >> [bign];”的方式输入
istream& operator >> (istream& in, bign& x)
{
string s;
in >> s;
x = s.c_str();
return in;
}
// 可以用“cout << [bign];”的方式输出
ostream& operator << (ostream& out, const bign& x)
{
out << x.str();
return out;
}
不论做哪类高精度运算最好都完整抄录该部分代码,可以让bign类型用起来跟int一样方便。
四个头文件包含了模板中需要用到的数据类型和函数。
常量maxn代表会出现的最大整数位数,这个值定太小会出错,但也不要太大浪费过多内存。
clean在后续的减法、乘法、除法里都要用到。
介绍-2:扩展bign的运算功能
该部分代码包括上面所有重载的运算符:+、-、*、/、%、+=。
模板的减法要注意不能用小数减大数,要算绝对值,可以用(a<b?b-a:a-b)。
虽然重载的运算符两边数据类型都是bign,但因为自动强制转换,所以用“[bign]*[int]”也不会错。
(这在应用中带来了相当大的便利)
这里的除法与C语言中两个整数相除的效果相同,会舍尾取整。且除法里其实包含取余运算了,最后的a就是。
末尾写了个重载“+=”的代码,主要是方便bign类型的使用。读者可以根据自己喜好,
①把“*=”等的重载代码写上方便使用,②或者在使用bign类型中不要用这类运算符。
最后说一下效率问题,因为我的代码可以进行大数对大数的运算,如大数除大数、大数对大数取余,
所以在大数除int、大数对int取余时,效率不及专门功能的函数,这里牺牲效率增加通用性。
介绍-3:扩展bign的比较功能
只要定义了“<”符号,即可用它定义其他所有比较运算符。实际题目中根据需要抄录小于和其它需要的运算符,不必全部写入(虽然到了高级运算,如取余,就环环相扣,很难删除某一部分了),在“介绍-2”中的运算符也是一样,这样在ACM比赛中能加快解题速度。