我想计算N的确切值! mod 2 ^ 32。 N可以高达2 31
任何语言都可以,但我希望详细解释算法。 时间限制是< 1秒
答案 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要困难得多,并且每次都取模数。