大数运算

大数运算

struct bign{
	int d[maxn];//底位存储num的底位
    int len;
}

大数加法

bign add(bign n1,bign n2){
    bign c;
    c.len = 0;
    int carry = 0;
    for(int i=0;i<n1.len||i<n2.len;i++){
        int temp = n1.d[i]+n2.d[i] + carry;
        c.d[c.len++] = temp%10;
        carry /=10;
    }
    if(carry != 0){
        c.d[len++] = carry;
    }
    return c;
}

延迟回文数(PAT basic level B1097)

题目链接:

https://pintia.cn/problemsets/994805260223102976/problems/994805261754023936

思路:

  • 设结构体倒着存储num和num的长度
  • 写一个bign_reverse()返回一个bign的reverse,注意要重新计算长度
  • 写一个判断bign是否回文数的函数,设一个cnt判断循环次数
  • 根据加法法则写一个add函数

代码

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
struct bign
{
    int d[10000];
    int len;
    bign() {
        memset(d, 0, sizeof(d));
        len = 0;
    }
};
bign change(string num) {
    bign b;
    b.len = num.size();
    for (int i = 0; i < b.len; i++)
    {
        b.d[b.len - i - 1] = num[i] - '0';
    }
    return b;
}
bool isplid(bign b) {
    int i = 0, j = b.len - 1;
    while (i < j) {
        if (b.d[i] != b.d[j]) {
            return false;
        }
        i++;
        j--;
    }
    return true;
}
bign add(bign b1, bign b2) {
    bign c;
    c.len = 0;
    int carry = 0;
    for (int i = 0; i < b1.len || i < b2.len; i++)
    {
        int temp = b1.d[i] + b2.d[i] + carry;
        c.d[c.len++] = temp % 10;
        carry = temp / 10;
    }
    if (carry != 0) {
        c.d[c.len++] = carry;
    }
    return c;
}
void print(bign b) {
    for (int i = b.len-1; i >=0; i--   )
    {
        printf("%d",b.d[i]);
    }
}
bign bign_reverse(bign b) {
    bign ans;
    for (int i = 0; i < b.len; i++)
    {
        ans.d[i] = b.d[b.len - i - 1];
    }
    int j = b.len - 1;
    while (ans.d[j] == 0) {
        j--;
    }
    ans.len = j + 1;
    return ans;
}
int main()
{
    string num;
    int cnt = 0;
    cin >> num;
    bign b1 = change(num);
  
    while (!isplid(b1)&& cnt++ != 10) {
        print(b1);
        printf(" + ");
        bign b2 = bign_reverse(b1);
        print(b2);
        bign sum = add(b1, b2);
        printf(" = ");
        print(sum);
        printf("\n");
        b1 = sum;
    }
    if (isplid(b1) && cnt < 10) {
        print(b1);
        printf(" is a palindromic number.");
    }
    else {
        printf("Not found in 10 iterations.");
    }
}

大数减法

bign minus(bign n1,bign n2){
    bign c;
    c.len = 0;
    for(int i=0;i<n1.len||i<n2.len;i++){
        if(n1.d[i] < n2.d[i]){//不够减
            n1.d[i+1]--;
            n1.d[i]+=10;
        }
        c.d[c.len++] = n1.d[i] - n2.d[i];
    }
    
    //除去高位的0,重新算len
    while(c.len-1>=1&&c.d[c.len-1]==0){
        c.len--;
    }
    return c;
}

大数与int乘法

bign mutify(bign n,int x){
    bign c;
    c.len = 0;
    int carry = 0;
    for(int i=0;i<n.len;i++){
        int temp = n.d[i] * x + carry;
        c.d[c.len++] = temp %10;
        carry = temp /10;
    }
    while(carry !=0){
        c.d[c.len++] = carry%10;
        carry=temp / 10;
    }
    return c;
}

1.清华大学机试(N的阶乘)1<N<=1000

大数与int的除法

