前言
今天来讲一讲高精度算法,我们说一个数据类型,有它的对应范围比如int类型最多
可以包含到负2的31次方到2的31次方减一
其实大概就是20亿左右那么其他的类型也同样如此
那么,如何解决一个很大很大的数的运算呢?
我们今天介绍两种对于整数的高精度加法和高精度除法
还算是比较简单的算法,但实现起来仍然有细节
高精度加法
对于两个很大很大的数,我们已经无法用任何整型来记录它更不能对其运算,那么此时我们完全可以使用字符串来记录要进行加法的数
我们以题目为例
输入两个数 a b 0<a< 0<b< ,求两个数之和,这里的数为整数
思路
使用字符串记录两个数,当然这个字符串的大小范围取决于数的范围最多有500位数
(不包括) 那么字符数组大小只要大于500就可以了
把它用字符数组记住后该数的高位对应字符数组低下标
所以我们需要逆转这个字符数组,并让它储存在整型数组中,最后让这个个数所对应的
相加,满10进1,就完成了.
当然这两个操作数都是正数,那如果有负数,怎么办那么我们可以把它当成减法嘛
思路是如此实现起来还有很多细节,会在代码中注释出来的,好好看,可以看懂的
看代码吧
//高精度算法
char a[505];
char b[505];
int a1[505];
int b1[505];
int result[505];
int main()
{printf("请输入两个数\n");scanf("%s", a);scanf("%s", b);int lc, la, lb;la = strlen(a);lb = strlen(b);//遇10进1,有可能位数是a b 中最大的或者是最大的加上1//所以在这里默认使位数加一,后面可以判断是否有改位lc = la > lb ? la + 1 : lb + 1;//逆置字符串,方便运算,毕竟要从低位开始算,//把低位放在低下标处for (int i = 0; i <la; i++){a1[la-i-1] = a[i] - '0';}for (int i = 0; i < lb; i++){b1[lb-i-1] = b[i] - '0';}for (int i = 0; i < lc; i++){result[i]+=a1[i] + b1[i];result[i + 1] += result[i]/10;result[i]%=10;}//但是这里值的注意的是//对于加法最多会多一个前置0//判断并清除前置0if(result[lc]==0)lc--;for (int i = lc - 1; i >= 0; i--){printf("%d", result[i]);}return 0;
}
一些细节全部都在代码的注释上了
当然 我们其实完全可以不构建太多变量,来实现优化
说一说思路,但是这个代码写起来就会变得难理解了
我们完全可以只构建两个char arr[] char brr[] 数组
然后直接把他们逆置,通过brr[]字符数组先可以去一个字符0在加到字符arr[]中如果大于字符‘9’+1
所对应的Ascll值就可以让和减去数字10,让下一位加数字1这样也可以解决问题
最后通过判断长度以及清除前置的‘0’来输出结果
不过没有太大必要 代码都差不多,就这么点空间,其实区别不大
好吧!我们看看测试的结果
左边是测试值右边是执行代码的结果 两者一样 nice!那么该程序就是可以计算更高精度的整数
高精度减法
高精度减法的思路与加法差不多
但是要多出一个判断,我们就用大或等的数减去小的数,得到一个非负数,最后再判断是否要添加负号
核心思路就是低位减去低位,若大数的低位小于小数的低位,那么低位向高位借一位
看个例题
计算最大10000位的正数之间的减法
多说无益 代码走起
//高精度减法
char s1[10090];
char s2[10090];
char s3[10090];
int a[10090];
int b[10090];
int c[10090];
bool flag;
bool cmpare(char *p1,char* p2)
{int lp1= strlen(p1);int lp2 = strlen(p2);if (lp1 > lp2)return true;else if (lp1 == lp2){if (strcmp(p1, p2) >= 0)return true;elsereturn false;}elsereturn false;
}
int main()
{while (1){printf("请输入被减数与减数\n");scanf("%s", s1);scanf("%s", s2);if (!cmpare(s1, s2)){flag = true;strcpy(s3, s1);strcpy(s1, s2);strcpy(s2, s3);}int la = strlen(s1);int lb = strlen(s2);int lc = la > lb ? la : lb;//逆置字符数组for (int i = 0; i < la; i++){a[la - i] = s1[i] - '0';}for (int i = 0; i < lb; i++){b[lb - i] = s2[i] - '0';}for (int i = 1; i <= lc; i++){if (a[i] < b[i]){a[i + 1]--;a[i] += 10;}c[i] = a[i] - b[i];}//清除前置0,如果两个数相等,我们就要清除位数-1个0//举例100-100=000 我们要清除这两个三位数的两个0//这里要用循环来解决while (c[lc] == 0 && lc > 1)lc--;//判断正负if (flag){printf("-");flag = false;}for (int i = lc; i >0; i--)printf("%d", c[i]);printf("\n");}return 0;
}
看看代码吧
细节还是很多的,值得注意的·
1就是那么前置0的清除
2还有就是a b整型数组是从1开始的
3ic的大小至少为1
还是那样,今天就这样了,继续努力