C++实现高精度大整数及其运算

18 篇文章 0 订阅
16 篇文章 2 订阅

高精度大整数

对于一个数,如果其超过了0x7fffffff,则无法用int存储,如果超过2^63-1则long long也无法存储。因此构造结构体来存储这样的高精度大数。

头文件

#include<cstdio>
#include<cstring>
using namespace std;

结构体

struct bign{	//存123时: d={3,2,1}llen =3; 
	int d[1000];
	int len;
	bign(){
		memset(d,0,sizeof(d));
		len = 0;}
};

通过字符数组赋值

bign change(char str[]){	//通过字符串读取大整数 
	//str[]={'1','2','3'} ->a.b={3,2,1}
	bign a;
	a.len = strlen(str);
	for(int i=0;i<a.len;i++){
		a.d[i] = str[a.len-1-i] - '0';
	}
	return a;
}

输出大整数

void print(bign a){	//输出大整数 
	for(int i=a.len-1;i>=0;i--)
		printf("%d",a.d[i]);
	return;
}

大整数的比较

int compare(bign a,bign b){	//比较a和b的大小,a>b返回1,相等返回0,a<b返回-1 
	if(a.len>b.len) return 1;
	if(a.len<b.len) return -1;
	for(int i=a.len-1;i>=0;i--){
		if(a.d[i]>b.d[i]) return 1;
		if(a.d[i]<b.d[i]) return -1;
	}
	return 0;
}

大整数的运算

大整数之间的加法

bign add(bign a,bign b){	//大整数之间进行加法 
	bign c;
	int carry = 0;	//进位
	for(int i=0;i<a.len||i<b.len;i++){
		int temp = a.d[i]+b.d[i] + carry;
		c.d[c.len++] = temp%10;
		carry = temp/10;
	} 
	if(carry!=0) c.d[c.len++] = carry;
	return c;
}

大整数之间的减法

bign sub(bign a,bign b){	//大整数之间进行减法 
	bign c;
	for(int i=0;i<a.len||i<b.len;i++){
		if(a.d[i]<b.d[i]){	//低位不够减,需要借位
			a.d[i+1]--; 
			a.d[i]+=10;
		}
		c.d[c.len++] = a.d[i]-b.d[i];
	}
	while(c.len-1>=1&&c.d[c.len-1]==0)
		c.len--;	//去除高位0
	return c;
}

高精度大整数与低精度的乘法

bign multi(bign a,int b){	//高精度大整数与低精度的乘法
	bign c;
	int carry = 0; //进位
	for(int i=0;i<a.len;i++){
		int temp = a.d[i]*b + carry;
		//printf("%d*%d+%d\n",a.d[i],b,carry);
		c.d[c.len++] = temp%10;
		carry = temp / 10;
	} 
	while(carry!=0){
		c.d[c.len++] = carry%10;
		carry/=10;
	}
	return c;
}

高精度除以低精度数,同时返回r为余数

bign divide(bign a,int b,int& r){	//高精度除以低精度,r为余数 
	bign c;
	c.len = a.len;
	r=0;
	for(int i=a.len-1;i>=0;i--){
		r = r*10 + a.d[i];
		if(r<b) c.d[i] = 0;
		else{
			c.d[i] = r/b;
			r %= b;
		}
	}
	while(c.len-1>=1&&c.d[c.len-1]==0){
		c.len--;
	}
	return c;
}

其他运算

比如大整数与大整数的乘除略。。。。

使用示例

例题1(贪心+大整数)

题目

洛谷P1080 国王游戏
在这里插入图片描述
分析

此题需要先贪心找到排序规律为按照每个人的左右手乘积非降序排列,在计算最小值时累乘的过程中可能数字溢出,所以要使用大整数,但是根据题目描述大整数开100001位是不够的需要开的更大,但是实际测试数据并没有这么大。

AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn = 10001;
pair<int,int> nums[maxn];	//first 右手,second左手

struct bign{	//存123时: d={3,2,1}llen =3; 
	int d[maxn];
	int len;
	bign(){
		memset(d,0,sizeof(d));
		len = 0;}
}res,sum,ans;	//res最终结果,sum累乘结果,ans比较变量

bign multi(bign a,int b){	//高精度大整数与低精度的乘法
	bign c;
	int carry = 0; //进位
	for(int i=0;i<a.len;i++){
		int temp = a.d[i]*b + carry;
		//printf("%d*%d+%d\n",a.d[i],b,carry);
		c.d[c.len++] = temp%10;
		carry = temp / 10;
	} 
	while(carry!=0){
		c.d[c.len++] = carry%10;
		carry/=10;
	}
	return c;
}

bign divide(bign a,int b,int& r){	//高精度除以低精度,r为余数 
	bign c;
	c.len = a.len;
	r=0;
	for(int i=a.len-1;i>=0;i--){
		r = r*10 + a.d[i];
		if(r<b) c.d[i] = 0;
		else{
			c.d[i] = r/b;
			r %= b;
		}
	}
	while(c.len-1>=1&&c.d[c.len-1]==0){
		c.len--;
	}
	return c;
}

