作业:如何编写自己的大数字乘法?

时间:2010-01-22 21:03:06

标签: java

在我的项目中,我必须处理我自己的BigNumber类中的大数字(大于java.long)的乘法作为int[]。基本上我需要实现这样的东西:

    157 x
    121 y
   ----
    157 result1
   314  + result2
  157   + result3
 ------
 18997  finalResult

但我该如何实施呢?

我考虑用零(3140,15700)扩展result2,3并添加它们。但首先我需要在y的每个数字之间导航并将其乘以x的每个数字。

11 个答案:

答案 0 :(得分:27)

使用对角线方法。创建一个数组,并将每个数字乘以每个其他数字,并填写每个单元格中的数字。

36 x 92

       3     6
    +-----+-----+
    | 2 / | 5 / |
9   |  /  |  /  |
    | / 7 | / 4 |
    +-----+-----+
    | 0 / | 1 / |
2   |  /  |  /  |
    | / 6 | / 2 |
    +-----+-----+

在每个对角线上添加数字。从最低有效数字(在右下方)移动到最高数字(左上角)。

2                                                                    2 (least-significant)
(6 + 1 + 4) = 11 (make this 1, and carry the 1 to the next digit)    1
(5 + 7 + 0 + 1(carried)) = 13 (make this 3, and carry the 1)         3
2 + 1(carried) = 3                                                   3 (most-significant)

答案是3312。

制作数字的二维数组。使用单个数字的乘法填充数组。

写一些逻辑来刮掉对角线,如上所述。

这适用于任意大数(只要你还有内存)。

答案 1 :(得分:4)

这是我写的代码。基本上与手动乘法相同。将两个大数字作为字符串传递给此函数,结果将作为字符串返回。

public String multiply(String num1, String num2){
        int product, carry=0, sum=0;
        String result = new String("");
        String partial = new String("");
        ArrayList<String> partialList = new ArrayList<String>();

        /* computing partial products using this loop. */
        for(int j=num2.length()-1 ; j>=0 ; j--) {
            for(int i=num1.length()-1 ; i>=0 ; i--) {       

                product = Integer.parseInt((new Character(num1.charAt(i))).toString()) * 
                                Integer.parseInt((new Character(num2.charAt(j))).toString()) + carry;               
                carry = product/10;
                partial = Integer.toString(product%10) + partial;               
            }       

            if(carry != 0)
                partial = Integer.toString(carry) + partial;

            partialList.add(partial);
            partial = "";
            carry = 0;
        }                           

        /* appending zeroes incrementally */
        for(int i=0 ; i<partialList.size() ; i++)
            partialList.set(i, partialList.get(i) + (Long.toString( (long)java.lang.Math.pow(10.0,(double)i))).substring(1)   );        

        /* getting the size of the largest partial product(last) */
        int largestPartial = partialList.get(partialList.size()-1).length();

        /* prefixing zeroes */
        int zeroes;
        for(int i=0 ; i<partialList.size() ; i++) {
            zeroes =  largestPartial - partialList.get(i).length();

            if(zeroes >= 1)
            partialList.set(i, (Long.toString( (long)java.lang.Math.pow(10.0,(double)zeroes))).substring(1) + partialList.get(i)   );
        }

        /* to compute the result */
        carry = 0;
        for(int i=largestPartial-1 ; i>=0 ; i--) {

            sum = 0;
            for(int j=0 ; j<partialList.size() ; j++)
                sum = sum + Integer.parseInt(new Character(partialList.get(j).charAt(i)).toString());

            sum = sum + carry;
            carry = sum/10;         
            result = Integer.toString(sum%10) + result;     
        }

        if(carry != 0)
            result = Integer.toString(carry) + result;

        return result;
    }

答案 2 :(得分:2)

我会避免写自己的麻烦,只使用java.math.BigInteger类。它应该拥有你需要的一切。

答案 3 :(得分:1)

分离携带和数字乘法:

def carries(digitlist):
    digitlist.reverse()
    for idx,digit in enumerate(digitlist):
        if digit>9:
            newdigit = digit%10
            carry = (digit-newdigit)/10
            digitlist[idx] = newdigit
            if idx+1 > len(digitlist)-1:
                digitlist.append(carry)
            else:
                digitlist[idx+1] += carry
    digitlist.reverse()
    return True