bign divide(bign num,int x,int &r){//r为余数,当不能整除时,余数存在这
    bign c;
    c.len = num.len;
    r = 0;
    //从高位开始除
    for(int i=num.len-1;i>=0;i--){
        int r = num.d[i] + r * 10; //被除数的当前位
        if(num.d[i] < x){//被除数当前位不够除
            c.d[i]=0;
        }else{
            c.d[i] = r /x;
            r = r % x;
        }
    }
    while(c.len-1>1&&c.d[c.len-1]==0)
        c.len--;
    return c;
}

1.10进制vs 2进制(清华大学机试)一题顶三题

https://www.nowcoder.com/practice/fd972d5d5cf04dd4bb4e5f027d4fc11e?tpId=40&tqId=21357&tPage=2&rp=2&ru=/ta/kaoyan&qru=/ta/kaoyan/question-ranking

思路:输入为最多1000位的十进制数n,将用大数除法思路变成2进制,再reverse,再将其变成十进制。(有点烦....)

代码:

#include <iostream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 1010;
struct bign
{
	int d[maxn], len;
	bign() {
		len = 1;
		memset(d, 0, sizeof(d));
	}
};
bign change(string num) {
	bign c;
	c.len = num.size();
	for (int i =c.len-1; i >=0 ; i--)
	{
		c.d[c.len - i - 1] = num[i]-'0';
	}
	return c;
}
bign divide(bign num, int x,int &r) {
	bign c;
	c.len = num.len;
	//从高位开始除
	for (int i = num.len - 1; i >= 0; i--) {
		r = num.d[i] + r * 10; //被除数的当前位
		if (r < x) {//被除数当前位不够除
			c.d[i] = 0;
		}
		else {
			c.d[i] = r / x;
			r = r % x;
		}
	}
	while (c.len - 1 >= 1 && c.d[c.len - 1] == 0)
		c.len--;
	return c;
}
vector<int> ten22(bign num) {//将num变成2进制,逆置后存储在vc中
	vector<int > vc;
	
	while (!(num.len == 1 &&num.d[0] == 0)) {
		int r = 0;
		num = divide(num, 2, r);
		vc.push_back(r);
	}
	reverse(vc.begin(), vc.end());
	while (vc[vc.size() - 1] == 0) {//去零头
		vc.pop_back();
	}
	return vc;
}
bign mutify(bign n, int x) {
	bign c;
	c.len = 0;
	int carry = 0;
	for (int i = 0; i < n.len; i++) {
		int temp = n.d[i] * x + carry;
		c.d[c.len++] = temp % 10;
		carry = temp / 10;
	}
	while (carry != 0) {
		c.d[c.len++] = carry % 10;
		carry /= 10;
	}
	return c;
}
bign add(bign n1, bign n2) {
	bign c;
	c.len = 0;
	int carry = 0;
		for (int i = 0; i < n1.len || i < n2.len; i++) {
			int temp = n1.d[i] + n2.d[i] + carry;
			c.d[c.len++] = temp % 10;
			carry = temp / 10;
		}
	if (carry != 0) {
		c.d[c.len++] = carry;
	}
	return c;
}
bign two1010(vector<int> vc) {//将逆置的二进制转换会bign。。。。感觉最难这里。。。。。
	bign ans;
	ans.d[0] = 0;
	ans.len = 1;
	bign product;//基数
	product.d[0] = 1;
	product.len = 1;
	for (int i = 0; i < vc.size(); i++)
	{
		if (vc[i] == 1) {
			ans = add(ans, product);
		}
		product = mutify(product, 2);
	}

	return ans;
}

void show(bign num){
	for (int i = num.len-1; i >=0 ; i--)
	{
		printf("%d", num.d[i]);
	}
	cout << endl;
}
int main()
{
	string n;

	while (cin>>n)
	{
		bign tar = change(n);
		vector<int> vc = ten22(tar);
		bign res = two1010(vc);
		show(res);
	}
}
posted @ 2020-04-02 16:14  cainiao11024  阅读(182)  评论(0编辑  收藏  举报