高精度计算 大数相乘+模拟

当数字过大,会存在超过范围而导致无法做运算,所以采取字符串的方法去模拟
,模拟手动做运算的过程。
在32位编译器下
1个字节8位

int 4个字节
long 4 个字节
long long 8个字节
_int64 8个字节
double 8个字节
long double 12个字节
unsigned int 4个字节
unsigned long 8个字节

问题 A: 大数相加

题目描述
计算A+B
输入
连续输入
输入字符串A和B
A和B分别代表一个正整数(保证A和B不超过5*106位)
输出
输出A+B
样例输入
2222222222222222222222
1111111111111111111111111
样例输出
1113333333333333333333333

#include <cstring>//c++ 版
#include <iostream>
#include <algorithm>
using namespace std;
string ans;
string num_push(string a,string b){
	ans.clear();
  int lena=a.size();
  int lenb=b.size();
  reverse(a.begin(),a.end());  //翻转a
  reverse(b.begin(),b.end());  //翻转b
  int yu=0;  //余数
  for(int i=0;;i++){    //一直跑
    if(i<lena&&i<lenb){    //如果小于a的长度,并且小于b的长度
      ans+=(yu+a[i]-'0'+b[i]-'0')%10+'0';  //第几位等于a的数值加上b的数值
      yu=(yu+a[i]-'0'+b[i]-'0')/10;  //然后再求余数
    }else if(i<lena){          //如果只小于a,说明b跑完了
      ans+=(yu+a[i]-'0')%10+'0';  //只需加上a的数值加上之前的余数
      yu=(yu+a[i]-'0')/10;  
    }else if(i<lenb){          
      ans+=(yu+b[i]-'0')%10+'0';
      yu=(yu+b[i]-'0')/10;
    }else if(yu!=0){   //都跑完了余数还不为零那么再进一位
      ans+=yu%10+'0';
      yu=yu/10;
    }else break; //然后退出
  }
  reverse(ans.begin(),ans.end());  //最后翻转一下
  return ans;
}
string a,b;
int main(){
  while(cin>>a>>b){
    cout<<num_push(a,b)<<endl;
  }
  return 0;
}

问题 B: 大数相减

题目描述
计算A-B
输入
连续输入
输入字符串A和B
A和B分别代表一个正整数(保证A和B不超过1*105位)
输出
输出A-B
样例输入
222222222222222222222222222
1
样例输出
222222222222222222222222221

#include<bits/stdc++.h>
using namespace std;
const int maxn=100000;
char a[maxn],b[maxn];
char ans[maxn];
char* strrev(char* s)
{
    /* h指向s的头部 */
    char* h = s;
    char* t = s;
    char ch;
    /* t指向s的尾部 */
    while(*t++){};
    t--;    /* 与t++抵消 */
    t--;    /* 回跳过结束符'\0' */
    /* 当h和t未重合时,交换它们所指向的字符 */
    while(h < t)
    {
        ch = *h;
        *h++ = *t;    /* h向尾部移动 */
        *t-- = ch;    /* t向头部移动 */
    }
    return(s);
}

int judge(char *a,char *b){
  int lena=strlen(a);
  int lenb=strlen(b);
  if(lena>lenb) return 1;
  else if(lena<lenb) return -1;
  else return strcmp(a,b);  //相等返回0;
}

char *solve(char *a,char *b){
    char aa[maxn],bb[maxn];
    memset(aa,0,sizeof(aa));  //aa始终存大的
    memset(bb,0,sizeof(bb)); //bb始终存小的
    memset(ans,0,sizeof(ans));  //初始化
    char *as=ans; //定义指针
    bool fuhao=false;  //定义负号
    int cnt=judge(a,b); //判断大小
    if(cnt>0){ //如果a大于b
      strcpy(aa,a);
      strcpy(bb,b);
      fuhao=false;
    }
    else if(cnt<0){
      strcpy(aa,b);
      strcpy(bb,a);
      fuhao=true;
    }
    else {
      ans[0]='0';
      return as;
    }
     int lena=strlen(aa);
     int lenb=strlen(bb);
     strrev(aa);
     strrev(bb);
     int i;
     for(i=0;;i++){
       if(i<lena&&i<lenb){
                if(aa[i]>=bb[i]){
                   ans[i]=aa[i]-bb[i]+'0';
                 }
                else {
                        ans[i]=aa[i]-bb[i]+10+'0';
                           for(int j=i+1;;j++){ //借位
                                 if(aa[j]=='0') aa[j]='9';
                                 else{
                                   aa[j]--;
                                   break;
                                  }
                           }
                }
      }
      else if(i<lena){
          ans[i]=aa[i];
      }else if(i<lenb){
          ans[i]=bb[i];
      }else break;
  }
    while(i--){
        ans[i+1]='\0';  //置为空格
        if(ans[i]-'0'>0)
        break;
    }
      if(fuhao) ans[i+1]='-';  //最后判断是否添加负号
      strrev(ans);
      return as;
}

