基础算法,大数加法和乘法的实现

来源:互联网 发布:淘宝营销思路 编辑:程序博客网 时间:2024/04/28 01:32

计算机中的基本数据类型都是定长的,比如long 64位 int32位。如果只使用基本的数据类型,那就只能实现操作数和结果都在 这个长度之内加法或乘法。虽然 int可以达到20亿数量级,可是如果数字更大呢?如果数字大到连long 都装不下呢?

表示数据应该不成问题,一个int 表示不了,那么可以用多个int 也就是 int[] 来表示,数组的长度取决于数字大小。

下面来决绝运算问题,先从最简单的搞起。。加法

算法直接给出

    private static int[] add(int[] x, int[] y) {
        // If x is shorter, swap the two arrays
        if (x.length < y.length) {
            int[] tmp = x;
            x = y;
            y = tmp;
        }


        int xIndex = x.length;
        int yIndex = y.length;
        int result[] = new int[xIndex];
        long sum = 0;


        // Add common parts of both numbers
        while(yIndex > 0) {
            sum = (x[--xIndex] & LONG_MASK) + 
                  (y[--yIndex] & LONG_MASK) + (sum >>> 32);
            result[xIndex] = (int)sum;
        }


        // Copy remainder of longer number while carry propagation is required
        boolean carry = (sum >>> 32 != 0);
        while (xIndex > 0 && carry)
            carry = ((result[--xIndex] = x[xIndex] + 1) == 0);


        // Copy remainder of longer number
        while (xIndex > 0)
            result[--xIndex] = x[xIndex];


        // Grow result if necessary
        if (carry) {
            int bigger[] = new int[result.length + 1];
            System.arraycopy(result, 0, bigger, 1, result.length);
            bigger[0] = 0x01;
            return bigger;
        }
        return result;
    }


可以这么理解,类比10进制加法,10进制加法的规则是 相同的位数相加

比如 10进制数,我们定义 10 进制数组 位 int10[]

int10[] a,int10[] b int10[c]

c=a+b

回忆小学知识,列出下列等式

c[i]=a[i]+b[i]+d[i-1]

其中d[i-1]是a[k-1]+b[i-1] 的进位

那么,我们可以类比来看了,既然 10进制数组可以这样运算,为什么 11进制不可以呢?为什么20进制不可以呢,为什么2^32 进制不可以呢?

当然可以。

我们把数组中的一个整数看成一个位,于是一切都清晰了,关键就在这几行代码。

        while(yIndex > 0) {
            sum = (x[--xIndex] & LONG_MASK) + 
                  (y[--yIndex] & LONG_MASK) + (sum >>> 32);
            result[xIndex] = (int)sum;
        }

其中 (sum >>> 32) 是计算这次加法的溢出部分,溢出部分就是要进位的部分,在加法中进位或者是1 或者是0.

这样,计算时间复杂度和空间复杂度都是 O(n)。

我们将问题延伸一下,来计算下乘法


    private int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
        int xstart = xlen - 1;
        int ystart = ylen - 1;


        if (z == null || z.length < (xlen+ ylen))
            z = new int[xlen+ylen];
        
        long carry = 0;
        for (int j=ystart, k=ystart+1+xstart; j>=0; j--, k--) {
            long product = (y[j] & LONG_MASK) *
                           (x[xstart] & LONG_MASK) + carry;
            z[k] = (int)product;
            carry = product >>> 32;
        }
        z[xstart] = (int)carry;

//关键代码在这里
        for (int i = xstart-1; i >= 0; i--) {
            carry = 0;
            for (int j=ystart, k=ystart+1+i; j>=0; j--, k--) {
                long product = (y[j] & LONG_MASK) * 
                               (x[i] & LONG_MASK) + 
                               (z[k] & LONG_MASK) + carry;
                z[k] = (int)product;
                carry = product >>> 32;
            }
            z[i] = (int)carry;
        }

////////////////////////////////////
        return z;
    }


上面标注关键代码部分 其实就是乘法法则描述的,把每一个整数看成一位来处理




原创粉丝点击