有这么一类整数,它们的数值非常巨大以致于我们不能使用任何内置整数类型来进行保存。面对这种情况,我们常用一个结构体来保存一个高精度整数:
struct bigInt {//高精度整数结构体
int d[maxn];//按一位数一个单位来保存数值
int size;//下一个我们未使用的数组单元
void init() {//初始化
for (int i = 0; i < maxn; i++) {
d[i] = 0;
}
size = 0;//目前还没有任何一个单位被使用
}
//将一个普通整数设置成一个大数
void set(int x) {
init();
do {
d[size++] = x % 10;
x /= 10;
} while (x != 0);
}
//当然,我们也可以从字符数组中提取大数的数值
/*void set(char str[]) {//从字符数组中提取大数的数值
init();
int len = strlen(str);
for (int i = len - 1; i >= 0; i--) {
d[size++] = str[i] - '0';
}
}*/
void output() {//输出函数
for (int i = size - 1; i >= 0; i--) {
printf("%d", d[i]);
}
if(size==0) printf("0");
printf("\n");
}
};
其中d 数组用来保存大整数中每若干位的数字,我们这里使用每一位作为一个单位保存。以整数123456为例,则d[0]=6,d[1]=5,d[2]=4,d[3]=3,d[4]=2,d[5]=1;
bigInt add(bigInt a, bigInt b) {//十进制 大整数与大整数相加
bigInt res;//返回值
res.init();//初始化
int carry = 0;//进位,初始值为0
for (int i = 0; i < a.size || i < b.size; i++) {
int tmp = a.d[i] + b.d[i] + carry;
carry = tmp / 10;//计算进位
tmp %= 10;//该位的结果
res.d[res.size++] = tmp;//保存该位结果
}
while (carry > 0) {//结束计算后如果最高位有进位
res.d[res.size++] = carry % 10;
carry /= 10;
}
return res;
}
实现高精度加法,即用代码模拟加法的运算法则,按照从低位开始各对应位相加并加上来自低位的进位,从而获得本位的数值以及进位的规则进行运算。
例题 a+b
实现一个加法器,使其能够输出a+b的值。
输入描述:
输入包括两个数a和b,其中a和b的位数不超过1000位。
输出描述:
可能有多组测试数据,对于每组数据,
输出a+b的值。
示例1
输入
2 6
10000000000000000000 10000000000000000000000000000000
输出
8
10000000000010000000000000000000
AC代码:
#include
#include
using namespace std;
struct bigInt {
int d[1011];
int size;
void init() {//初始化
for (int i = 0; i < 1011; i++) {
d[i] = 0;
}
size = 0;//目前还没有任何一个单位被使用
}
void set(char str[]) {//提取字符串
init();
int len = strlen(str);
for (int i = len - 1; i >= 0; i--) {
d[size++] = str[i] - '0';
}
}
void output() {//输出函数
for (int i = size - 1; i >= 0; i--) {
printf("%d", d[i]);
}
if(size==0) printf("0");
printf("\n");
}
};
bigInt add(bigInt a, bigInt b) {//十进制 大整数与大整数相加
bigInt res;//返回值
res.init();//初始化
int carry = 0;//进位,初始值为0
for (int i = 0; i < a.size || i < b.size; i++) {
int tmp = a.d[i] + b.d[i] + carry;
carry = tmp / 10;//计算进位
tmp %= 10;//该位的结果
res.d[res.size++] = tmp;//保存该位结果
}
while (carry > 0) {//结束计算后如果最高位有进位
res.d[res.size++] = carry % 10;
carry /= 10;
}
return res;
}
int main() {
bigInt a, b;
char str1[1002], str2[1002];
while (cin >> str1 >> str2) {
a.set(str1);
b.set(str2);
a = add(a, b);
a.output();
}
return 0;
}
高精度减法运算法则与加法类似,从最低位开始依次相减并减去来自低位的借位,从而得出本位的结果和向高位的借位,原理和代码都与加法类似。
这里给出参考代码(暂时不考虑结果为负的情况):
bigInt reduce(bigInt a, bigInt b) {//十进制 大整数与大整数相减 暂时不考虑结果为负的情况
bigInt res;
res.init();
int carry = 0;
for (int i = 0; i < a.size || i<b.size; i++) {
int tmp = a.d[i] - b.d[i] - carry;
if (tmp >= 0) {
res.d[res.size++] = tmp;
carry = 0;
}
else {
res.d[res.size++] = tmp + 10;
carry = 1;//借位
}
}
res.size = 0;//注意将最高有效位初始化
for (int j = a.size - 1; j >= 0; j--) {//注意这里要重新寻找最高有效位
if (res.d[j] != 0) {//找到最高有效位
res.size = j + 1;
break;
}
}
return res;
}
我们这里讨论的乘法指的是高精度整数乘普通整数的运算。高精度乘法的原理与高精度加法类似,用将要乘的小乘数来乘高精度整数的每一位并加上来自低位的进位,进而得到该位的结果以及向高位的进位。
bigInt mul(bigInt a, int x) {//大整数乘普通整数
bigInt res;
res.init();
int carry = 0;
for (int i = 0; i < a.size; i++) {
int tmp = x*a.d[i] + carry;//carry不参与乘法运算
carry = tmp / 10;
tmp %= 10;
res.d[res.size++] = tmp;
}
while (carry > 0) {//注意最后对进位的处理
res.d[res.size++] = carry % 10;
carry /= 10;
}
return res;
}
例题 N的阶乘 求1000以内n的阶乘 大数与普通整数相乘
输入一个正整数N,输出N的阶乘。
输入描述:
正整数N(0<=N<=1000)
输出描述:
输入可能包括多组数据,对于每一组输入数据,输出N的阶乘
示例1
输入
4
5
15
输出
24
120
1307674368000
AC代码:
#include
#include
using namespace std;
struct bigInt {
int d[50001];
int size;
void init() {//初始化
for (int i = 0; i < 50001; i++) {
d[i] = 0;
}
size = 0;//目前还没有任何一个单位被使用
}
void set(int x) {
init();
do {
d[size++] = x % 10;
x /= 10;
} while (x != 0);
}
void output() {//输出函数
for (int i = size - 1; i >= 0; i--) {
printf("%d", d[i]);
}
if (size == 0) printf("0");
printf("\n");
}
};
bigInt mul(bigInt a, int x) {//大整数乘普通整数
bigInt res;
res.init();
int carry = 0;
for (int i = 0; i < a.size; i++) {
int tmp = x*a.d[i] + carry;//carry不参与乘法运算
carry = tmp / 10;
tmp %= 10;
res.d[res.size++] = tmp;
}
while (carry > 0) {//注意最后对进位的处理
res.d[res.size++] = carry % 10;
carry /= 10;
}
return res;
}
int main() {
bigInt a; int n;
while (scanf("%d", &n) != EOF) {
a.set(1);
for (int i = 2; i <= n; i++) {
a = mul(a, i);
}
a.output();
//system("pause");
}
}
bigInt div(bigInt a, int x) {//大整数除普通整数
bigInt res;
res.init();
int carry = 0;//这里不再是进位,而是余数
for (int i = a.size - 1; i >= 0; i--) {//从最高位至最低位依次完成计算
int t = (carry * 10 + a.d[i]) / x;//计算 当前位数值加上高位剩余的余数的和 对x求得的商
int r = (carry * 10 + a.d[i]) % x;//计算 当前位数值加上高位剩余的余数的和 对x求模后得到的余数
res.d[i] = t;//保存本位的值
carry = r;//保存至本位为止的余数
}
res.size = 0;//结果的size值,初始化为0,即当所有位数值都为0时,高精度整数即为数字0
for (int j = a.size - 1; j >= 0; j--) {//注意这里要重新寻找最高有效位
if (res.d[j] != 0) {//找到最高有效位
res.size = j + 1;//最高位的下一位是size的值,即下一个我们未使用的数组单元
break;
}
}
return res;
}
int mod(bigInt a, int x) {//大整数对普通整数取余
int carry = 0;//这里不再是进位,而是余数
for (int i = a.size - 1; i >= 0; i--) {
int t = (carry * 10 + a.d[i]) / x;
int r = (carry * 10 + a.d[i]) % x;
carry = r;
}//过程同高精度整数对普通整数求商
return carry;//返回余数
}
题目描述
将 M 进制的数 X 转换为 N 进制的数输出。
输入:
输入的第一行包括两个整数: M 和 N(2<=M,N<=36) 。
下面的一行输入一个数 X , X 是 M 进制的数,现在要求你将 M 进制的数 X
转换成 N 进制的数输出。
输出:
输出 X 的 N 进制表示的数。
例输入: 样
16 10
F
样例输出:
15
提示:
输入时字母部分为大写,输出时为小写,并且有大数据。
找到了一道类似的题目,不过有没有大数据就不清楚了。。。
进制转换
给出链接的题目的AC代码:
#include
#include
#include
#include
using namespace std;
#define maxn 10001
struct bigInt {
int d[maxn];
int size;
void init() {//初始化
for (int i = 0; i < maxn; i++) {
d[i] = 0;
}
size = 0;
}
void set(int x) {
init();
do {
d[size++] = x % 10;
x /= 10;
} while (x != 0);
}
void output() {//输出函数
for (int i = size - 1; i >= 0; i--) {
printf("%d", d[i]);
}
if (size == 0) printf("0");
printf("\n");
}
};
bigInt mul(bigInt a, int x) {//大整数乘普通整数
bigInt res;
res.init();
int carry = 0;
for (int i = 0; i < a.size; i++) {
int tmp = x*a.d[i] + carry;//carry不参与乘法运算
carry = tmp / 10;
tmp %= 10;
res.d[res.size++] = tmp;
}
while (carry > 0) {
res.d[res.size++] = carry % 10;
carry /= 10;
}
return res;
}
bigInt add(bigInt a, bigInt b) {//十进制 大整数与大整数相加
bigInt res;
res.init();
int carry = 0;
for (int i = 0; i < a.size || i < b.size; i++) {
int tmp = a.d[i] + b.d[i] + carry;
carry = tmp / 10;
tmp %= 10;
res.d[res.size++] = tmp;
}
while (carry > 0) {
res.d[res.size++] = carry % 10;
carry /= 10;
}
return res;
}
bigInt div(bigInt a, int x) {//大整数除普通整数
bigInt res;
res.init();
int carry = 0;//这里不再是进位,而是余数
for (int i = a.size - 1; i >= 0; i--) {
int t = (carry * 10 + a.d[i]) / x;
int r = (carry * 10 + a.d[i]) % x;
res.d[i] = t;
carry = r;
}
res.size = 0;
for (int j = a.size - 1; j >= 0; j--) {
if (res.d[j] != 0) {//找到最高有效位
res.size = j + 1;
break;
}
}
return res;
}
int mod(bigInt a, int x) {//大整数对普通整数取余
int carry = 0;//这里不再是进位,而是余数
for (int i = a.size - 1; i >= 0; i--) {
int t = (carry * 10 + a.d[i]) / x;
int r = (carry * 10 + a.d[i]) % x;
carry = r;
}
return carry;//返回余数
}
char num1[1001];//存放m进制的大数
char num2[1001];//存放n进制的大数
int m, n;
int main() {
bigInt a, b;
while (scanf("%d%d%s", &m, &n, num1) != EOF) {
int len = strlen(num1);
a.set(0);//保存转化成10进制的m进制数
b.set(1);//保存权重
for (int i = len - 1; i >= 0; i--) {//将m进制转化为十进制
int t;
if (num1[i] >= '0'&&num1[i] <= '9') {
t = num1[i] - '0';
}
else t = num1[i] - 'A' + 10;
a = add(a, mul(b, t));
b = mul(b, m);//更新权重
}
int size = 0;//代表转化为n进制后的字符个数
do {
//a.output();
int t = mod(a, n);//求余数
if (t >= 10) num2[size++] = t - 10 + 'a';
else num2[size++] = t + '0';
a = div(a, n);
} while (a.d[0] != 0 || a.size != 0);//a不为0时重复上述过程
for (int i = size - 1; i >= 0; i--) {
printf("%c", num2[i]);
}
printf("\n");
}
return 0;
}
高精度整数间求差以及高精度整数除以普通整数可能会使得高位出现0的情况,因此要重新寻找最高的有效位。