进行高精度乘法运算时当数字输入位数超过大概105位时结果是错误的,此后随着输入位数的增加错误的位数也就越多,请问到底是怎么回事呢?
又该如何解决这个问题呢?
我的算法是模仿人类列竖式计算
下面是代码 乘法函数为BIgMultiply函数
#define _CRT_SECURE_NO_DEPRECATE
#pragma warning(disable:4996) //使scanf()函数可用
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 205 //精度(数字位数) +2
//将字符串变为倒序
void reverse(char a[]) {
static char a2[N];
memset(a2, 0, sizeof(a2));
int xa = strlen(a) - 1;
int j = 0;
for (int i = xa; i >= 0; i--) {
a2[j] = a[i];
j++;
}
memset(a, 0, sizeof(a));
strcpy(a, a2);
}
//将字符串换算为真实数字
void str2numArry(char a[]) {
for (int i = 0; a[i] != '\0'; i++) {
a[i] -= '0';
}
}
int strGetLongest(char a[], char b[]) {
int xa = strlen(a);
int xb = strlen(b);
int longest = xb;
if (xa >= xb) {
longest = xa;
}
return longest;
}
//运算得出的out[]是逆序的
void BigPlus(char ia[], char ib[], char ResultGet[]) {
static char out[N], a[N], b[N];
int JW;//进位
//初始化
memset(out, 0, sizeof(out));
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
memset(ResultGet, 0, sizeof(ResultGet));
strcpy(a, ia);
strcpy(b, ib);
//先将数字倒序(因为列竖式时需要右对齐且从需要从右往左算)
reverse(a);
reverse(b);
//取a,b之中最长的 长度?
int longest = strGetLongest(a, b);
//换算为真实数字
str2numArry(a);
str2numArry(b);
//因为转换为真实数字之后末尾的‘0’会变成‘\0’,又因为数组经过倒序处理,所以先导零将变成字符串结尾 '\0' 将被忽略。
//运算
JW = 0;
for (int i = 0; i <= longest; i++) {
out[i] = a[i] + b[i] + JW;
JW = 0;
if (out[i] >= 10) {
JW = out[i] / 10;
out[i] %= 10;
}
}
int j = 0;
while (out[longest] == 0 && longest > 0) {
longest--;
}
for (int i = longest; i >= 0; i--) {
ResultGet[j] = out[i] + '0';
j++;
}
ResultGet[j] = '\0';
}
void BigMinus(char ia[], char ib[], char ResultGet[]) {
static char out[N], a[N], b[N];
int JW;//借位
//初始化
memset(out, 0, sizeof(out));
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
memset(ResultGet, 0, sizeof(ResultGet));
strcpy(a, ia);
strcpy(b, ib);
//先将数字倒序(因为列竖式时需要右对齐且从需要从右往左算)
reverse(a);
reverse(b);
//取a,b之中最长的 长度?
int longest = strGetLongest(a, b);
//换算为真实数字
str2numArry(a);
str2numArry(b);
//因为转换为真实数字之后末尾的‘0’会变成‘\0’,又因为数组经过倒序处理,所以先导零将变成字符串结尾 '\0' 将被忽略。
//运算
JW = 0;
for (int i = 0; i < longest; i++) {
out[i] = a[i] - b[i] - JW;
JW = 0;
if (out[i] < 0) {
JW = 1;
out[i] += 10;
}
}
//逆序输出ASCII
int j = 0;
while (out[longest] == 0 && longest > 0) {
longest--;
}
for (int i = longest; i >= 0; i--) {
ResultGet[j] = out[i] + '0';
j++;
}
ResultGet[j] = '\0';
}
void BigMultiply(char ia[], char ib[], char ResultGet[]) {
static char out1[N][2 * N], a[N+84], b[N];
static long long int out[2 * N];
long long int JW;//进位
//初始化
memset(out, 0, sizeof(out));
memset(out1, 0, sizeof(out1));
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
memset(ResultGet, 0, sizeof(ResultGet));
strcpy(a, ia);
strcpy(b, ib);
//先将数字倒序(因为列竖式时需要右对齐且从需要从右往左算)
reverse(a);
reverse(b);
int la = strlen(a);
int lb = strlen(b);
int longest = strGetLongest(a, b) + 1;//中间过程结果长度可能的最大值
int longest_out = la + lb;//结果可能的最长长度
//换算为真实数字
str2numArry(a);
str2numArry(b);
//因为转换为真实数字之后末尾的‘0’会变成‘\0’,又因为数组经过倒序处理,所以先导零将变成字符串结尾 '\0' 将被忽略。
//运算
JW = 0;
for (int i = 0; i < lb; i++) {
for (int k = 0, m = i; k < longest + i; k++, m++) {//数组序列是从零开始的,用<
out1[i][m] = b[i] * a[k] + JW;
JW = 0;
if (out1[i][m] >= 10) {
JW = out1[i][m] / 10;
out1[i][m] %= 10;
}
printf("%d ", out1[i][k]);
}
putchar('\n');
}
putchar('\n');
putchar('\n');
//char test[50][50] = { {1,2,3},{1,1,1},{1,1,1} };
//lb是实际列数
for (int i = 0; i < longest_out; i++) {
out[i] = out1[0][i];
}
for (int i = 1; i < lb; i++) {
JW = 0;
for (int j = 0; j <= longest_out; j++) {
out[j] += out1[i][j] + JW;
//if(out[j] < 0 || out[j] > 9223372036854775000) exit(0);//test
JW = 0;
if (out[j] >= 10) {
JW = out[j] / 10;
out[j] %= 10;
}
//if (out[j] > 10) exit(0);//test
//if (JW > 10) exit(0);//test
}
}
//working
int j = 0;
while (out[longest_out] == 0 && longest_out > 0) {
longest_out--;
}
for (int i = longest_out; i >= 0; i--) {
ResultGet[j] = out[i] + '0';
//printf("%d",out[i]);
j++;
}
ResultGet[j] = '\0';
}
int main() {
//int T;
static char a[N], b[N], out[2 * N];
/*
scanf("%d", &T);
for (int i = 1; i <= T; i++) {
scanf("%s%s", a, b);
BigPlus(a, b, out);
printf("Case %d:\n%s + %s = %s\n\n", i, a, b, out);
}
*/
while (1) {
scanf("%s%s", a, b);
BigMultiply(a, b, out);
printf("%s", out);
putchar('\n');
}
return 0;
}