#include<stdio.h>
#include<iostream>
using namespace std;
#define NUM 700 //所要计算的数字的位数
/**
* Time:201503281307
* Use to deal with Long numbers.
*/
class BigDecimal{
private:
static int min(int a,int b){//获取两数中的最小值
return a^((a^b) & -(a>b));
}
public:
int r[NUM];//大数字
int bit;//最高位在数组所在的位置
/**
* r[NUM] ← 0
* 0 0 0 …… 0 1
* bit=NUM-1
*/
BigDecimal(){
memset(r,0,sizeof(r));
r[NUM-1]=1;
bit=NUM-1;
}
/**
* int To BigDecimal
* Maxint=2147483647
*/
/**
* if n = 0
* The last of number r = 0
* bit = The last index of number r
* return
* i ← The last index of number r
* while n != 0
* r[i] ← n % 10
* i ← i - 1
* n ← n / 10
* bit = The first index of number r
*/
void assign(int n){
if(n==0){//如果赋值为0
r[NUM-1]=0;//最后一位变0
bit=NUM-1;//最高位指向最后一位
return;
}
int i=NUM-1;//指向最后一位
while(n){//如果n不为0
r[i--]=n%10;//取n的个位数
n/=10;//消去n的个位数
}
bit=i+1;//bit指向最高位
}
/**
* int[] to BigDecimal
*/
void assign(int a[],int n){
int j=NUM-1;//指向最后一位
for(;--n>=0;){//从右到左遍历数组a
r[j--]=a[n];//从右到左给数组r赋值
}
bit=j+1;//最高位
}
void display(){
int i=bit-1;
for(;++i<NUM-1;){
printf("%d",r[i]);
}printf("%d\n",r[NUM-1]);
cout<<"该数总共有"<<NUM-bit<<"位"<<endl;
}
/**
* minBit 用于存储两个数中最高位所在的位置
* i 用于向前推进
* temp 用于存储个位和进位
*/
/**
* minBit ← The first index of the longer number
* i ← The last index of number r
* temp ← 0
* for i from NUM-1 to minBit (NUM-1 > minBit)
* temp ← temp + r[i] + _A.r[i]
* sum.r[i] ← temp % 10
* temp ← temp / 10
* while temp != 0
* sum.r[i] ← temp % 10
* i ← i-1
* temp ← temp / 10
* sum.bit ← i+1
* return sum;
*/
BigDecimal operator+(BigDecimal _A){
BigDecimal sum;//存储结果的变量,用于返回值
int minBit=min(bit,_A.bit),i=NUM-1,temp=0;//minBit获取两个加数中的最长数。
if(minBit<=0){
printf("结果位数太大,超出数组长度,请修改NUM的大小。\n");
exit(0);
}
for(;i>=minBit;i--){// minBit ← NUM-1
temp+=r[i]+_A.r[i];//单位与进位相加
sum.r[i]=temp%10;//该位相加取个位数
temp/=10;//进位
}
while(temp){//最后如果进位不为0
sum.r[i--]=temp%10;//获取进位的个位
temp/=10;//除去temp的个位
}
sum.bit=i+1;
return sum;
}
/**
* minBit 被加数的最高位 和 加数的最高位左移S位 取两者最小
* i 左移S位后 那S位不用相加
* temp 存储进位
*/
/**
* minBit ← The smaller number between bit and _A.bit-S
* i ← NUM-1-S
* temp ← 0
* for i ← from NUM-1-S to minBit (NUM-1-S > minBit)
* temp ← temp + r[i] + _A.r[i+S]
* r[i] ← temp % 10
* temp ← temp / 10
* while temp != 0
* r[i] = r[i] + temp % 10
* temp = temp / 10;
* bit = i + 1;
*/
void add(BigDecimal _A,int S){//错开S位相加,用于乘法的时候数字移位相加
int minBit=min(bit,_A.bit-S),i=NUM-1-S,temp=0;//使用的是移位相加,所以this % 10 * _A的最高位需要挪S格。
if(minBit<=0){
printf("结果位数太大,超出数组长度,请修改NUM的大小。\n");
exit(0);
}
for(;i>=minBit;i--){
temp+=r[i]+_A.r[i+S];
r[i]=temp%10;//该位相加取最后一位数
temp/=10;//进位
}
while(temp){
r[i--]+=temp%10;
temp/=10;
}
bit=i+1;
}
/**
* n 跟 BigDecimal每一位都乘以一遍,然后结果取个位,其余的数字进位
*/
/**
* if n==0
* sum.bit ← NUM -1
* all of sum.r ← 0
* return sum;
* i ← NUM - 1
* temp ← 0
* for i ← NUM-1 to bit (NUM-1 > bit)
* temp ← temp + r[i] * n
* sum.r[i] ← temp % 10
* temp ← temp / 10
* while temp !=0
* sum.r[i] ← temp % 10
* i ← i - 1
* temp ← temp / 10
* sum.bit ← i + 1
*/
BigDecimal operator *(int n){
BigDecimal sum;
//当乘以0的时候
if(n==0){
sum.bit=NUM-1;
memset(sum.r,0,sizeof(sum.r));
return sum;
}
int i=NUM-1,temp=0;
/**
* 乘数的每一位 乘以 被乘数(int),获取个位,进位赋给temp
*/
for(;i>=bit;i--){
temp+=r[i]*n;
sum.r[i]=temp%10;
temp/=10;
}
/**
* 如果进位有剩余就放在结果的最前面
*/
while(temp){
sum.r[i--]=temp%10;
temp/=10;
}
sum.bit=i+1;
return sum;
}
/**
* 乘数 与 被乘数的每一位相乘,然后移位相加
*/
/**
* sum.r[NUM-1] ← 0
* i ← bit - 1
* j ← NUM - 1
* while i != j
* temp ← _A * r[j]
* sum ← sum + temp * 10^(NUM-1-j)
* j ← j - 1
* return sum
*/
BigDecimal operator *(BigDecimal _A){//_A 0 this
BigDecimal sum,temp;
sum.r[NUM-1]=0;
int i=bit-1,j=NUM-1;//i为乘数的最高位的左边一位,j用于访问乘数的每一位
while(i!=j){
temp=_A*r[j];//乘数与被乘数的其中一位相乘,然后赋给temp
sum.add(temp,NUM-1-j);//每执行加法运算一次,下一次就左移一格
j--;
}
return sum;
}
/**
* temp的值为0或-1,表示是否向高位借1
*/
/**
* minBit ← The smaller number between bit and _A.bit
* temp ← 0
* i ← NUM
* for i ← NUM-1 to minBit (NUM-1 > minBit)
* if r[i] (+0 or -1) >= _A.r[i]
* sum.r[i] = r[i] +0 or -1 - _A.r[i]
* temp ← 0
* else
* sum.r[i] = r[i] + 10 (+0 or -1) -_A.r[i]
* temp ← -1
* if The first index of r 's value = 0
* sum.bit ← minBit + 1
* else
* sum.bit ← minBit
*/
BigDecimal operator -(BigDecimal _A){//减法,用于大整数乘法
BigDecimal sum;
int minBit=min(bit,_A.bit),temp=0;//获取两个数字中最长的数字,获取它最高位所在下标
int i=NUM;//用于遍历被减数
for(;--i>=minBit;){
if(r[i]+temp>=_A.r[i]){//如果这一位(-1 或 +0后)比被减数要大
sum.r[i]=r[i]+temp-_A.r[i];//得到这一位减后的值
temp=0;//不用向高位借1
}
else//否则
{
sum.r[i]=r[i]+10+temp-_A.r[i];//加10后再减
temp=-1;//向高位借1
}
}
if(minBit!=NUM-1 && sum.r[minBit]==0){//如果最高位不为NUM-1 且其值为0
sum.bit=minBit+1;//最高位右移
}
else{
sum.bit=minBit;//最高位不变
}
return sum;
}
/**
* 获取 BigDecimal中 S坐标到E坐标 的子串
*/
/**
* if S > E return
* num ← E - S + 1
* i ← NUM - 1
* for E to S
* sum.r[i--] ← r[E]
* sum.bit ← i + 1
* while the first index of r's value = 0
* sum.bit ← sum.bit + 1
* return sum
*/
BigDecimal sub(int S,int E){
if(S>E)return BigDecimal();
BigDecimal sum;
int num=E-S+1,i=NUM-1;
for(;E>=S;E--){//获取E到S的子串
sum.r[i--]=r[E];
}
sum.bit=i+1;
while(sum.bit!=NUM-1 && !sum.r[sum.bit]){//如果最高位为0
sum.bit++;//最高位右移
}
return sum;
}
/**
* 10^n
*/
static BigDecimal Ten(int n){
BigDecimal sum;
sum.r[NUM-1]=0;
sum.r[NUM-n-1]=1;//第NUM-n-1位赋值为1
sum.bit=NUM-n-1;//把该位设为最高位
return sum;
}
/**
* 大整数乘法
* 使用该函数不宜将NUM设为1000以上,内存占用太多导致弹框
*/
BigDecimal static mul(BigDecimal a,BigDecimal b){
int n=min(NUM-a.bit,NUM-b.bit);
if(n<=1)return a*b;
if(n<=0){
printf("结果位数太大,超出数组长度,请修改NUM的大小。\n");
exit(0);
}
BigDecimal a1=a.sub(a.bit,NUM-n/2-1),//获取a数字前半段
a0=a.sub(NUM-n/2,NUM-1),//获取a数字后半段
b1=b.sub(b.bit,NUM-n/2-1),//获取b数字前半段
b0=b.sub(NUM-n/2,NUM-1),//获取b数字后半段
c2=mul(a1,b1),//a数字前半段 乘以 b数字前半段
c0=mul(a0,b0),//a数字后半段 乘以 b数字后半段
c1=mul(a1+a0,b1+b0)-(c2+c0);
return c2*Ten(n/2*2)+c1*Ten(n/2)+c0;
}
};
class Power{
private:
int a;
int n;
int sum;
BigDecimal r;
/**
* 数字为600位以下的时候使用移位相乘法,600位以上的时候使用大整数乘法
*/
BigDecimal Cal_MOVEANDCUT(int nn){
if(nn>1){
BigDecimal a=Cal_MOVEANDCUT(nn/2);
BigDecimal b=Cal_MOVEANDCUT(nn-nn/2);
if(NUM-a.bit>=600 || NUM-b.bit>=600){
return BigDecimal::mul(a,b);
}
else{
return a*b;
}
}
return r;
}
/**
* 左移相加法,分治求a^n
*/
BigDecimal Cal_MOVE(int nn){
if(nn>1){
return Cal_MOVE(nn/2)*Cal_MOVE(nn-nn/2);
}
return r;
}
/**
* 折半求积法,分治求a^n
*/
BigDecimal Cal_CUT(int nn){
if(nn>1){
return BigDecimal::mul(Cal_CUT(nn/2),Cal_CUT(nn-nn/2));
}
return r;
}
public:
Power(int a,int n){
this->a=a;
this->n=n;
r.assign(a);
sum=0;
}
void set(int a,int n){
this->a=a;
this->n=n;
r.assign(a);
}
/**
* 大整数乘法
*/
BigDecimal Cal_CUT(){
try{
if(n==0 && a!=0)return BigDecimal();
if(n==0 && a==0)throw 1;
if(n<0 || a<=0)throw 2;
if(n==1)return r;
if(a==1)return BigDecimal();
return BigDecimal::mul(Cal_CUT(n/2),Cal_CUT(n-n/2));
}
catch(int message){
switch(message){
case 1:
printf("0 ^ 0 is undefined!\n");break;
case 2:
printf("Minus's exponentation is undefined\n");break;
}
return BigDecimal();
}
}
/**
* 左移相加法
*/
BigDecimal Cal_MOVE(){
try{
if(n==0 && a!=0)return BigDecimal();
if(n==0 && a==0)throw 1;
if(n<0 || a<=0)throw 2;
if(n==1)return r;
if(a==1)return BigDecimal();
return Cal_MOVE(n/2)*Cal_MOVE(n-n/2);
}
catch(int message){
switch(message){
case 1:
printf("0 ^ 0 is undefined!\n");break;
case 2:
printf("Minus's exponentation is undefined\n");break;
}
return BigDecimal();
}
}
/*
* 左移相加法与折半求积法一同使用
*/
BigDecimal Cal_MOVEANDCUT(){
try{
if(n==0 && a!=0)return BigDecimal();
if(n==0 && a==0)throw 1;
if(n<0 || a<=0)throw 2;
if(n==1)return r;
if(a==1)return BigDecimal();
return Cal_MOVEANDCUT(n/2)*Cal_MOVEANDCUT(n-n/2);
}
catch(int message){
switch(message){
case 1:
printf("0 ^ 0 is undefined!\n");break;
case 2:
printf("Minus's exponentation is undefined\n");break;
}
return BigDecimal();
}
}
};
int main(){
int a,n;
printf("a = ");
scanf("%d",&a);
printf("n = ");
scanf("%d",&n);
Power p(a,n);
BigDecimal b;
b=p.Cal_MOVE();
b.display();
return 0;
}
【算法与设计分析基础】大整数乘法int[]版+分治法求幂
原文作者:大整数乘法问题
原文地址: https://blog.csdn.net/u013580497/article/details/46839357
本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
原文地址: https://blog.csdn.net/u013580497/article/details/46839357
本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。