int compare(bign a,bign b){	//比较a和b的大小,a>b返回1,相等返回0,a<b返回-1 
	if(a.len>b.len) return 1;
	if(a.len<b.len) return -1;
	for(int i=a.len-1;i>=0;i--){
		if(a.d[i]>b.d[i]) return 1;
		if(a.d[i]<b.d[i]) return -1;
	}
	return 0;
}

void print(bign a){	//输出大整数 
	for(int i=a.len-1;i>=0;i--)
		printf("%d",a.d[i]);
	return;
}

int cmp(pair<int,int> a,pair<int,int> b){
	return a.first*a.second<b.first*b.second;
}

int main(){
	int n;
	scanf("%d",&n);
	scanf("%d %d",&nums[0].first,&nums[0].second);
	for(int i=1;i<=n;i++)
		scanf("%d %d",&nums[i].first,&nums[i].second);
	sort(nums+1,nums+1+n,cmp);
	sum.d[0] = 1; sum.len = 1;
	for(int i=1;i<=n;i++){
		int r = 0;	//存余数 
		sum = multi(sum,nums[i-1].first);
		ans = divide(sum,nums[i].second,r);
		if(compare(ans,res)==1)
			res = ans;
	}
	print(res);
	return 0;
}
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现高精度运算的双向循环链表可以分为三个部分:节点结构体、链表结构体和高精度运算函数。 首先是节点结构体,可以定义如下: ```c++ struct Node { int val; // 当前节点的值 Node* next; // 指向下一个节点的指针 Node* prev; // 指向上一个节点的指针 // 构造函数 Node(int v = 0, Node* n = nullptr, Node* p = nullptr) : val(v), next(n), prev(p) {} }; ``` 接下来是链表结构体,可以定义如下: ```c++ struct LinkedList { Node* head; // 头指针 Node* tail; // 尾指针 // 构造函数 LinkedList() : head(nullptr), tail(nullptr) {} // 复制构造函数 LinkedList(const LinkedList& lst) { head = tail = nullptr; Node* p = lst.head; while (p != nullptr) { push_back(p->val); p = p->next; } } // 析构函数 ~LinkedList() { while (head != nullptr) { Node* p = head; head = head->next; delete p; } } // 在链表尾部插入一个节点 void push_back(int v) { Node* p = new Node(v, nullptr, tail); if (tail != nullptr) { tail->next = p; } else { head = p; } tail = p; } // 在链表头部插入一个节点 void push_front(int v) { Node* p = new Node(v, head, nullptr); if (head != nullptr) { head->prev = p; } else { tail = p; } head = p; } }; ``` 最后是高精度运算函数,可以实现加法、减法和乘法等运算: ```c++ // 高精度加法 LinkedList add(const LinkedList& a, const LinkedList& b) { LinkedList res; int carry = 0; // 进位 Node* p = a.tail; Node* q = b.tail; while (p != nullptr || q != nullptr) { int x = (p != nullptr) ? p->val : 0; int y = (q != nullptr) ? q->val : 0; int sum = x + y + carry; res.push_front(sum % 10); carry = sum / 10; if (p != nullptr) { p = p->prev; } if (q != nullptr) { q = q->prev; } } if (carry > 0) { res.push_front(carry); } return res; } // 高精度减法 LinkedList sub(const LinkedList& a, const LinkedList& b) { LinkedList res; int borrow = 0; // 借位 Node* p = a.tail; Node* q = b.tail; while (p != nullptr || q != nullptr) { int x = (p != nullptr) ? p->val : 0; int y = (q != nullptr) ? q->val : 0; int diff = x - y - borrow; if (diff < 0) { diff += 10; borrow = 1; } else { borrow = 0; } res.push_front(diff); if (p != nullptr) { p = p->prev; } if (q != nullptr) { q = q->prev; } } // 去除前导零 while (res.head->next != nullptr && res.head->val == 0) { Node* p = res.head; res.head = res.head->next; res.head->prev = nullptr; delete p; } return res; } // 高精度乘法 LinkedList mul(const LinkedList& a, const LinkedList& b) { LinkedList res; int n = a.tail != nullptr ? 1 : 0; int m = b.tail != nullptr ? 1 : 0; if (n == 0 || m == 0) { return res; } int len = n + m - 1; int* c = new int[len]; memset(c, 0, len * sizeof(int)); Node* p = a.tail; for (int i = 0; p != nullptr; i++, p = p->prev) { Node* q = b.tail; for (int j = 0; q != nullptr; j++, q = q->prev) { c[i + j] += p->val * q->val; c[i + j + 1] += c[i + j] / 10; c[i + j] %= 10; } } while (len > 0 && c[len - 1] == 0) { len--; } for (int i = len - 1; i >= 0; i--) { res.push_back(c[i]); } delete[] c; return res; } ``` 这样,我们就实现了一个可以进行高精度运算的双向循环链表。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值