/*
Name: 高精度整数运算改进版
Copyright:始发于goal00001111的专栏;允许自由转载,但必须注明作者和出处
Author: goal00001111
Date: 15-12-08 08:18
Description:
高精度整数运算:加减乘除,乘方,阶乘 。
上次写了一个用字符串存储高精度整数的四则运算算法,虽然可以实现功能,但时间复杂度和空间复杂度都不够理想,
这次出了个改进版,将原来的用字符串存储改成用整型数组存储,而且改进了乘法,除法和乘方的算法,更快更高效!
*/
#include<iostream>
#include<string>
using namespace std;
const unsigned int MAX = 10000; //整型数组的最大长度
const long long WIDTHMAX = 1000000000; //整型数组val[MAX]的元素上限
const unsigned int WIDTH = 9; //输出整型数组val[MAX]的元素时的格式宽度,即整型数组val[MAX]的元素的最多位数
typedef struct node
{
long long val[MAX]; //用来存储高精度整数
unsigned int size; //整型数组的实际长度
} BigInt;
BigInt StrToBigInt(string s);
void PrintBigInt(const BigInt & a);
int ComPareBigInt(const BigInt & a, const BigInt & b);
BigInt MulBigInt(const BigInt & a, const BigInt & b);
BigInt AddBigInt(const BigInt & a, const BigInt & b);
BigInt SubBigInt(BigInt a, BigInt b);
BigInt DivBigInt(const BigInt & a, const BigInt & b);
BigInt FacBigInt(unsigned int n);
void PowBigInt(BigInt & c, const BigInt & a, unsigned int n);
void PowBigInt_2(BigInt & c, const BigInt & a, unsigned int n);
BigInt HalfBigInt(BigInt a);
int main()
{
string s;
BigInt a, b, c;
cin >> s;
a = StrToBigInt(s);
cin >> s;
b = StrToBigInt(s);
cout << " ";
PrintBigInt(a);
cout << "+ ";
PrintBigInt(b);
c = AddBigInt(a, b);
cout << "= ";
PrintBigInt(c);
cout << endl;
cout << " ";
PrintBigInt(a);
cout << "- ";
PrintBigInt(b);
c = SubBigInt(a, b);
cout << "= ";
PrintBigInt(c);
cout << endl;
cout << " ";
PrintBigInt(a);
cout << "* ";
PrintBigInt(b);
c = MulBigInt(a, b);
cout << "= ";
PrintBigInt(c);
cout << endl;
cout << " ";
PrintBigInt(a);
cout << "/ 2 " << endl;
c = HalfBigInt(a);
cout << "= ";
PrintBigInt(c);
cout << endl;
cout << " ";
PrintBigInt(a);
cout << "/ ";
PrintBigInt(b);
c = DivBigInt(a, b);
cout << "= ";
PrintBigInt(c);
cout << endl;
unsigned int n;
cin >> n;
//cout << n << "! = ";
// c = FacBigInt(n);
// PrintBigInt(c);
// cout << c.size << endl;
cout << endl;
cout << " ";
PrintBigInt(a);
cout << "^" << n << " = ";
PowBigInt(c, a, n);
PrintBigInt(c);
cout << endl;
cout << " ";
PrintBigInt(a);
cout << "^" << n << " = ";
PowBigInt_2(c, a, n);
PrintBigInt(c);
cout << endl;
system("pause");
return 0;
}
/*
函数名称:PrintBigInt
函数功能:输出用整型数组表示的高精度整数
输入参数:const BigInt & a:用整型数组表示的高精度整数
输出参数:无
*/
void PrintBigInt(const BigInt & a)
{
cout << a.val[a.size-1];
for (int i=a.size-2; i>=0; i--)
{
unsigned w = WIDTHMAX / 10;
while (w > 0)
{
if (a.val[i] >= w)
break;
cout << 0;
w /= 10;
}
cout << a.val[i];
}
cout << endl;
}
/*
函数名称:StrToBigInt
函数功能:把元素为数字的字符串转换为用整型数组表示的高精度整数
输入参数:string s:存储数字的字符串
输出参数:BigInt:返回用整型数组表示的高精度整数
*/
BigInt StrToBigInt(string s)
{
BigInt a;
a.size = 0;
int i = s.size();
unsigned long long sum = 0;
while ( i>=WIDTH)
{
for (int j=i-WIDTH; j<i; j++)
sum = sum * 10 + (s[j] - '0');
a.val[a.size++] = sum;
sum = 0;
i -= WIDTH;
}
if (i > 0)
{
for (int j=0; j<i; j++)
sum = sum * 10 + (s[j] - '0');
a.val[a.size++] = sum;
}
return a;
}
/*
函数名称:AddBigInt
函数功能:高精度整数加法
输入参数:const BigInt & a:用整型数组表示的高精度整数加数
const BigInt & b:用整型数组表示的高精度整数加数
输出参数:BigInt:返回用整型数组表示的高精度整数和
*/
BigInt AddBigInt(const BigInt & a, const BigInt & b)
{
//逆序计算a+b,则从低位开始计算
BigInt c;
unsigned long long carry = 0;
unsigned int i = 0;
c.size = 0;
while (i < a.size && i < b.size)
{
c.val[c.size++] = (a.val[i] + b.val[i] + carry) % WIDTHMAX;
carry = (a.val[i] + b.val[i] + carry) / WIDTHMAX;
i++;
}
while (i < a.size)
{
c.val[c.size++] = (a.val[i] + carry) % WIDTHMAX;
carry = (a.val[i] + carry) / WIDTHMAX;
i++;
}
while (i < b.size)
{
c.val[c.size++] = (b.val[i] + carry) % WIDTHMAX;
carry = (b.val[i] + carry) / WIDTHMAX;
i++;
}
if (carry > 0)
c.val[c.size++] = carry;
return c;
}
/*
函数名称:SubBigInt
函数功能:高精度整数减法
输入参数:BigInt a:用整型数组表示的高精度整数被减数
BigInt b:用整型数组表示的高精度整数减数
输出参数:BigInt:返回用整型数组表示的高精度整数差
*/
BigInt SubBigInt(BigInt a, BigInt b)
{
BigInt c;
c.size = 0;
if (ComPareBigInt(a, b) == 0)
{
c.size = 1;
c.val[0] = 0;
return c;
}
bool flag = false;
if (ComPareBigInt(a, b) < 0)//交换,并得到一个负号
{
flag = true;
BigInt temp = a;
a = b;
b = temp;
}
unsigned int i = 0;
while (i < b.size)
{
if (a.val[i] >= b.val[i])
c.val[c.size++] = a.val[i] - b.val[i];
else
{
a.val[i+1] -= 1;
c.val[c.size++] = a.val[i] + WIDTHMAX - b.val[i];
}
i++;
}
while (i < a.size)
{
if (a.val[i] < 0)
{
a.val[i+1] -= 1;
a.val[i] += WIDTHMAX;
}
c.val[c.size++] = a.val[i];
i++;
}
//消除多余的高位0
while (c.val[c.size-1] == 0)
c.size--;
if (flag)//如果是负数,加上负号
c.val[c.size-1] = -c.val[c.size-1];
return c;
}
/*
函数名称:ComPareBigInt
函数功能:比较两个高精度整数的大小
输入参数:BigInt a:用整型数组表示的高精度整数被减数
BigInt b:用整型数组表示的高精度整数减数
输出参数:int:a > b返回1,a = b返回0,a < b返回-1
*/
int ComPareBigInt(const BigInt & a, const BigInt & b)
{
if (a.size > b.size)
return 1;
if (a.size < b.size)
return -1;
for (int i=a.size-1; i>=0; i--)
{
if (a.val[i] > b.val[i])
return 1;
if (a.val[i] < b.val[i])
return -1;
}
return 0;
}
/*
函数名称:MulBigInt
函数功能:高精度整数乘法
输入参数:const BigInt & a:用整型数组表示的高精度整数被乘数
const BigInt & b:用整型数组表示的高精度整数乘数
输出参数:BigInt:返回用整型数组表示的高精度整数乘积
*/
BigInt MulBigInt(const BigInt & a, const BigInt & b)
{
if (a.size == 1 && a.val[0] == 0)
return a;
if (b.size == 1 && b.val[0] == 0)
return b;
BigInt c;
for (int i=0; i<MAX; i++) //全部赋初值为0
c.val[i] = 0;
for (int i=0, j=0; i<b.size; i++)
{
for (j=0; j<a.size; j++)
{
c.val[i+j] += a.val[j] * b.val[i];
c.val[i+j+1] += c.val[i+j] / WIDTHMAX;
c.val[i+j] %= WIDTHMAX;
}
c.size = i + j;
if (c.val[c.size] != 0)//最高位有进位
c.size++;
}
return c;
}
/*
老版本:
BigInt MulBigInt2(const BigInt & a, const BigInt & b)
{
if (a.size == 1 && a.val[0] == 0)
return a;
if (b.size == 1 && b.val[0] == 0)
return b;
BigInt c, tc;
unsigned long long carry = 0;
c.size = 0;
for (int i=0, j=0; i<b.size; i++)
{
for (j=0; j<i; j++)//先在临时和tc的低位补足0
tc.val[j] = 0;
carry = 0;
for (j=0; j<a.size; j++)
{
tc.val[i+j] = (a.val[j] * b.val[i] + carry) % WIDTHMAX;
carry = (a.val[j] * b.val[i] + carry) / WIDTHMAX;
}
tc.size = i + j;
if (carry > 0)
tc.val[tc.size++] = carry;
//累加到c中
c = AddBigInt(tc, c);
}
return c;
}
*/
/*
函数名称:FacBigInt
函数功能:高精度整数阶乘
输入参数:unsigned int n:正整数
输出参数:BigInt:返回用整型数组表示的高精度整数阶乘
*/
BigInt FacBigInt(unsigned int n)
{
BigInt s, c;
c.size = s.size = 1;
s.val[0] = 1;
for (unsigned long long i=2; i<=n; i++)
{
c.val[0] = i;
s = MulBigInt(s, c);
}
return s;
}
/*
函数名称:PowBigInt
函数功能:递归高效算法求高精度整数幂
输入参数:BigInt & c:存储高精度整数幂的整型数组
const BigInt & a:用整型数组表示的高精度整数底数
long long n: 指数
*/
void PowBigInt(BigInt & c, const BigInt & a, unsigned int n)
{
if (n == 1)
{
c = a;
return ;
}
if (n == 0 || (a.size == 1 && a.val[0] == 1))
{
c.size = c.val[0] = 1;
return ;
}
PowBigInt(c, a, n/2); //递归求高精度整数幂
c = MulBigInt(c, c); //a^n = a^(n/2)*a^(n/2)*f(a)
if (n % 2 == 1) //其中f(a) = 1(n%2==0)或f(a) = a(n%2==1)
c = MulBigInt(a, c);
}
/*
函数名称:PowBigInt_2
函数功能:非递归高效算法求高精度整数幂
输入参数:BigInt & c:存储高精度整数幂的整型数组
const BigInt & a:用整型数组表示的高精度整数底数
long long n: 指数
*/
void PowBigInt_2(BigInt & c, const BigInt & a, unsigned int n)
{
int stack[MAX] = {0};
int top = 0;
while (n > 0) //利用一个栈来存储n的状态:奇数还是偶数
{
stack[top++] = n % 2;
n /= 2;
}
c.size = c.val[0] = 1;
for (int i=top-1; i>=0; i--)
{
c = MulBigInt(c, c); //a^n = a^(n/2)*a^(n/2)*f(a)
if (stack[i] == 1) //其中f(a) = 1(n%2==0)或f(a) = a(n%2==1)
c = MulBigInt(a, c);
}
}
/*
函数名称:DivBigInt
函数功能:二分法实现高精度整数除法
输入参数:const BigInt & a:用整型数组表示的高精度整数被除数
const BigInt & b:用整型数组表示的高精度整数除数
输出参数:BigInt:返回用整型数组表示的高精度整数商
*/
BigInt DivBigInt(const BigInt & a, const BigInt & b)
{
BigInt high, low, mid, one, c;
if ((a.size == 1 && a.val[0] == 0) || (b.size == 1 && b.val[0] == 0))
{
c.size = 1;
c.val[0] = 0;
return c;
}
one.size = 1; //值为1的高精度整数
one.val[0] = 1;
high = a; //上界
low.size = 1; //下界
low.val[0] = 0;
while (ComPareBigInt(low, high) < 0)
{
mid = HalfBigInt(AddBigInt(high, low)); //中间数
c = MulBigInt(mid, b);
if (ComPareBigInt(c, a) == 0)
return mid;
else if (ComPareBigInt(c, a) < 0)
low = AddBigInt(mid, one);
else
high = SubBigInt(mid, one);
}
c = MulBigInt(low, b);
if (ComPareBigInt(c, a) <= 0)
return low;
else
return SubBigInt(low, one);
}
/*
函数名称:HalfBigInt
函数功能:高精度整数求半
输入参数:BigInt a:用整型数组表示的高精度整数
输出参数:BigInt:返回用整型数组表示的高精度整数的一半
*/
BigInt HalfBigInt(BigInt a)
{
BigInt c;
c.size = a.size;
for (int i=a.size-1; i>0; i--)
{
c.val[i] = a.val[i] / 2;
if (a.val[i] % 2 == 1)
a.val[i-1] += WIDTHMAX;
}
c.val[0] = a.val[0] / 2;
if (c.size > 0 && c.val[c.size-1] == 0)
c.size--;
return c;
}