java大整数四则运算

前言:
目前计算机中数据存储最大为64位,对超过64位的数进行运算就会导致运算结果错误。所以针对大整数进行四则运算是十分必要的。这也是面试中非常经典的问题,所以这次我们特意整理了关于大整数的四则运算。所谓的大整数的运算其实就是模拟了人脑进行数字计算用到的规则。

1.大整数的存储
由于后续很多运算都是从低位开始,所以我们设计该存储方式为从低位向高位依次存放在数组。

public class bigInt{
int [] data=null;//存放数据(从低位到高位依次存放)
int symbol=1;//1代表整数,0代表负数
}

2.判断大整数大小
大整数的绝对值大小判断在后面将大量的应用到,后续运算都是按照第一操作数大于第二操作数(无符号数)。java中提供了comparable接口比较大小,所以我们实现接口即可。

3.大整数类设计与实现

class bigInt implements Comparable<bigInt>{
int [] data=null;//存放数据(逆序放置)
int symbol=1;//1代表整数,0代表负数
public bigInt(){

}
public bigInt(String value){
    examSymbol(value);
}
public void examSymbol(String value){//检测符号问题
    int start=0;//数据的开始位置
    char head=value.charAt(0);
    if(head=='+'||head=='-'){
        start=1;
        if(head=='-')
            symbol=-1;
    }
    int len=value.length()-start;
    data=new int[len];//数据长度为Len
    for(;start<value.length();start++){
        data[--len]=value.charAt(start)-'0';
    }
}
@Override
public int compareTo(bigInt b1) {//比较的是绝对值
    //找到最高位的第一个非0开始
    int a_max=findMax(this.data);
    int b_max=findMax(b1.data);
    if(a_max!=b_max)
        return a_max>b_max?1:-1;
    //从高位开始比较
    int c1,c2;
    for(int k=a_max;k>=0;k--){
        c1=this.data[k];
        c2=b1.data[k];
        if (c1!=c2)
            return c1>c2?1:-1;
    }
    return 0;
}
#大整数中有效数字位,最高位不为0
public int findMax(int []data){
    int m=data.length-1;
    for(;m>=0;m--){
        if(data[m]!=0)
            return m;
    }
    return 0;
}
@Override
public String toString() {
    char symbol='+';
    if (symbol==-1)
        symbol='-';
    StringBuilder sb=new StringBuilder();
    sb.append(symbol);
    int k=findMax(data);//找到第一个不为0的高位
    for(;k>=0;k--){//从高位到低位依次输出
        sb.append(data[k]);
    }
    return sb.toString();
}

4.大整数同号相加
思路:假设大整数为a1,a2,默认|a1|>|a2|,先比较大小,若|a1|<|a2|,则交换2个操作数顺序,始终保持第一操作数大于第二操作数。

加法规则:分别从2个数的低位开始进行逐位相加,并加上前一位的进位,如果相加和超过9,则记录进位数,用于下一次进位。最后,如果最高位产生进位,则在最高位前面添加一个最高位1。

public bigInt unSignAdd(bigInt b1,bigInt b2){
   //   保存累加的结果
    StringBuilder sb=new StringBuilder();
//  if(b1.compareTo(b2)<0){//默认b1>b2
//      bigInt temp=b1;
//      b1=b2;
//      b2=temp;
//  }
    int m=b1.data.length;
    int n=b2.data.length;
    //从低位开始相加,设置进位
    int carry=0;//记录上一位的进位
    int b1_v,b2_v=0;
    int currentv=0;//当前位累加和
    for(int i=0;i<m;i++){
        b2_v=0;
        b1_v=b1.data[i];
        if(i<n)
            b2_v=b2.data[i];
        currentv=b1_v+b2_v+carry;
        if(currentv>9){//当前和产生进位
            carry=currentv/10;
            currentv=currentv%10;
        }
        else
            carry=0;  //当前位未产生进位,则置标记
        sb.insert(0,currentv);
    } //end for
    //如果2数相加最高位产生进位
    if(carry==1){
        sb.insert(0,1);
    }
    char symbol='+';//同号加法
    if(b1.symbol==-1)
        symbol='-';
    sb.insert(0,symbol);
    return new bigInt(sb.toString());
}

5.大整数异号相加
设a1,a2为2个大整数,且2符号相反,|a1|>=|a2|,如果|a1|=|a2|,则结果为0。如果不等,则按照下面规则进行运算。使用无符号大数-无符号小数,最后运算结果的符号有绝对值大的数的符号来决定。

假设我们计算3+(-2),由于2个操作数异号,则进行减法法则3-2=1,最后结果符号根据3来决定,所以结果为1。
所以这里异号相加需要使用大整数减法的法则。

减法规则:分别从2个数的低位开始进行逐位相减,并减去前一位的借位,如果值小于0,则向高位借一位,记录借位数值。最后结果符号由大数(绝对值)决定。

public bigInt unSignSub(bigInt b1,bigInt b2){
    StringBuilder sb=new StringBuilder();
//  if(b1.compareTo(b2)<0){//默认b1>b2
//      bigInt temp=b1;
//      b1=b2;
//      b2=temp;
//  }
    int borrow=0;
    int m=b1.data.length;
    int n=b2.data.length;
    int b1_v,b2_v;//当前对应位的值
    int currentV=0;
    for(int i=0;i<m;i++){
        b1_v=b1.data[i];
        b2_v=0;
        if(i<n)
            b2_v=b2.data[i];
        currentV=b1_v-b2_v-borrow;//相减之和的当前位的值
        if(currentV<0){//该位不够减
            currentV=currentV+10;//向高位借
            borrow=1;//借位1
        }
        else{
            borrow=0;
        }
        sb.insert(0,currentV);
    }
    //结果符号由大数符号决定
    char symbol=b1.symbol==1?'+':'-';
    sb.insert(0,symbol);
    return new bigInt(sb.toString());
}

6.大整数有符号相加
有符号大整数a1,a2相加的计算规则更负责些。根据a1,a2(|a1|>|a2|)是否同号指定不同的计算规则。
1)a1,a2同号,则直接使用上面的大整数无符号相加的规则。
2)a1,a2异号.则使用大整数异号规则处理。

