在利用计算机进行计算时,肯定会有一些数值的要求,那如何处理大数的加减乘除呢?我们可以利用数组的方式来计算出相应的结果。
进行高精度计算时要处理好一下几个问题:
一、数据的接收和储存
二、大数位数的确定
三、进位、借位的处理
四、商和余数的求法
下面分别来说明这几个问题:
一、数据的接收和存储
基本思路就是小学时计算加减乘除的思路如下图所示:
将大数中的每一位取出放入数组中:
for (int i = 0; i < length1; i++) {
a[length1-i] = str1.charAt(i)-'0';
}
例如:123放入数组a中:
a[3] = 1 a[2] = 2 a[1] = 3
二、大数位数的确定
这个很简单,就是字符串的长度:
str.length()
三、进位、借位处理
对于加法来说:
对于减法来说:
对于乘法来说:
具体的方式见下面的典例代码。
四、商和余数的求法
根据被除数和除数的位数进行处理。
典例一:高精度加法:
关键算法:
//计算大数
int n = 1;//代表正在计算的位置 从第一位开始计算
int x = 0;//每次的进位
while (n<=length1||n<=length2){//代表每一位都要小于总共的位数
c[n] = a[n] + b[n] + x;//求加数
x = c[n]/10;//求进位
c[n] = c[n]%10;//求此时c[n]的最终值
n++;
}
//处理最高进位
c[n] = x;
if (c[n]==0){
n--;
}
完整算法(Java实现):
package ACM_BigDate;
import java.util.Scanner;
/*
高精度加法
若输入是 a b 则cin接受的形式是:next()
若输入的a
b
则cin接受的形式是nextLine()
*/
public class Add {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
String str1 = cin.nextLine();//输入大数1
String str2 =cin.nextLine();//输入大数2
int length1 = str1.length();//计算大数1的长度
int length2 =str2.length();//计算大数2的长度
int[] a = new int[100];//将大数1的每一个字符装换成数字存入a中 根据题目要求设置成相应的长度
int[] b = new int[100];//将大数1的每一个字符装换成数字存入b中
int[] c = new int[100];//存放结果的数组
//例如 123 则是 a[1] = 3 a[2] = 2 a[3] = 1
//将大数1存入a数组 但是不利用a[0]
for (int i = 0; i < length1; i++) {
a[length1-i] = str1.charAt(i)-'0';
}
//将大数2存入b数组
for (int i = 0; i < length2; i++) {
b[length2-i] = str2.charAt(i)-'0';
}
//计算大数
int n = 1;//代表正在计算的位置 从第一位开始计算
int x = 0;//每次的进位
while (n<=length1||n<=length2){//代表每一位都要小于总共的位数
c[n] = a[n] + b[n] + x;//求加数
x = c[n]/10;//求进位
c[n] = c[n]%10;//求此时c[n]的最终值
n++;
}
//处理最高进位
c[n] = x;
if (c[n]==0){
n--;
}
for (int i = n; i >=1 ; i--) {
System.out.printf(String.valueOf(c[i]));
}
}
}
注意点:
1、根据题目要求设置数据的大小,例如大数1和大数2位数不超过1000,所以数组长度必须大于1000(这个我就错了,搞了半天,就是提交不上去,最后发现是自己搞错了需求)
2、还有就是进位的处理,一定要判断最后一个进位的处理,否则也会出错!
3、这这个例子中存储大数的数组a[0]是使用的,我觉得便于理解吧!意思就是把大数的个位放在数组的第一个位子(a[1])!!!
典例二:高精度减法
关键算法:
int n = 1;//此时两大数需要相减的位置
while (n <= length1 || n <= length2) {
//如果两数相减小于0
if (a[n] - b[n] < 0) {
a[n] = a[n] + 10;//向高层借一位
a[n+1]--;
}
c[n] = a[n] - b[n];//将两数相减的结果放入数组c中
n++;
}
//最高位的0不输出
while (c[n]==0&&n>1){
n--;
}
完整算法(Java实现):
package ACM_BigDate;
import java.util.Scanner;
/**
* 大数减法 祺本质个大数加法一样 只不过主要的算法需要改变
*/
public class Jian {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
String str1 = cin.nextLine();
String str2 = cin.nextLine();
int length1 = str1.length();
int length2 = str2.length();
int[] a = new int[100];
int[] b = new int[100];
int[] c = new int[100];
//将大数放入数组中
for (int i = 0; i < length1; i++) {
a[length1 - i] = str1.charAt(i) - '0';
}
for (int i = 0; i < length2; i++) {
b[length2 - i] = str2.charAt(i) - '0';
}
int n = 1;//此时两大数需要相减的位置
while (n <= length1 || n <= length2) {
//如果两数相减小于0
if (a[n] - b[n] < 0) {
a[n] = a[n] + 10;//向高层借一位
a[n+1]--;
}
c[n] = a[n] - b[n];//将两数相减的结果放入数组c中
n++;
}
//最高位的0不输出
//&&难点&& 例如: 111 - 111 结果为 000,所以要改写成0
while (c[n]==0&&n>1){
n--;
}
for (int i = n; i >=1; i--) {
System.out.printf(String.valueOf(c[n]));
}
}
}
注意点:
1、大数存入数组的算法是一样的,不需要更改,还是需要注意的是数的位数。
2、注意当a[1]-b[1]时,若小于0,则需要向a[2]借一位!!
3、假设是111-110时,得出的结果时001,需要将前面的0去掉,所以采用:
while (c[n]==0&&n>1){
n--;
}
4、注意a是两数中较大的数,输入时需要注意,或者需要将大小数比较之后放入对应的a、b中。
典例三:高精度乘法
如何计算大数乘法,这要回忆当年小学学的乘法最基本的法则:
关键算法:
int n = 0;//总共的位数
for (int i = 1; i <=length1 ; i++) {
int x = 0;//进位
for (int j = 1; j <=length2; j++) {
c[i+j-1] = a[i]*b[j]+c[i+j-1]+x;//现在c = 当前a[i]与b[j]的乘积+原来的c+进位
x = c[i+j-1]/10;//进位的计算
c[i+j-1] = c[i+j-1]%10;
}
c[i+length2] = x;
}
n = length1+length2;//假设总共的位数时length1+length2 因为m位数乘以n位数 最大为m+n位数
while (c[n]==0&&n>1){
n--;
}
完整算法(Java实现):
package ACM_BigDate;
import java.util.Scanner;
/**
* 高精度乘法
*/
public class Chen {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
String str1 = cin.nextLine();
String str2 = cin.nextLine();
int[] a = new int[100];
int[] b = new int[100];
int[] c = new int[100];
int length1 = str1.length();
int length2 = str2.length();
for (int i = 0; i < length1; i++) {
a[length1-i] = str1.charAt(i) - '0';
}
for (int i = 0; i < length2; i++) {
b[length2-i] = str2.charAt(i) - '0';
}
int n = 0;//总共的位数
for (int i = 1; i <=length1 ; i++) {
int x = 0;//进位
for (int j = 1; j <=length2; j++) {
c[i+j-1] = a[i]*b[j]+c[i+j-1]+x;//现在c = 当前a[i]与b[j]的乘积+原来的c+进位
x = c[i+j-1]/10;//进位的计算
c[i+j-1] = c[i+j-1]%10;
}
c[i+length2] = x;
}
n = length1+length2;//假设总共的位数时length1+length2 因为m位数乘以n位数 最大为m+n位数
while (c[n]==0&&n>1){
n--;
}
for (int i = n; i >=1 ; i--) {
System.out.printf(String.valueOf(c[i]));
}
}
}
注意点:
1、大数转数组和之前一样,不必多说。
2、对于关键算法的理解,我认为最好的方式就是利用99*99,自己画图演示一遍,这样会更加理解算法
3、对于m位数乘以n位数 最大为m+n位数,我是这样理解的,假设99*99,利用放缩法,99*99<100*100,既然100*100刚好等于10000,正好是5位数,所以99*99必定小于10000,也就是必定小于5位数,最大是4位数。
4、对于a、b数组长度大小的设定,若题目中给出每个数字的长度不超过1000,则c的数组的大小一定不会超过2000,由上面的结论而退出来的。
吃完饭回来再写,有点困了。。。。。。。剩下的几个算法慢慢再写。。。。。。
典例四:高精度除法
关键算法:
完整代码:
这个算法时是所有算法中最难的那一个,有时间我在慢慢推敲。。。。。。