简体   繁体   中英

Understanding vector multiplication

I have to perform multiplication by using vectors in c++, so for example to multiply the numbers 123 and 528, I have to store each number in a vector and multiply them. A multiplication algorithm was provided by my instructor. The first line of the following paragraph may look a bit confusing, but I want to let you know that I am just working on overloading the operator* to perform multiplication between two numbers by using vectors.

Multiplication in ubigint::operator* proceeds by allocating a new vector whose size is equal to the sum of the sizes of the other two operands. If u is a vector of size m and v is a vector of size n, then in O(mn)speed, perform an outer loop over one argument and an inner loop over the other argument, adding the new partial products to the product p as you would by hand. The algorithm can be described mathematically as follows:

p ←Φ   
for i ∈ [0, m):  
 c ← 0  
   for j ∈ [0, n):  
     d ← p_{i+ j} + u_iv_j + c  
     p_{i+ j} ← d % 10  
     c ← ceil(d÷10)  
  p_{i+n} ← c  

Note that the interval [a,b)refers to the set {x|a ≤ x < b}, ie, to a half-open interval including a but excluding b. In the same way, a pair of iterators in C++ bound an interval.

The problem is that I don't quiet understand how this algorithm works. For example, what is u_iv_j?. Can anybody clear this up?

Think of your algorithm as a formal description of how you multiply large numbers:

for i ∈ [0, m):                  # For every digit of the first number
   c ← 0                         # Initialize the carry
   for j ∈ [0, n):               # For every digit of the second number
     d ← p_{i+j} + u_i * v_j + c # Compute the product of the digits + carry + previous result
     p_{i+j} ← d % 10            # extract the lowest digit and store it
     c ← ceil(d÷10)              # carry the higher digits
 p_{i+n} ← c                     # In the end, store the carry in the
                                 # highest, not yet used digit

I left out some details (order of the operations, ...), but I can add them if necessary.

EDIT: To clarify what I meant, I'll show what the code does for 56*12: p gets initialized with 0

i = 0:                       # Calculate 6 * 12
  carry = 0
  j = 0:                     # Calculate 6 * 2
    d = p{0} + 6 * 2 + carry # == 0 + 12 + 0
    p{0} = d % 10            # == 2
    carry = ceil(d/10)       # == 1
  j = 1:                     # Calculate 6 * 1 + carry
    d = p{0} + 6 * 1 + carry # == 0 + 6 + 1
    p{1} = d % 10            # == 7
    carry = ceil(d/10)       # == 0
  p{2} = carry               # == 0
i = 1:                       # Calculate 5 * 12
  carry = 0
  j = 0:                     # Calculate 5 * 2
    d = p{1} + 5 * 2 + carry # == 7 + 10 + 0
    p{1} = d % 10            # == 7
    carry = ceil(d/10)       # == 1
  j = 1:                     # Calculate 5 * 1
    d = p{2} + 5 * 1 + carry # == 0 + 5 + 1
    p{2} = d % 10            # == 6
    carry = ceil(d/10)       # == 0
  p{3} = carry               # == 0

For i = 0, we calculated 6 * 12 = 72, for i = 1, we calculated 5 * 12 = 60.

Since 5 is in the second digit, we actually calculated 50 * 12 = 600. Now we need to add the results (ie 72 + 600), this is why I mentioned the previous value: After the first run of the loop, 72 is stored in p , to add 600 to this, we simply add the local products u_i * v_j to the existing value in p{i+j} while preserving the carry.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM