¿Cómo podemos calcular N elegir K módulo un número primo sin desbordamiento?

How can we computer (N choose K)% M in C or C++ without invoking overflow ?

For the particular case when N (4<=N<=1000) y K (1<=K<=N) y M = 1000003.

preguntado el 09 de enero de 11 a las 11:01

5 Respuestas

To compute (n choose k) % M, you can separately compute the nominator (n!) modulus M and the denominator (k!*(n - k)!) modulus M and then multiply the nominator by the denominator's modular multiplicative inverse (in M). Since M is prime, you can use Fermat's Little Theorem to calculate the multiplicative inverse.

There is a nice explanation, with sample code, on the following link (problem SuperSum):


Respondido el 09 de enero de 11 a las 20:01

For some extra speed, compute the numerator as the product from (K+1) to N, and the denominator as K!. We know that there won't be any factors of M in the calculation, because it's prime and larger than N. Hence we can cancel top and bottom without worrying that what we're cancelling could be a multiple of M (i.e. 0). - Steve Jessop

But now I see that 1,000,000,003 is not prime,any idea how to solve this now ? - Quijotesco

@Tretwick Marian: Unless it's banned for some reason, just get out a bignum library (GMP) and do the obvious. 1000!/500! has less than 5k binary digits, which probably isn't too large to do approx 1000 arithmetic operations on. If you need to optimize, your worst case is 1000 choose 500, which only has 1k binary digits. So calculate it intelligently, doing divisions as soon as possible rather than all the multiplications first, and the numbers never get significantly bigger than that. - Steve Jessop

Since 1000000003 = 23 * 307 * 141623 you can calculate (n choses k) mod 23, 307 and 141623 and then apply the chinese reminder theorem[1]. When calculating n!, k! and (n-k)!, you should calculate everythinng mod 23, 307 and 141623 each step to prevent overflow.

In this way you should avoid overflow even in 32bit machines.

A little improvement would be to calculate (n choses k) mod 141623 and 7061 (23 * 307) (edit: but it can be a little tricky to calculate the inverse modulus 7061, so I wouldn't do this)

I'm sorry for my poor English.


Edit2: Another potentially problem I've found is when calculating n! mod 23 (for example) it will probably be 0, but that doesn't implies that (n choses k) is 0 mod 23, so you should count how many times 23 divides n!, (n-k)! and k! before calculating (n choses k). Calculating this is easy, p divides n! exactly floor(n/p) + floor(n/p²) + ... times. If it happens that 23 divides n! the same times it divides k! and (n-k)!, the you proceed to calculate (n choses k) mod 23 dividing by 23 every multipler of it every time.The same applies for 307, but not for 141623

Respondido el 09 de enero de 11 a las 18:01

For the small primes, 23 and 307, you could use en.wikipedia.org/wiki/Lucas%27_theorem instead of counting powers. - Steve Jessop

You could use the recursive formula from the link you gave and do the calculation mod M.

Respondido el 09 de enero de 11 a las 15:01

He aquí un ejemplo sencillo:

(A * B * C) % N ... is equal to... ((A % N) *  (B % N) * (C % N)) % N;

That is, all you need to apply modulus to every operand and product, or as soon as it becomes big a number. And last the modulus must apply to the overall result.

Respondido el 09 de enero de 11 a las 15:01

With 32 bit int it still may cause an overflow on 1000000000*1000. - Yakov Galka

@ ybungalobill : apply ((1000000000%N)*(1000)%N)%N. - Nawaz

note that the modulus is M in the question, not N, and the example given, while not actually prime, is about a billion. So 1000000000%N es todavía 1000000000. To avoid overflow you'd need an integer type as big as N^2 (e.g. long long or int64_t, if available) - Steve Jessop

Utilización de Aproximación de Stirling to calculate the binomial coefficient. Then just calculate the modulus as usual.

Respondido el 09 de enero de 11 a las 15:01

How does an approximation help to calculate the binomial coefficient modulo M? Approximations are pretty much meaningless in modulo arithmetic. - Steve Jessop

Sorry I missed the approximation part. - Quijotesco

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.