快速算法计算大n! mod 2 ^ 32

时间:2013-03-05 17:38:07

标签: algorithm biginteger modulo factorial

我想计算N的确切值! mod 2 ^ 32。 N可以高达2 31

任何语言都可以,但我希望详细解释算法。 时间限制是< 1秒

5 个答案:

答案 0 :(得分:21)

在python中:

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

理由:

我们知道34!可以被2 32 整除,因为在序列中:

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

有:

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

这是每个较大因子的一个因子,因此所有较大的因子都是0 mod 2 32

对于小的N值,如果你没有可用的bignum算法,你可以进行单独的乘法mod 2 32 ,和/或你可以在factorial中预先计算2的幂,这很容易计算(见上文)。

答案 1 :(得分:6)

正常计算阶乘(乘以数字1,2,3,...),在每次乘法后执行模数。这将为您提供N的小值的结果。

对于N的较大值,请执行相同操作。很快,您的中间结果将为0,然后您可以立即停止循环并返回0。您停止的时间点相对较快:对于N == 64,结果将为0,因为1..64的乘积包含32个偶数,因此可被2^32整除。你得到0的N的实际最小值将小于64。

答案 2 :(得分:0)

通常,您可以使用大多数编程语言中可用的整数类型(int,long)来实现模数为2的小功率而无需bignums或模块缩减的算法。对于modulo 2 32 ,您将使用32位int。 "Integer overflow" takes care of the modular arithmetic.

在这种情况下,由于只有34个不同的结果,因此查找表可能比计算阶乘更快,假设经常使用阶乘以使表加载到CPU缓存中。执行时间将以微秒为单位进行测量。

答案 3 :(得分:0)

当乘以2个任意长度的数字时,低位总是精确的,因为它不依赖于高位。 Modulo 2 n 也是一种特殊情况,因为通过AND操作获得模数非常容易。 Modulo 2 32 更加特殊,因为对于32位无符号类型,C中的所有无符号运算都减少了模2 32 ,因此您不需要更宽的类型。

所以你可以乘以数字并忽略溢出,然后在AND之后用2 32 - 1来获得模数,这实际上是在做C中的正常非加宽乘法(即结果与操作数大小相同,而不是宽度的两倍)

unsigned int p = 1;
for (unsigned int i = 1; i <= n; i++)
    p *= i;
return p;

如果您的语言不像C那样减少模数学,那么您需要在for循环中使用

p = (p * i) & 0xffffffff;

答案 4 :(得分:-1)

计算模数是一种非常快速的运算,尤其是2的幂的模。相比之下,乘法是非常昂贵的。 最快的算法会将素数中的因子因子分解(由于数字小于33,因此非常快)。通过将所有这些相乘,将每个乘法之间的模数乘以大数字来获得结果。

例:计算10! mod 2 ** 32: 使用de Polignac的公式,得到10的素因子! 它给你:

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

这会比基本算法更快,因为计算 (29!mod 2 ** 32)X 30 比乘以5,3和2要困难得多,并且每次都取模数。