1.求N!(0 ≤ N ≤ 10000)
当N很大时
C、C++中,最大的数据类型long long只有64位: 2^64=18446744073709551616,也不够
解题方法
- java能直接算:无限大,直到撑爆计算机内存
import java.util.*;
import java.math.*;
public class Main{
public static void main(String[] args){
Scanner input = new Scanner(System.in);
while(input.hasNext()){
int n = input.nextInt();
BigInteger num = BigInteger.ONE;
for(int i=1;i<=n;i++)
num = num.multiply(BigInteger.valueOf(i));
System.out.println(num);
}
}
}
- 也可用C++的大数乘法
- C++中的万进制:用数组存数。从低位到高位,每四位存到一个数组元素中。
连java也处理不了的大数:hdu1061,n = 10^ 9,求n^n的最后一个数字
n = 10^ 9 :即使java能直接算,也会超时。
方案:
(1)数字太大:取模操作。
(2)计算量太大:用快速幂加速。
void multi(int a[],int n)
{
//1.先乘进去
for(int i = 1;i <= a[0];i++)
a[i] *= n;
//2.处理进位
int i;
for(i = 1;i <= a[0];i++){
a[i + 1] += a[i] / R;
a[i] %= R;
}
//3.处理高位进位
while(a[i]){
a[i + 1] = a[i] / R;//高位进位
a[i++] %= R;
a[0]++;
}
}
int main()
{
string s;int n;
while(cin >> n){
int m = s.length();
int a[N] = {1,1},j = 1;
for(int i = 2;i <= n;i++)
multi(a,i);
print(a);
}
return 0;
}
//输出大数a
void print(int a[])
{
printf("%d",a[a[0]]);
//中间的0必须有
for(int i = a[0] - 1;i >= 1;i--)
printf("%04d",a[i]);
cout << endl;
}
2.
高精度数的存储,用字符串读入
void init(int a[])
{
string s;
cin>>s;//读入字符串s
a[0]=s.length();
//用a[0]计算字符串s的位数
for(i=1;i<=a[0];i++)
a[i]=s[a[0]-i]-'0';
//将数串s转换为数组a,并倒序存储.
}
计算结果位数的确定
- 高精度加法: 两数之和的位数最大为较大数的位数加1;
- 高精度减法: 两数之差的位数最大为较大数的位数;
- 高精度乘法: 两数乘积的位数最大为两个因子的位数和
- 阶乘和乘方: 可利用对数运算来确定,2 ^ p的位数为:[log10(2^p)+1]=[p*ln2/ln10]+1
- 高精度除法: 两数相除的位数最大为较大数的位数减较小的位数加1
高精度数比较
比较数组a和b的大小关系,若a>b返回1,a<b返回-1,a=b返回0
int compare (int a[],int b[])
{
if (a[0]>b[0]) return 1;//a的位数大于b则a比b大
if (a[0]<b[0]) return -1;//a的位数小于b则a比b小
for(int i=a[0];i>0;i--) //从高位到低位比较
{
if (a[i]>b[i]) return 1;
if (a[i]<b[i]) return -1;
}
return 0;//各位都相等则两数相等。
}
高精度结果的输出
void print(int a[ ]) //打印输出
{
int i;
if (a[0]==0){
cout<<0<<endl;return;
}
for(i=a[0];i>0;i--)
cout<<a[i];
cout<<endl;
return ;
}
3.高精度加法
模拟手算
10进制
void jia(int a[],int b[]) //计算a=a+b
{
int i,k;
if(a[0]<b[0]) a[0]=b[0]; //确定加法最大位数
for(i=1;i<=a[0];i++)
a[i]+=b[i]; //逐位相加
for(i=1;i<=a[0];i++) //处理进位
{
a[i+1]+=a[i]/10;
a[i]%=10;
}
if(a[a[0]+1]>0) a[0]++;
//修正新的a的位数(a+b最多只能的一个进位)
}
N进制运算
1、当前位规范由%10改为% n
2、进位处理由/10改为/n
3、其他运算规则不变
4.高精度减法
void jian(int a[],int b[])//计算a=a-b
{
int flag,i;
flag=compare(a,b); //调用比较函数判断大小
if (flag==0) {
a[0]=0;
return;
}
//相等
for(i=1;i<=a[0];i++) {
if(a[i]<b[i]){
a[i+1]--;
a[i]+=10;
} //若不够减则向上借一位
a[i]=a[i]-b[i];
}
while(a[a[0]]==0)
a[0]--; //修正a的位数
return;
}
5.乘法运算
高精度数组a乘整数i
int chengshu(int a[],int k) //a=a*k,k是单精度数
{
int i;
if(k==0){
for(i=0;i<=101;i++)
a[i]=0;
a[0]=0;
return 0;
} //处理k=0
for(i=1;i<=a[0];i++)
a[i]=a[i]*k;//先每位乘起来
for(i=1;i<=a[0];i++) //处理进位
{
a[i+1]+=a[i]/10;
a[i]%=10;
}
while(a[a[0]+1]>0)//处理最高位相乘的进位
{
a[0]++;
a[a[0]+1]=a[a[0]]/10;
a[a[0]]=a[a[0]]%10;
}
return 0;
}
两个高精度数组相乘
#include<iostream>
using namespace std;
int a[101]={0},b[101]={0},c[101]={0};
void init(int a[])
{
int i;
string s;
cin>>s;
a[0]=s.length();
for(i=1;i<=a[0];i++)
a[i]=s[a[0]-i]-'0';
}
void print(int a[])
{
int i;
if (a[0]==0){
cout<<0<<endl;
return;
}
for(i=a[0];i>0;i--)
cout<<a[i];
cout<<endl;
return ;
}
void cheng (int a[],int b[],int c[])
{
int i,j,len;
for (i=1;i<=a[0];i++)
for (j=1;j<=b[0];j++)
c[i+j-1]+=a[i]*b[j];
c[0]=a[0]+b[0];
for(i=1;i<=c[0];i++)
{
c[i+1]+=c[i]/10;
c[i]%=10;
}
while(c[0]>0&&c[c[0]]==0)
c[0]--;
return ;
}
int main()
{
init(a);init(b);
cheng(a,b,c);
print(c);
return 0;
}
6.除法运算
整数数组除以整数(a←a/b,a为整数数组,b为整数)
void chushu(int a[],int b,int c[],int d)//c=a/b,d=a%b
{
int i;
d=0; //余数初始化
for(i=a[0];i>=1;i--)//按照由高位到底位的顺序,逐位相除
{
d=d*10+a[i]; //接受了来自第i+1位的余数
c[i]=d/b; //计算商的第i位
d=d%b;//计算第i位的余数
}
c[0]=a[0];
while(c[0]>0&&c[c[0]]==0)
c[0]--;//计算商的有效位数
return ;
}
高精度除法x←x/y(被除数x和除数y为整数)
void chu(int a[],int b[],int c[])
{
int i,j,tmp[101];
c[0]=a[0]-b[0]+1;
for (i=c[0];i>0;i--)
{
memset(tmp,0,sizeof(tmp));//数组清零
numcpy(b,tmp,i); //将b拷贝到tmp的第i位,其余位是0
while(compare(a,tmp)>=0){c[i]++;jian(a,tmp);}
//用减法来模拟
}
while(c[0]>0&&c[c[0]]==0)
c[0]--;
return ;
}