i信息学奥赛

加入QQ群:1025629106,或关注微信公众号:i信息学奥赛,获取更多学习资源。

导航

高精度

Posted on 2019-03-03 08:00  shnoip  阅读(737)  评论(1编辑  收藏  举报

高精度加法:

#include<iostream>
#include<cstring>
using namespace std;
string sa,sb;
int a[100],b[100],c[100],lena,lenb,lenc,jw;
int main() {
  cin>>sa;
  cin>>sb;  //读入数字a和b,将其存入字符串sa和sb中
  lena=sa.size();
  lenb=sb.size(); //求出2个数字的位数长度
  lenc=lena;
  if (lenb>lena) lenc=lenb;  //lenc存放a、b中较大位数长度
  for (int i=0;i<lena;i++) a[i]=sa[lena-i-1]-48;
  for (int i=0;i<lenb;i++) b[i]=sb[lenb-i-1]-48;
  //将字符串中的存储的数字字符转换为数字逆序存于a、b数组中
  for (int i=0;i<lenc;i++) {
    jw=jw+a[i]+b[i];
    c[i]=jw%10;
    jw=jw/10;
  }  //按位做加法,若有进位存于jw变量中
  if (jw>0) c[lenc]=jw,lenc++;  //若最高位有进位
  for (int i=lenc-1;i>=0;i--) cout<<c[i];  //输出答案
  return 0;
}

高精度减法:

#include<iostream>
#include<cstring>
using namespace std;
string sa,sb,t;
int a[100],b[100],c[100],lena,lenb;
int main() {
  cin>>sa;
  cin>>sb;
  lena=sa.size();
  lenb=sb.size();
  if (lena<lenb || lena==lenb && sa<sb) t=sa,sa=sb,sb=t,cout<<'-';  //若a<b,先交换a、b的值,再输出负号

  //若a、b位数相等可以直接字符串比较大小,若位数不等可通过位数来比较大小
  lena=sa.size();
  lenb=sb.size();
  for (int i=0;i<lena;i++) a[i]=sa[lena-i-1]-48;
  for (int i=0;i<lenb;i++) b[i]=sb[lenb-i-1]-48;
    
  for (int i=0;i<lena;i++) {
    c[i]=a[i]-b[i];
    if (c[i]<0) c[i]+=10,a[i+1]--;  //若不够减,向上借位
  }
  while (!c[lena-1] && lena>1) lena--;  //去除前导零,需注意答案为零的情况
  for (int i=lena-1;i>=0;i--) cout<<c[i];  //输出答案
  return 0;
}

高精度乘法:

#include<iostream>
#include<cstring>
using namespace std;
string sa,sb;
int a[100],b[100],c[100],lena,lenb,lenc;
int main() {
  cin>>sa;
  cin>>sb;  //读入数字a和b,将其存入字符串sa和sb中
  lena=sa.size();
  lenb=sb.size(); //求出2个数字的位数长度
  for (int i=1;i<=lena;i++) a[i]=sa[lena-i]-48;
  for (int i=1;i<=lenb;i++) b[i]=sb[lenb-i]-48;
  //将字符串中的存储的数字字符转换为数字逆序存于a、b数组中
  //a、b数组是从第1格开始存储,方便后续计算
  for (int i=1;i<=lena;i++)
    for (int j=1;j<=lenb;j++) {
      c[i+j-1]+=a[i]*b[j];
      c[i+j]+=c[i+j-1]/10;
      c[i+j-1]%=10;
    }
  lenc=lena+lenb;  
  while (c[lenc]==0 && lenc>1) lenc--;
  //从高位开始找非零值,确定乘积的位数
  for (int i=lenc;i>0;i--) cout<<c[i];  //输出答案
  return 0;
}

高精度乘方:
计算 x 的 n 次方
#include<iostream>
#include<cmath>
using namespace std;
int x,n,lx,s[100],len,jw,t;
int main() {
  cin>>x>>n;
  lx=floor(log(x)/log(10))+1;  //计算x的位数
  s[1]=1;
  for (int i=0;i<n;i++) {
    len+=lx;
    jw=0;
    for (int j=1;j<=len;j++)
      t=s[j]*x+jw,jw=t/10,s[j]=t%10;
  }
  t=floor(n*log(x)/log(10))+1;  //计算答案的位数
  for (int i=t;i>0;i--) cout<<s[i];
  return 0;
}

高精度乘方(快速幂):
计算 x 的 n 次方
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int x,n,a[100],b[100],len;
void ksm(int p) {
  if (p==0) return;
  ksm(p/2);
  for (int i=1;i<=len;i++)
    for (int j=1;j<=len;j++)
      if (p%2==1) b[i+j-1]+=a[i]*a[j]*x;
      else b[i+j-1]+=a[i]*a[j];
  for (int i=1;i<=len;i++) {
    b[i+1]+=b[i]/10;
    a[i]=b[i]%10;
  }
  memset(b,0,sizeof(b));
}
int main() {
  cin>>x>>n;
  len=floor(n*log(x)/log(10)+1);  //floor(n*log10(x)+1)也可
  a[1]=1;
  ksm(n);
  for (int i=len;i>0;i--)
    cout<<a[i];
  return 0;
}

 高精度实数加法:
#include<iostream>
#include<cstring>
using namespace std;
string s1,s2;
int zs1,xs1,zs2,xs2,len,a[100],b[100],zs,xs;
int main() {
  cin>>s1>>s2;
  //根据有没有小数点,区分整数和实数二种情况
  //分别计算整数部分位数和小数部分位数,并删除小数点  
  if (s1.find(".")==string::npos) zs1=s1.size();
  else zs1=s1.find("."),xs1=s1.size()-zs1-1,s1.erase(zs1,1);
  if (s2.find(".")==string::npos) zs2=s2.size();
  else zs2=s2.find("."),xs2=s2.size()-zs2-1,s2.erase(zs2,1);
  //对于整数位数较小的数,前面补零,使其整数部分位数与另一个数相等
  //对于小数位数较小的数,后面补零,使其小数部分位数与另一个数相等
  if (zs1<zs2) for (int i=1;i<=zs2-zs1;i++) s1="0"+s1;
  else for (int i=1;i<=zs1-zs2;i++) s2="0"+s2;
  if (xs1<xs2) for (int i=1;i<=xs2-xs1;i++) s1=s1+"0";
  else for (int i=1;i<=xs1-xs2;i++) s2=s2+"0";
  //cout<<s1<<endl<<s2<<endl;
  if (zs1>zs2) zs=zs1;
  else zs=zs2;
  if (xs1>xs2) xs=xs1;
  else xs=xs2;
  len=zs+xs;  //当前字串长度
  //将2个字串逆序反转存于a、b数组中
  for (int i=1;i<=len;i++) a[i]=s1[i-1]-48;
  for (int i=1;i<=len;i++) b[i]=s2[i-1]-48;
  //高精加,并加结果存于a数组中
  for (int i=len;i>0;i--) a[i]+=b[i],a[i-1]+=a[i]/10,a[i]%=10;
  while (a[len]==0 && len>zs) len--;  //删除小数部分后缀零
  if (a[0]) cout<<a[0];  //若最高位有进位
  for (int i=1;i<=zs;i++) cout<<a[i];  //输出整数部分
  if (len>zs) {  //若进位后小数部分有非零值
    cout<<'.';
    for (int i=zs+1;i<=len;i++) cout<<a[i];
  }
  return 0;
}

高精度除法:

#include<iostream>
#include<algorithm>
using namespace std;
string sa,sb;
int a[100],b[100],c[100],ans[100];
bool big() {
  if (c[0]>b[0]) return true;
  if (c[0]<b[0]) return false;
  for (int i=c[0];i>=1;i--)
    if (c[i]>b[i]) return true;
    else if (c[i]<b[i]) return false;
  return true;  //相等的情况
}
void jian() {
  int jw=0;  //借位
  for (int i=1;i<=c[0];i++) {
    c[i]-=b[i]+jw;
    if (c[i]<0) c[i]+=10,jw=1;
    else jw=0;
  }
  while (c[0]>1 && c[c[0]]==0) c[0]--;
}
int main() {
  cin>>sa;  //读入第1个数,将其反转存于a数组中
  a[0]=sa.size();
  for (int i=1;i<=a[0];i++) a[i]=sa[i-1]-48;
  reverse(a+1,a+1+a[0]);
  cin>>sb;  //读入第2个数,将其反转存于b数组中
  b[0]=sb.size();
  for (int i=1;i<=b[0];i++) b[i]=sb[i-1]-48;
  reverse(b+1,b+1+b[0]);
//按竖式除法原理,构造c数组,只要够减,就不断c-b
  for (int i=a[0];i>=1;i--) {
    for (int j=c[0];j>=1;j--) c[j+1]=c[j];
    c[1]=a[i];
    if  (c[c[0]+1]>0) c[0]++;
    while (big()) jian(),ans[i]++;
  }
  ans[0]=a[0];
  while (ans[0]>1 && ans[ans[0]]==0) ans[0]--;
  for (int i=ans[0];i>=1;i--) cout<<ans[i];  //输出商
  cout<<endl;
  for (int i=c[0];i>=1;i--) cout<<c[i];  //输出余数
  return 0;
}

大整数开方:
输入一个正整数 n,用二分法计算它的平方根的整数部分。

/*简版代码
#include<iostream>
using namespace std;
int target,z,mid,y;
int main() {
  cin>>target;
  z=1;
  y=target;
  while (y-z>1) {
    mid=(z+y)/2;
    if (mid*mid>target) y=mid;  //大了
    else z=mid;  //小了
  }
  cout<<z;
  return 0;
}
*/
#include<iostream>
#include<cstring>
using namespace std;
struct ds {
  int len,num[100];
};
string s;
ds target,z,mid,y;
ds times(ds a,ds b) {
  ds ans;
  memset(ans.num,0,sizeof(ans.num));
  for (int i=1;i<=a.len;i++)
    for (int j=1;j<=b.len;j++)
      ans.num[i+j-1]+=a.num[i]*b.num[j];
  for (int i=1;i<=a.len+b.len;i++) {
    ans.num[i+1]+=ans.num[i]/10;
    ans.num[i]%=10;
  }
  if (ans.num[a.len+b.len]>0) ans.len=a.len+b.len;
  else ans.len=a.len+b.len-1;
  return ans;
}
ds add(ds a,ds b) {
  ds ans;
  memset(ans.num,0,sizeof(ans.num));
  if (a.len>b.len) ans.len=a.len;
  ans.len=b.len;
  for (int i=1;i<=ans.len;i++) {
    ans.num[i]=a.num[i]+b.num[i];
    ans.num[i+1]+=ans.num[i]/10;
    ans.num[i]%=10;
  }
  if (ans.num[ans.len+1]>0) ans.len++;
  return ans;
}
ds average(ds a,ds b) {
  ds ans;
  ans=add(a,b);
  for (int i=ans.len;i=2;i--) {
    ans.num[i-1]+=ans.num[i]%2*10;
    ans.num[i]/=2;
  }
  ans.num[1]/=2;
  if (ans.num[ans.len]==0) ans.len--;
  return ans;
}
ds plustwo(ds a){
  ds ans;
  ans=a;
  ans.num[1]+=2;
  int i=1;
  while (ans.num[i]>=10) {
    ans.num[i+1]+=ans.num[i]/10;
    ans.num[i]%=10;
    i++;
  }
  if (ans.num[ans.len+1]>0) ans.len++;
  return ans;
}
bool over(ds a,ds b) {  //判断a大于b吗?
  if (a.len<b.len) return false;
  if (a.len>b.len) return true;
  for (int i=a.len;i>=1;i--)
    if (a.num[i]<b.num[i]) return false;
    else if (a.num[i]>b.num[i]) return true;
  return false;  //每个数位都相等
}
int main() {
  cin>>s;
  target.len=s.size();
  for (int i=1;i<=target.len;i++) target.num[i]=s[target.len-i]-48;
  z.len=1;
  z.num[1]=1;
  y=target;
  while (!over(plustwo(z),y)) {
    mid=average(z,y);
    if (over(times(mid,mid),target)) y=mid;  //大了
    else z=mid;  //小了
  }
  for (int i=z.len;i>=1;i--) cout<<z.num[i];
  return 0;
}