大数乘法

大数乘法
基本思想:
输入字符串,转成char数组,转成int数组。采用分治思想,每一位的相乘;

  • 公式:AB*CD = AC (BC+AD) BD

=任意位数的整数相乘,最终都是可以转化为两位数相乘。但是,不同位的两位数乘的结果,最后应该如何拼接呢?这需要我们来找下更深层次的规律。分析一下四位数的乘法

             1  2  3  4 
          *  5  6  7  8 
 ------------------------ 
              9  8  7  2 
          8  6  3  8 
      7  4  0  4 
 6  1  7  0 
 ------------------------ 
 7  0  0  6  6  5  2 

结果看起来没什么特别的,如果按照我们分治的思想,转换为两位数相乘,之间能否有些关系呢?
1234分为 12(高位)和34(低位);5678分为56(高位)和78(低位)
高位高位结果:1256=672
高位低位+低位高位:1278+3456=936+1094=2840
低位低位结果:3478=2652

最后,拼接。需要说明的是,刚才我们提到两位数分解成一位数相乘的规则:超过一位数,需要进位。同理(这里就不证明了),两位数乘以两位数,结果超过两位数,也要进位。
从低位开始:低两位:2652,26进位,低位保留52;中间两位,2840+26(低位进位)=2866,28进位,中位保留66;高位,672+28(进位)=700,7进位,高位保留00。再往上就没有了,现在可以拼接起来:最高位进位7,高两位00,中位66,低位52,最后结果:7006652。

规律

任意位数(例如N位整数相乘),都可以用这种思想实现:低位保留 N 位数字串,多余高位进位;高位要加上低位进位,如果超过 N 位,依然只保留 N 位,高位进位。(如果是M位整数乘以N位整数怎么办?高位补0,凑成一样位数的即可,不赘述。)

代码如下:

import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class  multipliers {
 
    // 规模只要在这个范围内可以直接计算(整型数值满足)
    private final static int SIZE = 4;
 
    // 其中,len为X、Y的长度最大值
    private static String bigIntMultiply(String X, String Y, int len) {
        String str = "";
 
        if (len <= SIZE) { // 少于4位数,可直接计算
            return "" + (Integer.parseInt(X) * Integer.parseInt(Y));
        }
 
        if (X.length() != Y.length()) { // 长度不同,调用formatNumber方法,补齐X、Y,使之长度相同
            X = formatNumber(X, len);
            Y = formatNumber(Y, len);
        }
 
        // 将X、Y分别对半分成两部分
        int len1 = len / 2;
        int len2 = len - len1;
        String A = X.substring(0, len1);
        String B = X.substring(len1);
        String C = Y.substring(0, len1);
        String D = Y.substring(len1);
 
        // 乘法法则,分块处理
        int lenM = Math.max(len1, len2);
        String AC = bigIntMultiply(A, C, len1);
        String AD = bigIntMultiply(A, D, lenM);
        String BC = bigIntMultiply(B, C, lenM);
        String BD = bigIntMultiply(B, D, len2);
 
        // 注意处理进位的方法,巧妙地运用了字符串的拼接方面
        // 【1】 处理BD,得到原位及进位
        String[] sBD = dealString(BD, len2);
        // 【2】 处理AD + BC的和
        String ADBC = add(AD, BC);
        // 【3】 加上BD的进位
        if (!"0".equals(sBD[1])) {
            ADBC = add(ADBC, sBD[1]);
        }
        // 【4】 得到ADBC的进位
        String[] sADBC = dealString(ADBC, lenM);
 
        // 【5】 AC加上ADBC的进位
        AC = add(AC, sADBC[1]);
        // 【6】 最终结果
        str = AC + sADBC[0] + sBD[0];
 
        return str;
    }
 
    // 两个数字串按位加
    private static String add(String ad, String bc) {
        // 返回的结果
        String str = "";
 
        // 两字符串长度要相同
        int lenM = Math.max(ad.length(), bc.length());
        ad = formatNumber(ad, lenM);
        bc = formatNumber(bc, lenM);
 
        // 按位加,进位存储在flag中
        int flag = 0;
        // 按序从后往前按位求和
        for (int i = lenM - 1; i >= 0; i--) {
            int t = flag + Integer.parseInt(ad.substring(i, i + 1))
                    + Integer.parseInt(bc.substring(i, i + 1));
            // 结果超过9,则进位当前位,保留个位数
            if (t > 9) {
                flag = 1;
                t = t - 10;
            } else {
                flag = 0;
            }
            // 拼接结果字符串
            str = "" + t + str;
        }
        if (flag != 0) {
            str = "" + flag + str;
        }
        return str;
    }
 
    // 处理数字串,分离出进位,String数组第一个为原位数字,第二个为进位
    private static String[] dealString(String ac, int lenn) {
        String[] str = { ac, "0" };
 
        if (lenn < ac.length()) {
            int t = ac.length() - lenn;
            str[0] = ac.substring(t);
            str[1] = ac.substring(0, t);
        } else {
            // 保证结果length与lenn一致,少于则高位补0
            String result = str[0];
            for (int i = result.length(); i < lenn; i++) {
                result = "0" + result;
            }
            str[0] = result;
        }
        return str;
    }
 
    // 格式化操作的数字字符串,高位补零
    private static String formatNumber(String x, int len) {
        while (len > x.length()) {
            x = "0" + x;
        }
        return x;
    }
 
    public static void main(String[] args) {
        String pat = "^[1-9]\\d*$"; // 正则表达式:不以0开头的数字串
        Pattern p = Pattern.compile(pat); // 将给定的正则表达式编译并赋予给Pattern类
 
        System.out.println("乘数A(不以0开头的正整数):");
        Scanner sc = new Scanner(System.in);
        String A = sc.next();
        Matcher m = p.matcher(A);
 
        if (!m.matches()) {
            System.out.println("数字不合法!");
            return;
        }
 
        System.out.println("乘数B(不以0开头的正整数):");
        String B = sc.next();
        m = p.matcher(B);
        if (!m.matches()) {
            System.out.println("数字不合法!");
            return;
        }
        // Math.max(A.length(), B.length())比较读入的字符串的长短
        System.out.println(A + " * " + B + " = "
                + bigIntMultiply(A, B, Math.max(A.length(), B.length())));
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容