![](/img/trans.png)
[英]program received signal SIGFPE, Arithmetic exception when using modulo in C
[英]modulo arithmetic steps for this program
我已經用C
編寫了這段代碼,其中a,b,cc,ma,mb,mcc,N,k
都是int
。 但是根據問題的具體說明, N
和k
可能高達10^9
。 10^9
可以存儲在我的機器的int
變量中。 但是a,b,cc,ma,mb,mcc
對於較大的N
和k
值, a,b,cc,ma,mb,mcc
內部和最終值將大得多,即使在unsigned long long int
變量中也無法存儲。
現在,我要打印代碼中mcc % 1000000007
值。 我知道, for
循環主體操作中的一些巧妙的模運算技巧可以創建正確的輸出而不會發生任何溢出,並且還可以使程序節省時間。 作為模數運算的新手,我無法解決這個問題。 有人可以指出這些步驟嗎?
ma=1;mb=0;mcc=0;
for(i=1; i<=N; ++i){
a=ma;b=mb;cc=mcc;
ma = k*a + 1;
mb = k*b + k*(k-1)*a*a;
mcc = k*cc + k*(k-1)*a*(3*b+(k-2)*a*a);
}
printf("%d\n",mcc%1000000007);
我的嘗試:
我使用a,b,cc,ma,mb,mcc
long long
並且做到了這一點。 可以進一步優化嗎?
ma=1;mb=0;cc=0;
ok = k*(k-1);
for(i=1; i<=N; ++i){
a=ma;b=mb;
as = (a*a)%MOD;
ma = (k*a + 1)%MOD;
temp1 = (k*b)%MOD;
temp2 = (as*ok)%MOD;
mb = (temp1+temp2)%MOD;
temp1 = (k*cc)%MOD;
temp2 = (as*(k-2))%MOD;
temp3 = (3*b)%MOD;
temp2 = (temp2+temp3)%MOD;
temp2 = (temp2*a)%MOD;
temp2 = (ok*temp2)%MOD;
cc = (temp1 + temp2)%MOD;
}
printf("%lld\n",cc);
讓我們看一個小例子:
mb = (k*b + k*(k-1)*a*a)%MOD;
在此,考慮到k*b
, k*(k-1)*a*a
可能溢出,所以總和也可能溢出
(x + y) mod m = (x mod m + y mod m) mod m
我們可以重寫它( x= k*b
, y=k*(k-1)*a*a
和m=MOD
)
mb = ((k*b) % MOD + (k*(k-1)*a*a) %MOD) % MOD
現在,我們可以再走一步。 以來
x * y mod m = (x mod m * y mod m) mod m
我們還可以將x=k*(k-1)
和y=a*a
的乘法k*(k-1)*a*a % MOD
重寫為
((k*(k-1)) %MOD) * ((a*a) %MOD)) % MOD
我確定您可以做剩下的事。 盡管您可以在所有位置灑% MOD
,但應考慮John的提示 ,仔細考慮是否需要它:
將兩個n位數字相加會產生最多n + 1位數字,將n位數字與m位數字相乘會得到最多n + m位的結果。
因此,在某些地方您將需要使用模數屬性,在某些地方您肯定不需要它,但這是您的工作;)。
按照以下步驟構建模板類是一個很好的練習:
template <int N>
class modulo_int_t
{
public:
modulo_int_t(int value) : value_(value % N) {}
modulo_int_t<N> operator+(const modulo_int_t<N> &rhs)
{
return modulo_int_t<N>(value_ + rhs.value) ;
}
// fill in the other operations
private:
int value_ ;
} ;
然后使用modulo_int_t <1000000007>對象而不是int編寫操作。 免責聲明:在適當的地方使用long long並注意消除負面差異...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.