0

For n queries I am given a number x and I have to print its factorial under modulo 1000000007.

def fact_eff(n, d):

    if n in d:
        return d[n]
    else:
        ans=n*fact_eff(n-1,d)
        d[n]=ans
        return ans

d={0:1}
n=int(input())
while(n!=0):
    x=int(input())
    print(fact_eff(x, d)%1000000007)
    n=n-1

The problem is that x can be as large as 100000 and I receive runtime error for values greater than 3000 as maximum recursion depth exceeds. Am I missing something with the modulus operator?

1 Answers1

1

Why would you use recursion in the first place to compute a simple factorial? You can check the dictionary in a loop. Or better, start at the highest valid memoized position and go higher from there, creating new entries as you go.

To save space, maybe only record n! every 32 iterations or something, so future calls need at most 31 multiplies. Still O(1) but trading some computation for huge space savings.

Also, does it work to apply the modulus before you get the final huge product? Like every few multiply steps to keep the numbers small? Or every single step if that keeps the numbers small enough for CPython's single-limb fast path. I think (x * y) % n = ((x%n) * y) % n. (But I didn't double-check that.)

If so, you could combine early modulo with sparse memoization to memoize the final modulo-reduced result.

(For numbers above 2^30, Python BigInteger multiply cost should scale with number of 2^30 chunks required to represent the number. Fortunately one of the multiplicands is always small, being the counter. Keeping the product small buys speed, but division is expensive so it's a tradeoff. And doing any more operations costs Python interpreter overhead which may simply dominate anyway until numbers get really huge.)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847