大整数实现加减乘除

2018/03/22 Algorithms 共 5436 字,约 16 分钟

python 实现

# 大整数操作
class BigInt:
    def add(self, a, b):
        i, j = len(a) - 1, len(b) - 1
        carry = 0
        res = []
        while i >= 0 or j >= 0 or carry > 0:
            if i >= 0:
                carry += int(a[i])
                i -= 1
            if j >= 0:
                carry += int(b[j])
                j -= 1
            res.append(str(carry % 10))
            carry = carry // 10
        res = "".join(res[::-1])
        return res

    def multiply(self, a, b):
        if a == "0" or b == "0":
            return "0"

        a = list(a[::-1])
        b = list(b[::-1])
        r = ['0'] * (len(a) + len(b) + 1)
        for i in range(len(a)):
            up = 0
            for j in range(len(b)):
                t = (int(a[i]) - int('0')) * (int(b[j]) - int('0')) + up + int(r[i + j]) - int('0')
                up = t // 10
                r[i + j] = chr(ord('0') + t % 10)
            if up != 0:
                r[i + j + 1] = chr(up + ord('0'))

        res = ''.join(r)
        for i in range(len(res) - 1, -1, -1):
            if res[i] != '0':
                res = res[:i + 1]
                break
        return res[::-1]

    def sub(self, a, b):
        # print("sub ", a,b)
        if a == b:
            return "0"
        isf = False  # a,b互换
        if len(a) < len(b) or (len(a) == len(b) and a < b):
            a, b = b, a
            isf = True

        a = a[::-1]
        b = b[::-1]
        r1 = list(map(int, a))
        r2 = list(map(int, b))
        for i in range(len(r2)):
            if r1[i] >= r2[i]:
                r1[i] = r1[i] - r2[i]
            else:
                r1[i + 1] = r1[i + 1] - 1
                r1[i] = r1[i] - r2[i] + 10
        r1 = list(map(str, r1))
        res = ''.join(r1[::-1])
        for i in range(len(res)):
            if res[i] != '0':
                res = res[i:]
                break
        if isf:
            res = "-" + res
        return res

    def divide(self, a, b):
        res = ""
        if (len(a) == len(b) and a < b) or len(a) < len(b):
            return "0"
        dis = len(a) - len(b)
        len2 = len(b)
        b += "0" * dis

        while dis >= 0:
            sum = 0
            while len(b) < len(a) or (len(a) == len(b) and a >= b):
                sum += 1
                a = self.sub(a, b)
            res += str(sum)
            dis -= 1
            b = b[:len2 + dis]
        # a is the remainder
        # print(" 余数:  " + a)
        for i in range(len(res)):
            if res[i] != '0':
                res = res[i:]
                break
        return res


内部用一个int 数组,每个元素保存DLEN位数字

普通大整数思路

加法

只能是正数,模仿手算加法,用额外一个int保存每个位置相加结果并加到进位上

class Solution {
public:
string addStrings(string num1, string num2) {
    int i = num1.size() - 1;
    int j = num2.size() - 1;
    int carry = 0;
    string res = "";
    while(i>=0 || j>=0 || carry){
        long sum = 0;
        if(i >= 0){sum += (num1[i] - '0');i--;}
        if(j >= 0){sum += (num2[j] - '0');j--;}
        sum += carry; 
        carry = sum / 10;
        sum = sum % 10;
        res =  res + to_string(sum);
    }
    reverse(res.begin(), res.end());
    return res;
}
};

减法

同样是模拟手算,处理借位。用大的减去小的,最后再判断是否需要添加负号。

关键部分

        for(int i=0;i<s2.length();i++)  
        {  
            if(s[i]>=s2[i])  
            s[i]=s[i]-'0'-(s2[i]-'0')+'0';  
            else{  
                s[i+1]=s[i+1]-'0'-1+'0';  
                s[i]=s[i]-'0'+10-(s2[i]-'0')+'0';  
            }  
        }  

乘法

还是模拟手算,第一个字符串的第i位乘以第二个字符串的第j位一定是结果的第i+j位,如果i+j已经有值,直接加上去就OK,别忘了处理进位。

这样的算法的复杂度是O(n2).利用FFT可以将算法优化到O(nlogn),关于FFT的实现在此不再赘述,可以参考算法导论或者 http://www.cnblogs.com/lsx54321/archive/2012/07/20/2601632.html。

关键部分

        for(int i=0;i<s1.length();i++)  
        for(int j=0;j<s2.length();j++)  
        {  
            int temp=(s1[i]-'0')*(s2[j]-'0');  
            s[i+j+1]=s[i+j+1]-'0'+(s[i+j]-'0'+temp)/10+'0';  
            s[i+j]=(s[i+j]-'0'+temp)%10+'0';  
        }  