int main(){
while(~scanf("%s %s", a, b)){
    printf("%s\n", solve(a,b));
  }
  return 0;
}

问题 C: 大数相乘

题目描述
计算A
输入
连续输入
输入字符串A和B
A和B分别代表一个正整数(保证A和B不超过3
104位)
输出
输出A*B
样例输入
22222222222222222222222222 1
样例输出
22222222222222222222222222

#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 100000
int ans[maxn];
string num;
string num_mul(string a,string b){
  memset(ans,0,sizeof ans);
  num.clear();
  int lena=a.size();
  int lenb=b.size();
  reverse(a.begin(),a.end());
  reverse(b.begin(),b.end());
  for(int i=0;i<lena;i++){
    for(int j=0;j<lenb;j++){  //b的每一位乘a的每一位
      ans[i+j]+=(a[i]-'0')*(b[j]-'0');
    }
  }
  int yu=0; //初始余数为0
  int i;
  int len=lena+lenb-1;  //总长度
  for(i=0;;i++){    //转化
    if(i<len||yu!=0){   //小于总长或者还有余数时 
      yu=ans[i]+yu; 
      ans[i]=yu%10; //数值等于模十
      yu=yu/10;  //余数等于除十
    }else break;   
  }
  while(i--){
    num+=ans[i]+'0';
  }
  return num;
}
string a,b;
int main(){
  while(cin>>a>>b){
    cout<<num_mul(a,b)<<endl;
  }
  return 0;
  }

问题 D: 大数相除

题目描述
计算:
A÷B = C
A % B = D
输入
连续输入
输入字符串A和B
A和B分别代表一个正整数(保证A和B不超过1*103位)
输出
A÷B = C (向下取整)
A % B = D
样例输入
22222222222222222222222222 2
样例输出
11111111111111111111111111
0

大数除法的模拟用减法去模拟,除法可以用减法去表示,相减的次数就是除法的值
但是当10000000000/1时就要相减10000000000次,这样就会超时
所以我们做每一位的减法,如300/2=150,百位相减一次,十位相减5次,个位相减0次
那如何对每一位进行相减呢。
比如a/b,先给b末位补零b,直到a和b的长度相等,变为b1,然后用a去减b1,直到a小于b1了,存储相减次数,这时给b1抹去一个0,再做相减,如此循环做上述操作,直到b1变为原来的b
如300/2 ,先给20,补到200和a的长度相等,然后300-200=100100小于200,然后记录相减次数为1,这是抹去一个0,变为100/20,然后做相减操作,100-20等于80,变为80/20,然后再相减变为60/20,再做相减,一直相减直到小于20,最后变为0/200小于20,这时记录相减次数为5次,然后抹去0,变为0/2,从200变为了原来的2,就结束,这时的相减次数为0,所以每一位的相减次数分别为150。得到答案150


#include<bits/stdc++.h>
using namespace std;
 string ans;
 string anss;
 string yu;
int judge(string a,string b){  
  int lena=a.size(); //string 的大小使用size()  字符数组使用strlen()
  int lenb=b.size();
  if(lena>lenb) return 1;   //判断长度,如果a长度大于b,直接返回1
  else if(lena<lenb) return -1;//如果a长度小于b,直接返回-1
  else if(a>b) return 1;
  else if(a<b) return -1;
  else if(a==b) return 0;  //长度一样的情况下。字符串比较
}

string num_mul(string a,string b){
  string aa;  //aa始终存大的
  string bb;  //bb始终存小的
  bool fuhao=false;
  aa.clear();
  bb.clear();
  ans.clear();
  int cnt=judge(a,b);
  if(cnt==1){ //cnt=1说明a比b大
     aa=a;
     bb=b;
     fuhao=false;
  }else if(cnt==-1){
     aa=b;
     bb=a;
     fuhao=true;
  }else{
    ans+='0'; //一样时直接返回0
    return ans;
  }
  reverse(aa.begin(),aa.end());
  reverse(bb.begin(),bb.end());
  int lena=aa.size(); //string 的大小使用size()  字符数组使用strlen()
  int lenb=bb.size();
  int i;
   for(i=0;;i++){
       if(i<lena&&i<lenb){  //如果i即小于a的长度又小于b的长度
            if(aa[i]>=bb[i]){   //如果这一位的数值大于等于这一位,则直接减
               ans+=aa[i]-bb[i]+'0';
            }else{              //如果小于,则需要借位
               ans+=aa[i]-bb[i]+10+'0'; //减了之后加10
               for(int j=i+1;;j++){   //先前借位
                  if(aa[j]=='0') aa[j]='9';  //碰到 0需要再向前借位
                  else{
                    aa[j]--;  //否则只需借的位减一
                    break; //退出借位循环
                  }
               }
            }
       }else if(i<lena){
         ans+=aa[i];
       }else if(i<lenb){
         ans+=bb[i];
       }
       else break;
   }
   while(i--){  //减法后存在前几位翻转后为0的情况所以需要删除
     if(ans[i]-'0'>0)
        break;   //找到位置退出
   }
   ans.erase(i+1,lena-i);  //删除0
   if(fuhao) ans+='-'; //如果为负,加负号
   reverse(ans.begin(),ans.end());
   return ans;
}

