tags:

views:

428

answers:

7

In my project I have to deal with multiplication of bignumbers ( greater then java.long ) stared in my own BigNumber class as int[]. Basically i need to implement something like this :

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

but how to implement it ? I thought about expanding result2,3 with zeros (3140, 15700) and adding them. But first I somehow need to navigate between each digit of y and multiply it by each digit of x.

+2  A: 

I would avoid the headaches of writing your own and just use the java.math.BigInteger class. It should have everything you need.

Mike Clark
Indeed: no need to reinvent the wheel.
Bart Kiers
unfortunately it's a homework and BigInteger as well as BigDecimal is prohibited :/
owca
Good answer, wrong question given the homework requirements.. Could you maybe remove your answer to solicit new answers, Mike?
Tim
A: 

You're going to have to treat each int in the array as a single "digit". Instead of using base 10 where each digit goes from 0 to 9, you'll have to use base 2^32 = 4294967296, where every digit goes from 0 to 4294967295.

I would first implement addition, as your algorithm for multiplication might use addition as an auxiliary.

Danny Roberts
adding is already done. operates on []int .
owca
A: 

As this is for homework I'll give a few hints.

You could approach it the same way you show your example, using strings to hold numbers of any length and implementing:

  • add one number to another
  • multiply as your example by appending zeroes and calling the addition method per step (so for multiply with 20, append the "0" and addd that number twice

The addition method you can build by retrieving the char[] from the strings, allocate a result char[] that is 1 longer than the longest and add like you would do on paper from the end back to the start of both arrays.

The end result will not be the best performing solution, but it it easy to show it is correct and will handle any length numbers (as long they will fit a Java string.)

Update

Ok, if you solved adding two numbers, you could:

  • implement multiplication by 10
  • implement multiplication by repeated addition like in your example

or:

  • implement multiplication by 2 (left shift)
  • implement a binary multiplication via the same concept, only this time x 2 and add once

to illustrate the latter,

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

note that the 1 0 1 are the bits in the number (5) you multiply with and 26 = 13 x 2, 52 = 26 x 2. Your get the idea :-)

rsp
I would like to avoid returning to strings as my add methods also operate on int and they're pretty quick :)
owca
A: 

Since this is homework... Are you sure using an int array is your best shot?
I tried to implement something similar a year ago for performance in a research
project, and we ended up going with concatenated primitives..

Using this you can take advantage of what's already there, and "only" have to worry about overflows near the ends.. This might prove to be fairly simple when you implement your multiplication with <<'s (bit shift lefts) and additions..

Now if you want a real challenge try to implement a modulo... ;)

Tim
+8  A: 

Use the diagonal approach. Make an array, and multiply each digit by each other digit and fill in the numbers in each cell.

36 x 92

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

Add the numbers on each diagonal. Move from the least-significant digit (at the lower right) to the most (upper left).

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)

The answer's 3312.

Make a two-dimensional array of your digits. Fill the array with the multiplications of the single digits together.

Write some logic to scrape the diagonals as I did above.

This should work for arbitrarily large numbers (as long as you still have memory left).

Tenner
+1 interesting algo. Does it have a name? Can't seem to find it in wikipedia.
BalusC
great algo, will try it later.
owca
@BalusC: No idea if it has an actual name; I've just always called it "the diagonal method". I used to teach high school (physics) and had actually never seen this approach to multiplication until a student showed me.
Tenner
Found it, it's called "Lattice Multiplication" or "Gelosia Multiplication": http://en.wikipedia.org/wiki/Lattice_multiplication#Lattice_multiplication
BalusC
@BalusC: Thanks for finding this!
Tenner
A: 

did it my own way :

    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;
    }

then I check the sign.

owca
Your numbers are stored in int arrays with one digit per index. This makes it equivalent to the string method I described. Your inner loop implements a multiplication by the current multiplyer digit, and could be replaced by calling your `add()` method a few times on an array with the digits moved left (multiplied by 10) on each iteration. The result is a much smaller method which uses only the add method to implement multiplication.
rsp
just found that it crashes when multiplied numbers end in 0 or both have zeros, ie 100*110 :/
owca
+1  A: 

Separating out the carrying and the digit multiplication:

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))

Then we can call it:

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))

Yields:

1234762*9879
calc: 12198213798
real: 12198213798

Of course the 10s in the carries function and the implicit decimal representation in prettify are the only thing requiring this to be base 10. Adding an argument could make this base n, so you could switch to base 1000 in order to reduce the numbers of blocks and speed up the calculation.

Phil H