/**
 * 有符号的加法
 * @return
 */
public bigInt add(bigInt b1,bigInt b2){
    int c=b1.compareTo(b2);
    if(c<0){ //保证大数在前,小数在后
        bigInt temp=b1;
        b1=b2;
        b2=temp;
    }
    //判断是否同号
    if(b1.symbol*b2.symbol==-1){//异号
        if(c==0)//a1,a2的绝对值相等,则结果为0
            return new bigInt("0");
        return unSignSub(b1,b2);
    }
    else//同号
    return unSignAdd(b1,b2);
}

7.大整数有符号减法
减法可以转化为加法进行运算,如3-5=3+(-5),这样就就转化为加法进行运算。即只需要将第二操作数符号反置即可。

/**
 * 有符号减法
 */
public bigInt sub(bigInt b1,bigInt b2){
    b2.symbol*=-1;
    bigInt r=add(b1,b2);//变成加法运算
    b2.symbol*=-1;//将修改的符号变过来
    return r;
}

8.大整数乘法

乘法法则:模拟手动计算乘法,乘数每一位与被乘数每一相乘的结果累加到相应位上。最后再针对每一位上的结果进行进位即可。

乘法过程:
这里写图片描述

/**
 * 大整数相乘
 * @param a1
 * @param a2
 * @return
 */
public bigInt multi(bigInt b1,bigInt b2){
    //大数放前面
    if(b1.compareTo(b2)<0){
        bigInt temp=b1;
        b1=b2;
        b2=temp;
    }
    int m=b1.data.length;
    int n=b2.data.length;
    int []result=new int[m+n];
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            result[i+j]+=b1.data[i]*b2.data[j];
        }
    }
    //考虑进位
    int carry=0;
    StringBuilder sb=new StringBuilder();
    for(int k=0;k<m+n;k++){
        result[k]+=carry;
        if(result[k]>9){
            carry=result[k]/10;
            result[k]=result[k]%10;
        }
        else
            carry=0;
        sb.insert(0,result[k]);
    }
    bigInt r=new bigInt(sb.toString());
    r.symbol=b1.symbol*b2.symbol;
    return r;   
}

9.大整数除法
采用试商法,设被除数为d,除数为v,从高位开始取被除数的下一位与当前余数连接形成p,
规则:用试商法求p除以除数v如果p大于v,使用递减法(不断使用p=p-v)来求出p/v的商。记录当前的商和余数,以此类推,直到计算完最后一位。

除法过程:
这里写图片描述

public bigInt div(bigInt b1,bigInt b2){
    int m=b1.data.length;
    int n=b2.data.length;
    StringBuilder result=new StringBuilder();//保存商
    bigInt yu=new bigInt(); //存放余数
    yu.data=new int[n+1];//余数位数为除数+1
    int k=0;
    for(int i=m-1;i>=0;i--){ //从高位开始
    //确保余数的位数为n+1位,如果不等则进行复制
        if(yu.data.length!=n+1){
            int len=yu.findMax(yu.data);
            int mydata[]=new int[n+1];
            for(i=0;i<=len;i++){
                mydata[i]=yu.data[i];
            }
            yu.data=mydata;
          }
//将取得的数放入低位和余数构成被除数p
System.arraycopy(yu.data,0,yu.data,1,n);
        yu.data[0]=b1.data[i];
        k=0;//试商的结果
        while(yu.compareTo(b2)>=0){
            yu=sub(yu,b2);//不断相减,来求商.
            k+=1;
        }
        result.append(k);
    }
    return new bigInt(result.toString());   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值