1、大整数乘法的实现思路(一):模拟手工列竖式计算两个大整数的乘积
模拟手工计算两个整数相乘的过程:逐位相乘,错位累加,最后进位。以 1235789×6452351 1235789 × 6452351 为例:
- 相乘的前提: 被乘数位数 >= 乘数位数。 x×y x × y 的逐位相乘次数取决于乘数y的位数。
- 低位补0:乘数y从十位数开始乘以被乘数的每位时,相乘后的结果的低位要补足相应0的数目,例如:从十位开始,则需要补个位的0;从百位开始,则需要补十位和个位的0,诸如此类。
- 高位补0:m位的被乘数x和n位的乘数y相乘,最终累加和的位数为:m+n-1,所以相乘后的结果的高位也要补足相应的0的数目,例如:乘数6452351的十位乘以被乘数1235789的每位时,算上低位补的0,数组中一共是8位,所以乘积结果需要在高位补0:(7+7-1)-8=5个。
乘数的每位和被乘数的每位逐位相乘,每次相乘结果如下:
10的幂 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12] 第一次: [9, 8, 7, 5, 3, 2, 1, 0, 0, 0, 0, 0,0] 第二次: [0,45,40,35, 25,15, 10, 5, 0, 0, 0, 0,0] 第三次: [0, 0,27,24, 21,15, 9, 6, 3, 0, 0, 0,0] 第四次: [0, 0, 0,18, 16,14, 10, 6, 4, 2, 0, 0,0] 第五次: [0, 0, 0, 0, 45,40, 35, 25,15,10, 5, 0,0] 第六次: [0, 0, 0, 0, 0,36, 32, 28,20,12, 8, 4,0] 第七次: [0, 0, 0, 0, 0, 0, 54, 48,42,30,18,12,6] 逐位累加:[9,53,74,82,110,122,151,118,84,54,31,16,6]
进位:除了最高位,每位逢十进一,本位只留一个数字。
[9,53,74,82,110,122,151,118,84,54,31,16,6]
进位结果:[9, 3, 9, 9, 8, 3, 4, 4, 7, 3, 7, 9, 7]
。
- 相乘的前提: 被乘数位数 >= 乘数位数。 x×y x × y 的逐位相乘次数取决于乘数y的位数。
- 上述大整数相乘思路的代码实现(java):
package com.nwnu.algorithm.divide_and_conquer.bigInteger_multiply;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Scanner;
/** * @Author gaoyF * @Date 2018/7/3 9:28 * @Description 任意大整数相乘 */
public class BigIntegerMultiply {
public static void main(String[] args) {
System.out.print("被乘数:");
Scanner sc_a = new Scanner(System.in);
String x_a = sc_a.nextLine();
System.out.print("乘数:");
Scanner sc_b = new Scanner(System.in);
String x_b = sc_b.nextLine();
//调用multiply()方法计算两个大整数的乘积
String result = multiply_v1(x_a,x_b);
System.out.printf("multiply 乘积:%s",result);
System.out.println('\r');
//计算结果正误验证
BigInteger bi_x_a = new BigInteger(x_a);
BigInteger bi_x_b = new BigInteger(x_b);
System.out.printf("bigInteger 乘积:%s",bi_x_a.multiply(bi_x_b));
}
/** * 模拟手工计算大整数相乘的过程:逐位相乘,然后再进位 * @param x_a 被乘数 * @param x_b 乘数 * @return */
public static String multiply_v1(String x_a,String x_b) {
/** * 始终保证被乘数的位数大于乘数的位数 */
if (x_a.length() < x_b.length()) {
String x_t = x_a;
x_a = x_b;
x_b = x_t;
}
/** * 将字符串形式的被乘数和乘数解析至列表al_a/al_b,并倒序存储 */
ArrayList<Character> al_a = new ArrayList<>();
ArrayList<Character> al_b = new ArrayList<>();
ArrayList<Integer> al_z = new ArrayList<>(); //al_z用来存储被乘数和乘数各位乘积的累加和
for (int i = 0; i < x_a.length() + x_b.length()-1; i++) {
al_z.add(0);
}
for (int i = x_a.length()-1; i >= 0 ; i--) {
al_a.add(x_a.charAt(i));
}
for (int i = x_b.length()-1; i >= 0 ; i--) {
al_b.add(x_b.charAt(i));
}
// System.out.println(al_a);
// System.out.println(al_b);
/** * 被乘数和乘数累积和计算 */
for (int i = 0; i < al_b.size(); i++) {
ArrayList<Integer> al_y = new ArrayList<>(); //al_y用于存储每次累乘完后的结果
//低位补0
if (i != 0) {
for (int k = 0; k < i; k++) {
al_y.add(0);
}
}
for (int j = 0; j < al_a.size(); j++) {
//ASCII码值相减,获得字符数字表示的整型数字
al_y.add(((int)al_a.get(j).charValue()-(int)('0')) * ((int)al_b.get(i).charValue()-(int)('0')));
}
//高位补0
if (al_y.size() != al_z.size()) {
for (int k = al_y.size(); k < al_z.size(); k++) {
al_y.add(0);
}
}
// System.out.println(al_y);
//累加和
for (int k = 0; k < al_y.size(); k++) {
al_z.set(k,al_y.get(k) + al_z.get(k));
}
}
// System.out.println(al_z);
/** * 进位处理 */
for (int i = 0; i < al_z.size()-1; i++) {
if (al_z.get(i) >= 10) {
al_z.set(i+1,al_z.get(i+1) + al_z.get(i)/10);
al_z.set(i,al_z.get(i)%10);
}
}
// System.out.println(al_z);
/** * 返回乘积结果 */
String value = "";
for (int i = al_z.size()-1; i >= 0 ; i--) {
value = value.concat(al_z.get(i).toString());
// System.out.println(value);
}
return value;
}
}