我们如何计算N,选择K模作为素数而不产生溢出? 我们如何在没有调用溢出的情况下,在C或C++中计算%M?p>

我们如何计算N,选择K模作为素数而不产生溢出? 我们如何在没有调用溢出的情况下,在C或C++中计算%M?p>,c++,c,algorithm,math,modulo,C++,C,Algorithm,Math,Modulo,对于N(4的特殊情况,您可以使用您给出的链接中的递归公式,并执行计算模式M。用于计算二项式系数。然后只需像往常一样计算模量。以下是一个简单的示例: (A * B * C) % N ... is equal to... ((A % N) * (B % N) * (C % N)) % N; 也就是说,您只需要对每个操作数和乘积应用模,或者在它变大时立即应用模。最后,模必须应用于整个结果。要计算(n选择k)%M,您可以分别计算命名子(n!)模M和分母(k!*(n-k)!)模M,然后用分母的模乘法逆

对于N(4的特殊情况,您可以使用您给出的链接中的递归公式,并执行计算模式M。

用于计算二项式系数。然后只需像往常一样计算模量。

以下是一个简单的示例:

(A * B * C) % N ... is equal to... ((A % N) *  (B % N) * (C % N)) % N;
也就是说,您只需要对每个操作数和乘积应用模,或者在它变大时立即应用模。最后,模必须应用于整个结果。

要计算(n选择k)%M,您可以分别计算命名子(n!)模M和分母(k!*(n-k)!)模M,然后用分母的模乘法逆(M)乘以命名子。因为M是素数,你可以用费马的小定理来计算乘法逆

下面的链接(problem SuperSum)上有一个很好的解释,带有示例代码:


由于1000000003=23*307*141623,您可以计算(n选择k)mod 23、307和141623,然后应用中国提醒定理[1]。在计算n!、k!和(n-k)!时,您应该每一步计算所有mod 23、307和141623,以防止溢出

这样,即使在32位机器中也应该避免溢出

一点改进是计算(n选择k)mod 141623和7061(23*307)(编辑:但计算逆模7061可能有点棘手,所以我不会这么做)

我很抱歉我的英语不好

[1]http://en.wikipedia.org/wiki/Chinese_remainder_theorem


Edit2:我发现的另一个潜在问题是,当计算n!mod 23(例如)时,它可能是0,但这并不意味着(n choses k)是0 mod 23,所以在计算(n choses k)之前,你应该计算23除以n!,(n-k)!和k!的次数。计算很简单,p正好除以n!地板(n/p)+地板(n/p²)+…次。如果23除以n!等于它除以k!和(n-k)!,则继续计算(n选择k)mod 23除以它的每一个乘法器。这同样适用于307,但不适用于带32位int的141623

,它仍然可能导致100000000*1000上的溢出。@ybungalobill:apply
((100000000%n)*(1000)%N) %N
。请注意,问题中的模是M,而不是N,并且给出的示例虽然不是素数,但大约是10亿。因此
100000000%N
仍然是
100000000
。为了避免溢出,您需要一个大到N^2的整数类型(例如
long
int64_t
,如果可用)近似值如何帮助计算二项式系数模M?近似值在模运算中几乎没有意义。很抱歉,我错过了近似值部分。为了加快速度,请将分子计算为(K+1)的乘积到N,分母为K!。我们知道计算中不会有M的任何因子,因为它是素数且大于N。因此,我们可以取消顶部和底部,而不用担心我们取消的可能是M的倍数(即0).但现在我看到100000003不是prime,你知道现在该怎么解决吗?@Tretwick Marian:除非出于某种原因被禁止,否则就拿出一个bignum库(GMP)然后做显而易见的事情。1000!/500!的二进制数字少于5k,这可能不会太大,无法对其进行大约1000次算术运算。如果需要优化,最坏的情况是1000选择500,它只有1k个二进制数字。因此,智能地计算它,尽快进行除法,而不是首先进行所有乘法运算,然后e数永远不会比这个大很多。对于小素数,23和307,你可以用它来代替计算幂。看起来