def multiply(first,second):
    digits = [0 for place in range(len(first)+len(second))]
    for fid,fdig in enumerate(reversed(first)):
        for sid,sdig in enumerate(reversed(second)):
            offset = fid+sid
            mult = fdig*sdig
            digits[offset] += mult
    digits.reverse()
    carries(digits)
    return digits

def prettify(digitlist):
    return ''.join(list(`i` for i in digitlist))

然后我们可以称之为:

a = [1,2,3,4,7,6,2]
b = [9,8,7,9]
mult = multiply(a,b)
print prettify(a)+"*"+prettify(b)
print "calc:",prettify(mult)
print "real:",int(prettify(a))*int(prettify(b))

收率:

1234762*9879
calc: 12198213798
real: 12198213798

当然carries函数中的10s和prettify中的隐式十进制表示是唯一要求它作为基数10的东西。添加参数可以使这个基数为n,所以你可以切换以1000为基数,以减少块数并加快计算速度。

答案 4 :(得分:0)

您将不得不将数组中的每个int视为单个“数字”。而不是使用每个数字从0到9的基数10,你将不得不使用base 2 ^ 32 = 4294967296,其中每个数字从0到4294967295。

我首先实现加法,因为你的乘法算法可能会使用加法作为辅助。

答案 5 :(得分:0)

由于这是作业,我会给出一些提示。

你可以像展示你的例子一样接近它,使用字符串来保存任意长度的数字并实现:

  • 将一个号码添加到另一个
  • 通过附加零并且每步调用一个加法来乘以你的例子(因此,乘以20,加上“0”并加上该数字两次

你可以通过从字符串中检索char []来构建的添加方法,分配比最长的1更长的结果char [],并添加就像你在纸上做的那样从最后一个回到两个数组的开头

最终结果将不是性能最佳的解决方案,但它很容易显示它是正确的并且将处理任何长度数字(只要它们适合Java字符串。)

<强>更新

好的,如果你解决了添加两个号码的问题,你可以:

  • 实现乘以10
  • 通过重复添加实现乘法,如您的示例

或:

  • 实现乘以2(左移)
  • 通过相同的概念实现二进制乘法,只有这次x 2并且添加一次

说明后者,

  13
   5 x
----
  13 x 1
  26 x 0
  52 x 1
---- +
  65

请注意,1 0 1是您乘以的数字(5)中的位数,26 = 13 x 2,52 = 26 x 2.您明白了: - )

答案 6 :(得分:0)

因为这是作业...你确定使用int数组是最好的镜头吗? 我试图在一年前实施类似的研究表现 项目,我们最终选择了concatenated primitives ..

使用这个你可以利用已经存在的东西,“only”必须担心两端附近的溢出..当你用&lt;实现乘法时,这可能会相当简单。 &lt;(位移左派)和补充......

现在,如果你想要一个真正的挑战try to implement a modulo... ;)

答案 7 :(得分:0)

以我自己的方式做到了:

    int bigger = t1.length;
    int smaller = t2.length;
    int resultLength = bigger + smaller;
    int []resultTemp = new int[resultLength];
    int []result = new int[bigger + smaller];
    int []temporary = new int[resultLength+1];

    int z = resultLength-1;
    int zet = z;
    int step = 0;
    int carry = 0;
    int modulo = 0;

    for(int i=smaller-1; i>=0; i--){
        for(int k = bigger-1; k>= -1; k--){
            if(k == -1 && carry != 0 ){
                resultTemp[z] = carry;
                carry = 0;
                break;
            }
            else if(k == -1 && carry == 0){
                resultTemp[z] = 0;
                break;
            }
            resultTemp[z] = carry + t1[k]*t2[i];
            carry = 0;
            if( resultTemp[z] > 9 ){
               modulo = resultTemp[z] % 10;
               carry = resultTemp[z]/10;
               resultTemp[z] = modulo;
            }
            else{
                resultTemp[z] = resultTemp[z];
            }
            z--;
        }
        temporary = add(resultTemp, result);
        result = copyArray(temporary);
        resultTemp = clear(resultTemp);

        z = zet;
        step++;
        z = z - step;
    }
然后我检查了标志。

答案 8 :(得分:0)

我用C ++实现了这个。请参阅此逻辑......

#include <iostream>
#include <deque>

using namespace std;

void print_num(deque<int> &num) {
  for(int i=0;i < num.size();i++) {
    cout<<num[i];
  }
  cout<<endl;
}

deque<int> sum(deque<int> &oppA, deque<int> &oppB) {
  if (oppA.size() == 0) return oppB;
  if (oppB.size() == 0) return oppA;

  deque<int> result;
  unsigned int carry = 0;

  deque<int>::reverse_iterator r_oppA = oppA.rbegin();
  deque<int>::reverse_iterator r_oppB = oppB.rbegin();
  while ((r_oppA != oppA.rend()) && (r_oppB != oppB.rend())) {

    int tmp = *r_oppA + *r_oppB + carry;
    result.push_front(tmp % 10);
    carry = tmp / 10;

    r_oppB++;
    r_oppA++;

  }
  while (r_oppA != oppA.rend()) {
    int tmp = *r_oppA + carry;
    result.push_front(tmp % 10);
    carry = tmp / 10;
    r_oppA++;
  }

  while (r_oppB != oppB.rend()) {
    int tmp = *r_oppB + carry;
    result.push_front(tmp % 10);
    carry = tmp / 10;
    r_oppB++;
  }

  return result;
}

deque<int> multiply(deque<int>& multiplicand, deque<int>& multiplier) {

  unsigned int carry = 0;
  deque<int> result;
  int deci_cnt = 0;

  deque<int>::reverse_iterator r_multiplier = multiplier.rbegin();
  deque<int> tmp_result;

  while (r_multiplier != multiplier.rend()) {

    for (int i=0; i<deci_cnt ;i++) {
      tmp_result.push_front(0);
    }

    deque<int>::reverse_iterator r_multiplicand = multiplicand.rbegin();
    while (r_multiplicand != multiplicand.rend()) {
      int tmp = (*r_multiplicand) * (*r_multiplier) + carry;
      tmp_result.push_front(tmp % 10);
      carry = tmp / 10;
      r_multiplicand++;
    }

    if (carry != 0) {
      tmp_result.push_front(carry);
      carry = 0;
    }

    result = sum(result, tmp_result);

    deci_cnt++;
    tmp_result.clear();
    r_multiplier++;
  }

  return result;
}

deque<int> int_to_deque(unsigned long num) {
  deque<int> result;

  if (num == 0) {
    result.push_front(0);
  }

  while (num > 0) {
    result.push_front(num % 10);
    num = num / 10;
  }

  return result;
}

int main() {

  deque<int> num1 = int_to_deque(18446744073709551615ULL);
  deque<int> num2 = int_to_deque(18446744073709551615ULL);

  deque<int> result = multiply(num1, num2);
  print_num(result);

  return 0;
}

输出:340282366920928463426481119284349108225

答案 9 :(得分:0)

您可以查看以下解决方案,该解决方案教会我们乘法和添加更大的数字。请评论是否可以改进。

public static void main(String args[]) {

    String s1 = "123666666666666666666666666666666666666666666666669999999999999999999999999666666666666666666666666666666666666666666666666666666666666666666";
    String s2 = "45688888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888";
    System.out.println(multiply(s1, s2));
}

private static String multiply(String s1, String s2) {

    int[] firstArray = convert(s1);
    int[] secondArray = convert(s2);
    //System.out.println(Arrays.toString(firstArray));
    //System.out.println(Arrays.toString(secondArray));
    // pass the arrays and get the array which is holding the individual
    // rows while we multiply using pen and paper
    String[] result = doMultiply(firstArray, secondArray);
    //System.out.println(Arrays.toString(result));

    // Now we are almost done lets format them as we like

    result = format(result);
    //System.out.println(Arrays.toString(result));

    //Add elements now and we are done
    String sum="0";
    for(String s:result){
        sum=add(sum,s);
    }

    return sum;
}

private static String[] doMultiply(int[] firstArray, int[] secondArray) {

    String[] temp = new String[secondArray.length];

    for (int i = secondArray.length - 1; i >= 0; i--) {

        int result = 0;
        int carry = 0;
        int rem = 0;
        temp[secondArray.length - 1 - i] = "";
        for (int j = firstArray.length - 1; j >= 0; j--) {
            result = (secondArray[i] * firstArray[j]) + carry;
            carry = result / 10;
            rem = result % 10;
            temp[secondArray.length - 1 - i] = rem
                    + temp[secondArray.length - 1 - i];
        }
        // if the last carry remains in the last digit
        if (carry > 0)
            temp[secondArray.length - 1 - i] = carry
                    + temp[secondArray.length - 1 - i];
    }

    return temp;
}

