4

I want to calculate the exact value of N! mod 232. N can be up to 231

Any language is fine but I would appreciate detailed explanation of algorithm. Time limit is < 1 sec

phuclv
  • 37,963
  • 15
  • 156
  • 475
user2129227
  • 97
  • 1
  • 4
  • Is there a practical application to this problem? The number (2^31)! is kind of ridiculously huge. Take a look at http://stackoverflow.com/questions/1384160/calculating-factorial-of-large-numbers-in-c for more discussion of this. – Nick Mitchinson Mar 05 '13 at 17:41
  • It's impossible for a (standard desktop) computer to even write down a number that large in less than a second. – Andrew Mar 05 '13 at 17:59
  • 2
    @Andrew: It's about 4 billion, it's really not *that* huge.. – BlueRaja - Danny Pflughoeft Mar 05 '13 at 20:13
  • @BlueRaja-DannyPflughoeft I'm talking about (2^32)! and not 2^32. The former containing over a billion digits. – Andrew Mar 05 '13 at 20:32
  • 3
    @Andrew: When calculating `n! mod p` under normal circumstances *(ie. when `p` is prime)*, you always mod after each multiplication; then the numbers you deal with are never larger than `p`. See my comment [here](http://stackoverflow.com/a/9728079/238419) for more info. – BlueRaja - Danny Pflughoeft Mar 05 '13 at 20:36

5 Answers5

22

In python:

if n > 33:
  return 0
else
  return reduce(lambda x, y: x*y, range(1, n+1)) % 2**32

Justification:

We know that 34! is divisible by 232 because in the sequence:

1 * 2 * 3 * 4 * ... * 34

there are:

17 multiples of 2
 8 multiples of 4
 4 multiples of 8
 2 multiples of 16
 1 multiple  of 32
--
32 multiplications by 2

It's a factor of every larger factorial, so all the larger ones are 0 mod 232

For small values of N, if you don't have bignum arithmetic available, you can do the individual multiplications mod 232, and/or you can prefactor the power of 2 in the factorial, which is easy to compute (see above).

rici
  • 234,347
  • 28
  • 237
  • 341
  • the modulo 2**32 part is only needed because Python supports bigint math. In most normal languages you just need to do a direct multiplication on a 32-bit type and the result is already modulo 2³² automatically – phuclv Dec 21 '19 at 10:14
6

Calculate the factorial normally (multiply the numbers 1,2,3,...), performing the modulo after each multiplication. This will give you the result for small values of N.

For larger values of N, do the same. Pretty soon, your intermediate result will be 0, and then you can stop the loop immediately and return 0. The point at which you stop will be relatively fast: For N == 64 the result will already be 0 because the product of 1..64 contains 32 even numbers and is therefore divisible by 2^32. The actual minimal value of N where you get 0 will be less than 64.

interjay
  • 107,303
  • 21
  • 270
  • 254
  • *The actual minimal value of N where you get 0 will be < 64* 34, as [rici](https://stackoverflow.com/a/15230586/3789665) and [Joni](https://stackoverflow.com/a/15233896/3789665) stated on the same day, if later. – greybeard Jun 19 '23 at 08:25
1

In general, you can implement algorithms modulo small powers of two without bignums or modular reduction using the integer types (int, long) available in most programming languages. For modulo 232 you would use a 32-bit int. "Integer overflow" takes care of the modular arithmetic.

In this case, since there are only 34 distinct results, a lookup table may be faster than computing the factorial, assuming the factorials are used often enough that the table gets loaded into the CPU cache. The execution time will be measured in microseconds.

Joni
  • 108,737
  • 14
  • 143
  • 193
0

When multiplying 2 numbers of arbitrary length, the lower bits are always exact because it doesn't depend on high order bits. That's how 2-adic or p-adic multiplication works. Basically a×b mod m = [(a mod m)×(b mod m)] mod m so to do N! mod m just do

1×2×...×N mod m = (...(((1×2 mod m)×3 mod m)×4 mod m)...)×N mod m

Modulo 2n is a special case because getting the modulus is rather easy with an AND operation. Modulo 232 is even more special because all unsigned operations in C and most C-like languages are reduced modulo 232 for a 32-bit unsigned type

As a result you can just multiply the numbers in a twice-as-wide type then after that AND with 232 - 1 to get the modulus

uint32_t p = 1;
for (uint64_t i = 1; i <= n && p /* early exit because product = 0 */; i++)
    p = uint32_t(p*i); // or p = p*i & 0xFFFFFFFFU;
return p;
phuclv
  • 37,963
  • 15
  • 156
  • 475
-1

Calculating a modulo is a very fast operation, especially the modulo of a power of 2. A multiplication is very costly in comparison.

The fastest algorithm would factorize the factors of the factorial in prime numbers (which is very fast since the numbers are smaller than 33). And get the result by multiplying all of them together, by taking the modulo in between each multiplication, and starting with the big numbers.

E.g.: to calculate 10! mod 232: use de Polignac's formula, to get the prime factors of 10! which gives you :

10! = 7 * 5 * 5 * 3 * 3 * 3 * 3 * 2 ...

this would be faster than the basic algorithm, because calculating (29! mod 232) X 30 is much harder than multiplying by 5, 3 and 2, and taking the modulo in between each time.

phuclv
  • 37,963
  • 15
  • 156
  • 475
bruce_ricard
  • 743
  • 1
  • 7
  • 15
  • This would actually be a lot slower. First there is a lot of extra work in doing the factorizing, and then a lot more multiplications. I don't know why you think that multiplying by 5, 3, and 2, performing a modulo each time, is faster than multiplying by 30. – interjay Mar 05 '13 at 21:01
  • Again, the numbers to factorize are very small, so easy so factorize. But the number to multiply are big, so hard. It's clear that if you can reduce the size of the intermediate result, you're gonna be faster. Try to calculate 67 * 4 mod 100. The best way is : 67 * 2 = 134, 34 * 2 = 68. By doing that I avoided multiplying 134 by 2. – bruce_ricard Mar 05 '13 at 22:18
  • A multiplication is not "an operation", as complexity theory tries to teach it. Yes this algorithm is doing more multiplications than the first one, but the complexity of each multiplication is much smaller. – bruce_ricard Mar 05 '13 at 22:24
  • @double_squeeze: actually you can leave out the factors of 2 altogether, as I mentioned in my answer. However, for `n < 34`, it's hardly worth it: I can compute the entire range in 32 milliseconds (including python startup) on my not-particularly fancy laptop. – rici Mar 05 '13 at 22:31
  • Yes I agree, for this particular small example it is not really worth it. But let's say you don't have a computer available, and you need to do it by hand, you definitely want to do that. – bruce_ricard Mar 05 '13 at 22:42
  • 1
    @double_squeeze: if you were doing it by hand, you'd want to use http://en.wikipedia.org/wiki/De_Polignac%27s_formula rather than trying to factor all those numbers one at a time, which would be seriously inefficient no matter how small they are. – rici Mar 05 '13 at 22:45