Java大数相乘——不用BigInteger方法

本文详细介绍了一种在Java中实现大数相乘的算法,该算法不使用BigInteger类,而是通过字符串处理和数学运算来完成。文章以123乘以456为例,解释了如何将字符串倒置、转换为字符数组,并通过多重循环计算乘积,处理进位,最后将结果逆序转换回字符串。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java大数相乘(不使用BigInteger)

作者:黑衣侠客


一.前言

此次Java大数相乘,完全用算法实现,不使用Java大数计算的关键字方法,算法开始很难理解,不过彻彻底底的把每一步过一遍,感觉算法还是很容易的。

二.算法

我们以123乘以456为例:

在这里插入图片描述

在这里我们将123,和456以字符串的形式存储在String中,然后通过再将String类型转为StringBuffer类型,通过StringBuffer的reverse方法,将123,456倒置,然后存储在char[]数组中,这样就会成为654,123,然后我们知道这两个三位数相乘,得到数的长度一定小于两数长度之和,这也就是我每行画了6个格子的含义,同时我在每个乘数的下端都标记了他们在char[]数组中的存储位置。接下来看最右侧红框里的数18,他是在0位置的数字3和在另一个char数组中0位置的数字6相乘得来的,同样,靠着1815是下标为0的数字3和下标为1的数字5相乘的来的,以此类推…
从以上叙述中,我们可以根据每个结果的下标得出一个规律,可以看出,红框的每一列的下标和都是相等的,因此我们可以得出这段代码:
for(int i =0;i<len1;i++){
    for(int j =0;j<len2;j++){
        result[i+j]+=(int)(num1[i]-'0')*(int)(num2[j]-'0');
        //其中result[]是用来存储红框内数据每一列的和,详情见下图
    }
}

在这里插入图片描述

result[]是用来存储18,27,28,13,4(按result的存储顺序),其中后面空的一位默认为0。

现在我们处理进位的问题:

由于我们现在采用的是倒置的,所以18其实是个位,因此,个位保留8将10进位到27里,27变为28,而28为十位,保留8,将20进位到28,28变为30,30为百位,保留0,将30进位到13,13变为16,16在保留6,再次进位,4变为5。代码如下:
int leng = result.length;
//开始取余
for(int i=0;i<leng;i++){
    if(result[i]>=10){
        result[i+1]+=result[i]/10;
        result[i]%=10;
    }
}
目前,大致思路已经差不多了,接下来,该将逆序变为正序了,通过StringBuffer的append方法,将字符串变为正序,但是,仔细看会发现,存进去的是 ‘0’,‘5’,‘6’,‘0’,‘8’,‘8’ ,首位的0,是因为我们开始定义result数组长度为6,但只使用了前5个,第六个位置默认值为0,所以在正序之后自然跑到前面来了,因此在将逆序转成正序传入StringBuffer中时,需要加一个判断,代码如下:
//开始倒置,将result中的数组倒置存入StringBuffer
StringBuffer sb = new StringBuffer();
boolean bool = true;
for(int i=leng-1;i>=0;i--){
    if(result[i]==0&&bool){
        continue;
    }
    sb.append(result[i]);
    bool=false;
}
至此,大数相乘的算法思路,已经讲完了,还有一些判断正负号的方法,在具体代码中写的很清楚,虽然代码不长,但是整体思路理解起来还是挺困难的,不过现在理解了,总比开始时不知从哪下手的感觉要好得多,至少心态不崩了。接下来我会将具体代码写到下面。

三.具体代码

import java.util.Scanner;

public class question_test {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String num1 = sc.next();
        String num2 = sc.next();
        String num  = bigNumMultiplication(num1,num2);
        System.out.println(num);
    }
    public static String bigNumMultiplication(String f,String s){
        //获取首字母,判断是否是符号位
        char signA = f.charAt(0);
        char signB = s.charAt(0);
        char sign = '+';
        if(signA=='+'||signA=='-'){
            sign = signA;
            f=f.substring(1);//使f返回一个子字符串,该字符串从原始字符串的第二位开始,一直到结尾结束(substring(索引))
        }
        if(signB=='+'||signB=='-'){
            if(signB==sign){
                sign ='+';
            }else{
                sign ='-';
            }
            s=s.substring(1);
        }
        //将大数翻转并转换成字符数组
        char[] num1 =  new StringBuffer(f).reverse().toString().toCharArray();
        //字符串内容较长的时候,特别是这个字符串是动态拼接的时候,用String可能发生内存不够的错误,这种情况必须用stringbuffer
        char[] num2 =  new StringBuffer(s).reverse().toString().toCharArray();
        //StringBuffer()的reverse方法作用是:使StringBuffer中的内容进行反转
        int len1 = num1.length;
        int len2 = num2.length;
        int [] result = new int[len1+len2];
        //计算最终最大长度
        //开始做乘法
        for(int i =0;i<len1;i++){
            for(int j =0;j<len2;j++){
                result[i+j]+=(int)(num1[i]-'0')*(int)(num2[j]-'0');
                //用a[i]-'0'的作用是:如果直接转a[i]为int型那么只会显示a[i]所对应的ASCLL码值,减去字符0的ASCLL码值,正好为改数字,然后再转int型

            }
        }
        int leng = result.length;
        //开始取余
        for(int i=0;i<leng;i++){
            if(result[i]>=10){
                result[i+1]+=result[i]/10;
                result[i]%=10;
            }
        }
        //开始倒置,将result中的数组倒置存入StringBuffer
        StringBuffer sb = new StringBuffer();
        boolean bool = true;//该字段用于标识是否有前置0,如果是0就不需要打印或者存储下来
        for(int i=leng-1;i>=0;i--){
            if(result[i]==0&&bool){
                continue;
            }
            sb.append(result[i]);
            bool=false;
        }
        if(!sb.toString().equals("")){
            if(sign=='-'){
                sb.insert(0,sign);
            }
        }else{
            sb.append(0);
        }
        return sb.toString();
    }
}
注:大家有什么更好的思路或是想法的,欢迎在下方留言。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值