以前没接触过高精度整数,今天在王道机试书上看到这个专题,写的浅显易懂,故而搬上来供大家一起作为学习入门。
高精度整数保存形式(结构体):
struct bigInteger {
int digit[1000];//暂且规定每四位作为一个单位保存
int size;//digit数组中第一个还没使用的数组单元
};
//以整数123456789为例,digit[0]=6789,digit[1]=3456,digit[2]=12,size=3
例题1:a+b
题目描述:实现一个加法器,使其能够输出a+b的值。
输入:输入包括两个数a和b,其中a和b的位数不超过1000位。
输出:可能有多组测试数据,对于每组数据,输出a+b的值
样例输入:
2 6
1000000000000000000000 10000000000000000000000000000000000000000000
样例输出:
8
100000000000000000000000000000000000000000000
解:(重载+运算符)
#include <cstdio>
#include <cstring>
struct bigInteger { // 高精度整数结构体
int digit[1000]; // 按四位数一个单位保存数值
int size; // 下一个我们未使用的数组单元
void init() {
for (int i = 0; i < 1000; i++)
digit[i] = 0;
size = 0;
}
void set(char str[]) { // 从字符串中提取整数
init();
int L = strlen(str);
for (int i = L-1, j = 0, t = 0, c = 1; i >= 0; i--) {
// 从最后一个字符开始倒序遍历字符串,j控制每4个字符转换为一个数字存入数组
// t临时保存字符转换为数字的中间值,c表示当前位置的权重,按1,10,100,1000顺序变化
t += (str[i] - '0') * c; // 计算这个四位数中当前字符代表的数字,即数字乘以当前位的权重
j++; // 当前转换字符数增加
c *= 10;
if (j == 4 || i== 0) {
digit[size++] = t;
j = 0;
t = 0;
c = 1;
}
}
}
void output() {
for (int i = size-1; i >= 0; i--) {
if (i != size-1)
printf("%04d", digit[i]); // 若当前输出的不是最高位数字,用%04输出前导0,即当前数字不足4位时由0补充,如输出110001的后四位数
else
printf("%d", digit[i]);
}
printf("\n");
}
bigInteger operator + (const bigInteger &A) const { // 加法运算符
bigInteger ret; // 返回值,即两数相加的结果
ret.init(); // 对其初始化
int carry = 0; // 进位,初始值为0
for (int i = 0; i < A.size || i < size; i++) {
int tmp = A.digit[i] + digit[i] + carry; // 计算两个整数当前位以及来自低位的进位和
carry = tmp / 10000; // 计算该位的进位
tmp %= 10000; // 去除进位部分,取后四位
ret.digit[ret.size++] = tmp;
}
if (carry != 0) { // 计算结果后若最高位有进位
ret.digit[ret.size++] = carry; // 保存该进位
}
return ret;
}
}a, b, c;
char str1[1002], str2[1002];
int main() {
while (scanf("%s%s", str1, str2) != EOF) {
a.set(str1);
b.set(str2);
c = a + b;
c.output();
}
return 0;
}
例题2:N的阶乘
题目描述:输入一个正整数N,输出N的阶乘。
输入:正整数N(0<=N<=1000)
输出:输入可能包括多组数据,对于每一组输入数据,输出N的阶乘
样例输入:
4
5
15
样例输出:
24
120
1307674368000
解:(重载*运算符)
#include <cstdio>
#include <cstring>
struct bigInteger { // 高精度整数结构体
int digit[1000]; // 按四位数一个单位保存数值
int size; // 下一个我们未使用的数组单元
void init() {
for (int i = 0; i < 1000; i++)
digit[i] = 0;
size = 0;
}
void set(int x) { // 用一个小整数设置高精度整数
init();
digit[size++] = x % 10000;
x /= 10000;
while (x != 0) {
digit[size++] = x % 10000;
x /= 10000;
}
}
void output() {
for (int i = size-1; i >= 0; i--) {
if (i != size-1)
printf("%04d", digit[i]); // 若当前输出的不是最高位数字,用%04输出前导0,即当前数字不足4位时由0补充,如输出110001的后四位数
else
printf("%d", digit[i]);
}
printf("\n");
}
bigInteger operator * (int x) const { // 乘法运算符
bigInteger ret; // 将要返回的高精度整数
ret.init(); // 对其初始化
int carry = 0; // 进位,初始值为0
for (int i = 0; i < size; i++) {
int tmp = x * digit[i] + carry; // 用小整数x乘以当前位数字并加上来自低位的进位
carry = tmp / 10000; // 计算该位的进位
tmp %= 10000; // 去除进位部分,取后四位
ret.digit[ret.size++] = tmp;
}
if (carry != 0) { // 计算结果后若最高位有进位
ret.digit[ret.size++] = carry; // 保存该进位
}
return ret;
}
}a;
int main() {
int n;
while (scanf("%d", &n) != EOF) {
a.init();
a.set(1);
for (int i = 1; i <= n; i++) {
a = a * i; // 依次乘上每一个数
}
a.output();
}
return 0;
}
例题3:进制转换
题目描述:将M进制的数X转换为N进制的数输出。
输入:输入的第一行包括两个整数:M和N(2<=M,N<=36)。
下面的一行输入一个数X,X是M进制的数,现在要求你将M进制的数X转换成N进制的数输出。
输出:输出X的N进制表示的数。
样例输入:
16 10
F
样例输出:
15
解:(高精度整数的综合使用)
#include <cstdio>
#include <cstring>
#define maxDigits 100
struct bigInteger { // 高精度整数结构体
int digit[maxDigits]; // 按四位数一个单位保存数值
int size; // 下一个我们未使用的数组单元
void init() {
for (int i = 0; i < maxDigits; i++)
digit[i] = 0;
size = 0;
}
void set(int x) {
init();
digit[size++] = x % 10000;
x /= 10000;
while (x != 0) {
digit[size++] = x % 10000;
x /= 10000;
}
}
void output() {
for (int i = size-1; i >= 0; i--) {
if (i != size-1)
printf("%04d", digit[i]); // 若当前输出的不是最高位数字,用%04输出前导0,即当前数字不足4位时由0补充,如输出110001的后四位数
else
printf("%d", digit[i]);
}
printf("\n");
}
bigInteger operator * (int x) const { // 高精度整数与普通整数的乘积
bigInteger ret;
ret.init();
int carry = 0;
for (int i = 0; i < size; i++) {
int tmp = x * digit[i] + carry;
carry = tmp / 10000;
tmp %= 10000;
ret.digit[ret.size++] = tmp;
}
if (carry != 0) {
ret.digit[ret.size++] = carry;
}
return ret;
}
bigInteger operator + (const bigInteger &A) const { // 高精度整数之间的加法运算
bigInteger ret;
ret.init();
int carry = 0;
for (int i = 0; i < A.size || i < size; i++) {
int tmp = A.digit[i] + digit[i] + carry;
carry = tmp / 10000;
tmp %= 10000;
ret.digit[ret.size++] = tmp;
}
if (carry != 0) {
ret.digit[ret.size++] = carry;
}
return ret;
}
bigInteger operator / (int x) const { // 高精度整数除以普通整数
bigInteger ret;
ret.init();
int remainder = 0; // 余数
for (int i = size-1; i >= 0; i--) { // 从最高位至最低位依次完成计算
int t = (remainder*10000 + digit[i]) / x; // 计算当前位置数值加上高位剩余的余数的和对x求得的商
int r = (remainder*10000 + digit[i]) % x; // 计算当前数位值加上搞卫生与的余数的和对x求模后的余数
ret.digit[i] = t; // 保存本位的值
remainder = r; // 保存至本位为止的余数
}
ret.size = 0; // 返回高精度整数的size初始值为0,即当前所有位数字都为0时,digit[0]代表数字0,作为最高有效位,高精度整数即为数字0
for (int i = 0; i < maxDigits; i++) {
if (digit[i] != 0)
ret.size = i;
} // 若存在非0位,确定最高的非0位,作为最高有效位
ret.size++; // 最高有效位的下一位即为下一个我们不曾使用的digit数组单元,确定为size的值
return ret;
}
int operator % (int x) const { // 高精度整数对普通整数求余数
int remainder = 0; // 余数
for (int i = size-1; i >= 0; i--) {
int t = (remainder*10000 + digit[i]) / x;
int r = (remainder*10000 + digit[i]) % x;
remainder = r;
} // 过程同高精度整数对普通整数求商
return remainder; // 返回余数
}
}a, b, c;
char str[10000];
char ans[10000];
int main() {
int n, m;
while (scanf("%d%d", &m, &n) != EOF) {
scanf("%s", str); // 输入m进制数
int L = strlen(str);
a.set(0); // a的初始值为0,用来保存转换成十进制的m进制数
b.set(1); // b的初始值为1,在m进制向十进制转换的过程中,依次代表每一位的权重
for (int i = L-1; i >= 0; i--) { // 由低位至高位转换m进制数至相应的十进制数
int t;
if (str[i] >= '0' && str[i] <= '9') {
t = str[i] - '0';
} else
t = str[i] - 'A' + 10; // 确定当前位字符代表的数字
a = a+b*t; // 累加当前数字乘当前位权重的积
b = b*m; // 计算下一位权重
}
int size = 0; // 代表转换为n进制后的字符个数
do { // 对转换后的十进制数求其n进制值
int t = a % n; // 求余数
if (t >= 10)
ans[size++] = t-10+'a';
else ans[size++] = t+'0'; // 确定当前位字符
a = a / n; // 求商
} while (a.digit[0] != 0 || a.size != 1); // 当a不为0时重复该过程
for (int i = size-1; i >= 0; i--)
printf("%c", ans[i]);
printf("\n");
}
return 0;
}
作者注:使用高精度整数后不能忽略其复杂度,如a+b,由于要进行每一位的运算,复杂度为O(size),其中size是两个整数中较多的位数
代码转自点击跳转