Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the "divide and conquer" method of computing factorials so fast for large ints? [closed]

I recently decided to look at factorial algorithms for large integers, and this "divide and conquer" algorithm is faster than a simple iterative approach and the prime-factoring approach:

def multiply_range(n, m):
    print n, m
    if n == m:
        return n
    if m < n:
        return 1
    else:
        return multiply_range(n, (n+m)/2) * multiply_range((n+m)/2+1, m)

def factorial(n):
    return multiply_range(1, n)

I understand why the algorithm works, it just breaks the multiplication into smaller parts recursively. What I don't understand is why this method is faster.

like image 462
Broseph Avatar asked Dec 01 '12 07:12

Broseph


People also ask

What are the advantages and disadvantages of divide and conquer?

Disadvantages of Divide and Conquer Since most of its algorithms are designed by incorporating recursion, so it necessitates high memory management. An explicit stack may overuse the space. It may even crash the system if the recursion is performed rigorously greater than the stack present in the CPU.

What is the time complexity of divide and conquer?

The Divide and Conquer algorithm solves the problem in O(nLogn) time. Strassen's Algorithm is an efficient algorithm to multiply two matrices. A simple method to multiply two matrices need 3 nested loops and is O(n^3) . Strassen's algorithm multiplies two matrices in O(n^2.8974) time.

What is the basic principle of divide and conquer?

The divide-and-conquer paradigm is often used to find an optimal solution of a problem. Its basic idea is to decompose a given problem into two or more similar, but simpler, subproblems, to solve them in turn, and to compose their solutions to solve the given problem.

What is the divide and conquer approach to problem solving?

The divide and conquer approach divides a problem into smaller subproblems; these subproblems are further solved recursively. The result of each subproblem is not stored for future reference, whereas, in a dynamic approach, the result of each subproblem is stored for future reference.


1 Answers

Contrary to @NPE's answer, your method is faster, only for very large numbers. For me, I began to see the divide and conquer method become faster for inputs ~10^4. At 10^6 and above there is no comparison a traditional loop fails miserably.

I'm no expert on hardware multipliers and I hope someone can expand on this, but my understanding is that multiplication is done digit for digit same way we are taught in grade school.

A traditional factorial loop will start with small numbers and the result keeps growing. In the end you are muliplying a ginormous number with a comparatively small number, an expensive calculation due to the mismatch in digits.

ex. compare

reduce(operator.mul, range(1,10**5))
reduce(operator.mul, range(10**5,1,-1))

the second is slower because the result grows fast, leading to more expensive calculations sooner.

Your method is faster than either of these by orders of magnitude for large numbers because it divides the factorial into similarly sized parts. The sub-results have similar numbers of digits and multiply faster.

like image 70
kalhartt Avatar answered Nov 14 '22 23:11

kalhartt