string num_div(string a,string b){   //a除b
  anss.clear();
  int lena=a.size();
  int lenb=b.size();
  for(int i=lenb;i<lena;i++)
     b+='0';
  while(lena-->=lenb){  //上下做减法,减到a的长度小于0了,b摸去个0  求的是每一位的减法
    int i=0;  //该位相减次数先置0
    while(judge(a,b)>=0){
      a=num_mul(a,b);
      i++;  //该位相减次数加1
    }
    anss+=(i+'0');  //该位相减次数入anss
    b.erase(lena); //抹去个零  lena有--
  }
  yu=a;
  if(anss.size()==0){
     anss+='0';
     return anss;
   }
   if(anss[0]=='0'){
     anss.erase(0,1);
   }
   return anss;
}

string a,b;
int main(){
    while(cin>>a>>b){
        cout<<num_div(a,b)<<endl;
  			cout<<yu<<endl;
    }
return 0;
}

问题 E: 计算N!

题目描述
给定一个整数N( 0 <= N <= 10000),你的任务是计算它的阶乘。
输入
输入包含多组测试样例,每组测试样例包含一个整数n。
输出
对于每个N,输出N的阶乘。
样例输入
1
2
3
样例输出
1
2
6

首先题目给出n最大为10000,这做阶乘肯定会爆掉,所以用字符串去模拟

      ans(ans存结果)string类型
n=1   1
n=2   22去乘前面的结果
n=3   63去乘前面的结果
n=4   4 24去乘前面的结果(4624,先存4,然后有进位2,再加一位存2)
以此类推


#include<bits/stdc++.h>
using namespace std;
const int maxn=1000000;
int tot,ans[maxn];

int main(){
  int n;
  while(cin>>n){
    memset(ans,0,sizeof(ans));
    ans[0]=1;
    tot=1;//进位位置
    int now,cnt;//now为要存放的位置cnt为进位
    for(int i=2;i<=n;i++){ //直接命n=1时结果为1,然后从2开始走
        now=0;cnt=0;
        while(now<tot){
          int t=ans[now]*i+cnt;//这一位的总值
          ans[now++]=t%10;  //值为总值模10
          cnt=t/10; //余数为总值除10
          if(now==tot&&cnt) tot++; 
        }
    }
    for(int i=tot-1;i>=0;i--){
      cout<<ans[i];
    }
    cout<<endl;
  }
}

问题 F: 数字除法

题目描述
给你一个整数N,你可以执行如下操作,
1:如果N能被2整除,用N/2代替N。
2:如果N能被3整除,用2N/3代替N。
3: 如果N能被5整除 用4N/5代替N。
你的任务是通过上述操作,求出将N变成1所需要的最小操作次数。
输入
输入第一行一个数字q,代表询问次数,1 < q < 100。
接下来q次询问,每次询问给出一个整数N 1 <= N <= 10^18。
输出
对于每次询问,输出一个数并换行,如果能从N到1输出最小操作次数,否则输出 -1。
样例输入
7
1
10
25
30
14
27
1000000000000000000
样例输出
0
4
6
6
-1
6
72

#include<bits/stdc++.h>
using namespace std;
int main(){
  int q,cnt;
  long long int n;
  while(cin>>q){
    while(q--){
        cnt=0;
        cin>>n;
        while(1){
             if(n%2==0){
                n=n/2;
                 cnt++;
             }else if(n%3==0){
                n=(n/3)*2;
                 cnt++;
             }else if(n%5==0){
                n=(n/5)*4;
                 cnt++;
             }else if(n==1)
                break;
             else{
               cnt=-1;break;
             }
          }
        if(cnt>=0) cout<<cnt<<endl;
        else cout<<"-1"<<endl;
  }
}

问题 G: 神奇的数字基因

题目描述
众所周知,人类的外观与外貌具有极大的差异性,但实际决定其各种因素的根本因素在于基因,而实际上,同种生物的全部基因库相似性其实相当的高。而数字长相上差异性也是很大的,但数字的大小取决于它的基因,也就是说相同大小的数字基因是相等的。羊村的新村长帆洋洋对数字很感兴趣,尤其是对于数字之间基因的关系,他给希望你能够写一个程序帮助他判断数字 A 与 B 的基因关系,如果你能帮助村长帆洋洋成功找出数字间的基因关系,羊村将会俸你为贵客,还有希望能见到羊村的村花美羊羊哦! 你可以帮助帆洋洋嘛?只需要写出一个能够判断A和B是否相等的程序哦

Data range: (1e -10000 <= A ,B <= 1e10000)
输入
测试可能包含多个样本。
每个测试用例包含两个数字A和B。
输出
对于每一种情况,如果A等于B,你应该打印“YES”,否则打印“NO”。
样例输入
1 2
3 3
4 3
21 21
1.00 1.0
样例输出
NO
YES
NO
YES
YES
提示
1.00 和 1.0
001 和 1 都相等哦

即去除前置无用0和后置无用0
#include <cstdio>
#include <cstring>
using namespace std;

void cut(char * a) {  //切掉后置无用0
  int la = strlen(a)  - 1;
  for (int i = la; i > 0; i-- ) {
    if (a[i] == '0') 
       la--;
    else break;
  }
  if (a[la] == '.') 
      la--;
   a[la + 1] = '\0';
}

int main() {
  char a[50000], b[50000];

  while (scanf("%s%s", a, b) != EOF) {
    int la = strlen(a);
    int lb = strlen(b);
    for (int i = 0 ; i < la; i++ ) {
     	 if (a[i] == '.') {
      		cut(a);
      		break;
      	}
    }

    for (int i = 0 ; i < lb; i++ ) {
      if (b[i] == '.') {
      	cut(b);
      	break;
      }
  }
  //切掉无用前置0
    char * p1 = a, * p2 = b;  //用指针的方法切
    int t = 0;
    while (a[t] == '0') 
        t++;
    p1 = p1 + t;
     t = 0;
    while (b[t] == '0') 
        t++;
    p2 = p2 + t;

    if (strcmp(p1, p2)) printf("NO\n");
    else printf("YES\n");
  }

return 0;
}

问题 H: 刘莎莎的作业

题目描述
快帮数学不好的刘莎莎解决这个问题吧
得到一个正整数n,请输出有几个正整数k满足 k^k ≤ n
输入
测试用例不超过50个
每种情况只包含一行中的正整数n
1 ≤ ñ ≤ 10^18
输出
对于每个测试用例,输出一个整数表示正整数k满足k^k ≤ n的k的数量
样例输入
5
19
28
样例输出
2
2
3

方法一:k^k<=n 可以两边取对数变为k*log(k)<=log(n),这样就能很快算出来了
#include<bits/stdc++.h>
using namespace std;

int main(){
  long long int n;
   int flag;
  while(cin>>n){
    flag=0;
    for(int i=1;i<=n;i++){
      if(i*log(i)<=log(n)){
        flag++;
      }
      else break;
    }
    cout<<flag<<endl;
  }
}
方法二
#include<stdio.h>
 
int main(){
    long long int n, num, i;
    long long int sum[20]; 
    //因为大致到15时,15的15次方就能超过题所给的n的最大值,所以整个数组直接存下来这前十五位的情况
    for(i = 1; i <= 15; i++){
            num = 1;
           for(j = 1; j <= i; j++) 
              num *= i;
           sum[i] = num;
    }
    while(~scanf("%lld", &n)) {
         for(i=1; i<16; i++){
            if(sum[i]<=n);  //比较然后直接输出坐标
            else break;
        }
        printf("%lld", i-1);
    }
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Problems involving the computation of exact values of very large magnitude and precision are common. For example, the computation of the national debt is a taxing experience for many computer systems. This problem requires that you write a program to compute the exact value of Rn where R is a real number ( 0.0 < R < 99.999 ) and n is an integer such that 0 < n <= 25. 输入说明 The input will consist of a set of pairs of values for R and n. The R value will occupy columns 1 through 6, and the n value will be in columns 8 and 9. 输出说明 The output will consist of one line for each line of input giving the exact value of R^n. Leading zeros should be suppressed in the output. Insignificant trailing zeros must not be printed. Don't print the decimal point if the result is an integer. 输入样例 95.123 12 0.4321 20 5.1234 15 6.7592 9 98.999 10 1.0100 12 输出样例 548815620517731830194541.899025343415715973535967221869852721 .00000005148554641076956121994511276767154838481760200726351203835429763013462401 43992025569.928573701266488041146654993318703707511666295476720493953024 29448126.764121021618164430206909037173276672 90429072743629540498.107596019456651774561044010001 1.126825030131969720661201 小提示 If you don't know how to determine wheather encounted the end of input: s is a string and n is an integer C++ while(cin>>s>>n) { ... } c while(scanf("%s%d",s,&n)==2) //to see if the scanf read in as many items as you want /*while(scanf(%s%d",s,&n)!=EOF) //this also work */ { ... } 来源 East Central North America 1988 北大OJ平台(代理

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值