对于非常大的非负n和m,n%= m能否返回负值?

时间:2015-01-25 11:45:51

标签: c++ operators largenumber

这个问题与模运算符%有关。我们知道一般a % b返回余数,当a除以b且余数大于或等于零且严格小于b时。但是当a和b的大小为10 ^ 9时,上述情况是否成立?

我似乎得到以下输入代码的负输出:

74 41 28

但是,更改最终输出语句会使工作和结果变得正确!

    #include<iostream>
    using namespace std;

    #define m 1000000007

    int main(){
       int n,k,d;
       cin>>n>>k>>d;
       if(d>n)
         cout<<0<<endl;
       else
       {
           long long *dp1 = new long long[n+1], *dp2 = new long long[n+1];

           //build dp1:
           dp1[0] = 1;
           dp1[1] = 1;

           for(int r=2;r<=n;r++)
           {
              dp1[r] = (2 * dp1[r-1]) % m;
              if(r>=k+1) dp1[r] -= dp1[r-k-1];
              dp1[r] %= m;
           }

           //build dp2:
           for(int r=0;r<d;r++) dp2[r]  = 0;
           dp2[d] = 1;

           for(int r = d+1;r<=n;r++)
           {
             dp2[r] = ((2*dp2[r-1]) - dp2[r-d] + dp1[r-d]) % m;
             if(r>=k+1) dp2[r] -= dp1[r-k-1];
             dp2[r] %= m;
           }

           cout<<dp2[n]<<endl;
        }
   }

将最终输出语句更改为:

        if(dp2[n]<0) cout<<dp2[n]+m<<endl;
        else cout<<dp2[n]<<endl; 

完成工作,但为什么需要它?

顺便说一句,代码实际上是我对this question

的解决方案

3 个答案:

答案 0 :(得分:1)

这是int

范围的限制

int只能保存 -2,147,483,648 2,147,483,647 之间的值。

考虑将long long用于你的m,n,k,d&amp; r变量。如果您的计算永远不会有负值,请尽可能使用unsigned long long

long long可以将 -9,223,372,036,854,775,808 的值保存到 9,223,372,036,854,775,807

虽然unsigned long long可以将值从 0 保存到 18,446,744,073,709,551,615 。 (2 ^ 64)

与无符号类型相比,有符号类型的正值范围大约减半,因为最高有效位用于符号;当您尝试分配大于指定数据类型强加的范围的正值时,将引发最高有效位并将其解释为负值。

答案 1 :(得分:1)

嗯,不,使用正数操作数的模数不会产生负面结果。

然而......

只有C标准才能保证int类型支持-32767到32767范围内的值,这意味着你的宏m不一定要扩展为int类型的文字。它会很长(但保证有足够大的范围)。

如果发生这种情况(例如,具有16位int类型和32位长类型的编译器),模数运算的结果将被计算为long,并且可能具有超过int可以表示的值。将该值转换为int(由于dp1是指向int的指针,因此dp1 [r]%= m等语句将需要)会给出未定义的行为。

答案 2 :(得分:0)

数学上,大数字并没有什么特别之处,但是计算机只有有限的宽度来记下数字,所以当事情变得太大时,你会得到溢出&#34;错误。一个常见的比喻是在汽车仪表板上行驶的里程计数器 - 最终它将显示为全9并且滚动到0。由于处理负数的方式,标准符号整数不会滚动到零,但是到一个非常大的负数。

你需要切换到更大的变量类型,以便它们快速溢出 - &#34; long int&#34;或者&#34; long long int&#34;而不只是&#34; int&#34;,范围与每个额外的宽度加倍。您还可以使用无符号类型进一步加倍,因为没有范围用于否定。