除法

我们将除法看作是减法来处理,用被减数不断的减去减数,记录减的次数即是商的值。但是我们当然不能一个一个减,因为如果有10000000/1这种情况不是要减到猴年马月。

我们可以记录被减数和减数的位数之差len,将减数扩大10的len倍。然后依次去减,一旦被减数小于减数时,将减数减小10倍,直至到原值。依次循环,去掉前置0,得出结果。

Java实现

import javax.print.DocFlavor;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    /**
     * 大整数减法
     * 注意大减小的肯定长度够所以不需要加
     * @param a
     * @param b
     * @return
     */
    static String sub(String a,String b){
        if(a.compareTo(b)==0){
            return "0";
        }
        boolean isf=false;
        if(a.length()<b.length()||a.length()==b.length()&&a.compareTo(b)<0){
            String t=b;
            b=a;
            a=t;
            isf=true;
        }
//        System.out.println("a ,b:  ==  "+a+" "+b);
        a=new StringBuilder(a).reverse().toString();
        b=new StringBuilder(b).reverse().toString();
        char[] r1=a.toCharArray();
        char[] r2=b.toCharArray();
        for(int i=0;i<r2.length;i++){
            char t1=r1[i];
            char t2=r2[i];
            if(t1>=t2){
                r1[i]=(char)(t1-t2+'0');
            }else{
                r1[i+1]--;
                r1[i]=(char)(t1-t2+'0'+10);
            }
        }
        String res=new StringBuilder(new String(r1)).reverse().toString();

        for(int i=0;i<res.length();i++){
            if(res.charAt(i)!='0'){
                res=res.substring(i,res.length());
                break;
            }
        }
        if (isf){
            res="-"+res;
        }
        return res;

    }

    /**
     * 大整数加法
     * @param a
     * @param b
     * @return
     */
    static String add(String a,String b){
        String res="";
        int i=a.length()-1;
        int j=b.length()-1;
        int carry=0;
        while (i>=0||j>=0||carry>0){
            if(i>=0){
                carry+=a.charAt(i--)-'0';
            }
            if(j>=0){
                carry+=b.charAt(j--)-'0';
            }
            res=String.valueOf(carry%10)+res;
            carry=carry/10;
        }
        return res;
    }

    /**
     * 大整数乘法
     * @param a1
     * @param b1
     * @return
     */
    static String multiply(String a1,String b1){
        if(a1.equals("0")||b1.equals("0")){
            return "0";
        }
        a1=new StringBuilder(a1).reverse().toString();
        b1=new StringBuilder(b1).reverse().toString();
        char[] a=a1.toCharArray();
        char[] b=b1.toCharArray();
        char[] r=new char[a.length+b.length+1];
        Arrays.fill(r,'0');
        int up=0;
        for(int i=0;i<a.length;i++){
            up=0;
            int j;
            for(j=0;j<b.length;j++){
                int t=(a[i]-'0')*(b[j]-'0')+up+r[i+j]-'0';
                up=t/10;
                r[i+j]=(char)('0'+t%10);
            }
            if(up!=0){
                r[i+j]+=up+'0';
            }
        }
        String res=new String(r);
        for(int i=res.length()-1;i>=0;i--){
            if(res.charAt(i)!='0'){
                res=res.substring(0,i+1);
                break;
            }
        }
        res=new StringBuilder(res).reverse().toString();
        return res;
    }

    /**
     *  大整数除法
     * @param a
     * @param b
     * @return
     */
    static String divide(String a,String b){
        String res="";
        if(cmp(a,b)<0){
            return "0";
        }
        int dis=a.length()-b.length();
        int len2=b.length();
        for(int i=0;i<dis;i++){
            b+="0";
        }
        while (dis>=0){
            int sum=0;
            String temp="";
            while (cmp(a,b)>=0){
                sum++;
                a=sub(a,b);
            }
            res=res+String.valueOf(sum);
            dis--;
            b=b.substring(0,len2+dis);
        }
//        a为余数
        System.out.println(" yu:  "+a);
        return res;
    }
    static int cmp(String a,String b){
        if(a.length()==b.length()){
            return a.compareTo(b);
        }else{
            return a.length()-b.length();
        }
    }
    public static void main(String[] args) {
        FileInputStream fin=null;
        try {
            fin=new FileInputStream("D:\\in.txt");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("File not found");
        }
        System.setIn(fin);
        Scanner in=new Scanner(new BufferedInputStream(System.in));
//        int t=in.nextInt();
        while (in.hasNext()){
            String a=in.next();
            String b=in.next();
//            System.out.println(add(a,b));
            System.out.println("Input:  "+a+"  -  "+b);
            System.out.println("Output:  "+divide(a,b));
        }

    }
}

Search

    Table of Contents