public static int[] convert(String str) {

    int[] arr = new int[str.length()];
    for (int i = 0; i < str.length(); i++) {
        arr[i] = Character.digit(str.charAt(i), 10);
    }

    return arr;
}

private static String[] format(String[] result) {

    for (int i = 0; i < result.length; i++) {
        int j = 0;
        while (j < i) {
            result[i] += "0";
            j++;
        }
    }

    return result;
}

public static String add(String num1, String num2) {

    //System.out.println("First Number :" + num1);
    //System.out.println("Second Number :" + num2);

    int max = num1.length() > num2.length() ? num1.length() : num2.length();

    int[] numArr1 = new int[max];
    int[] numArr2 = new int[max];

    for (int i = 0; i < num1.length(); i++) {
        numArr1[i] = Integer.parseInt(""
                + num1.charAt(num1.length() - 1 - i));
    }
    for (int i = 0; i < num2.length(); i++) {
        numArr2[i] = Integer.parseInt(""
                + num2.charAt(num2.length() - 1 - i));
    }

    int carry = 0;
    int[] sumArr = new int[max + 1];

    for (int k = 0; k < max; k++) {
        int tempsum = numArr1[k] + numArr2[k] + carry;
        sumArr[k] = tempsum % 10;
        carry = 0;
        if (tempsum >= 10) {
            carry = 1;
        }
    }
    sumArr[max] = carry;

/*  System.out.println("Sum :"
            + new StringBuffer(Arrays.toString(sumArr)).reverse()
            .toString().replaceAll(",", "").replace("[", "")
            .replace("]", "").replace(" ", ""));*/
    return new StringBuffer(Arrays.toString(sumArr)).reverse().toString()
            .replaceAll(",", "").replace("[", "").replace("]", "")
            .replace(" ", "");
}

答案 10 :(得分:0)

我认为这会对你有帮助

import java.util.ArrayList;
import java.util.List;

public class Multiply {


static int len;
public static void main(String[] args) {
      System.out.println(multiply("123456789012345678901","123456789012345678901");
}

private static ArrayList<Integer> addTheList(List<ArrayList<Integer>> myList) {
    ArrayList<Integer> result=new ArrayList<>();

    for(int i=0;i<len;i++)
    {
        result.add(0);

    }
    int index=0;
    for(int i=0;i<myList.size();i++)
    {
        ArrayList<Integer> a=new ArrayList<>(myList.get(index));
        ArrayList<Integer> b=new ArrayList<>(myList.get(index+1));
        for (int j = 0; j < a.size()||j < b.size(); i++) {
            result.add(a.get(i) + b.get(i));
    }

    }

    return result;
}

private static ArrayList<Integer> multiply(ArrayList<Integer> list1, Integer integer) {
    ArrayList<Integer> result=new ArrayList<>();
    int prvs=0;
    for(int i=0;i<list1.size();i++)
    {
        int sum=(list1.get(i)*integer)+prvs;
        System.out.println(sum);
        int r=sum/10;
        int m=sum%10;

        if(!(r>0))
        {

            result.add(sum);                
        }
        else
        {
            result.add(m);
            prvs=r;
        }
        if(!(i==(list1.size()-1)))
        {
            prvs=0;
        }

    }
    if(!(prvs==0))
    {
        result.add(prvs);
    }
    return result;
}

private static ArrayList<Integer> changeToNumber(String str1) {
    ArrayList<Integer> list1=new ArrayList<>();
    for(int i=0;i<str1.length();i++)
    {

        list1.add(Character.getNumericValue(str1.charAt(i)));
    }
    return list1;

}
public static String multiply(String num1, String num2) {
    String n1 = new StringBuilder(num1).reverse().toString();
    String n2 = new StringBuilder(num2).reverse().toString();

    int[] d = new int[num1.length()+num2.length()];

    //multiply each digit and sum at the corresponding positions
    for(int i=0; i<n1.length(); i++){
        for(int j=0; j<n2.length(); j++){
            d[i+j] += (n1.charAt(i)-'0') * (n2.charAt(j)-'0');
        }
    }

    StringBuilder sb = new StringBuilder();

    //calculate each digit
    for(int i=0; i<d.length; i++){
        int mod = d[i]%10;
        int carry = d[i]/10;
        if(i+1<d.length){
            d[i+1] += carry;
        }
        sb.insert(0, mod);
    }

    //remove front 0's
    while(sb.charAt(0) == '0' && sb.length()> 1){
        sb.deleteCharAt(0);
    }

    return sb.toString();
}
}