n %= m 是否可以为非常大的非负 n 和 m 返回负值

Can n %= m ever return negative value for very large nonnegative n and m?

本文关键字:返回 是否 非常      更新时间:2023-10-16

这个问题是关于模运算符%的。我们知道,一般来说,当 a 除以 b 并且余数大于或等于零且严格小于 b 时,a % 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; 

确实有效,但为什么需要它?

顺便说一句,代码实际上是我对这个问题的解决方案

这是

int范围施加的限制。

int只能保存介于 –2,147,483,6482,147,483,647 之间的值。

考虑对 m、n、k、d 和 r 变量使用 long long。如果可能,请使用unsigned long long如果您的计算不应具有负值。

long long可以保存 –9,223,372,036,854,775,8089,223,372,036,854,775,807 之间的值

unsigned long long可以保存 018,446,744,073,709,551,615 之间的值。(2^64)

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

嗯,不,具有正操作数的模不会产生负结果。

然而。。。。。

只有 C 标准保证 int 类型支持介于 -32767 到 32767 范围内的值,这意味着宏 m 不一定扩展到 int 类型的文本。 它将适合很长的时间(保证具有足够大的范围)。

如果发生这种情况(例如,具有 16 位 int 类型和 32 位长类型的编译器),取模运算的结果将被计算为尽可能长,并且可能具有超出 int 可以表示的值。 将该值转换为 int(就像 dp1[r] %= m 这样的语句一样,因为 dp1 是指向 int 的指针)会产生未定义的行为。

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

您需要切换到更大的变量类型,以便它们溢出的速度不那么快 - "long int"或"long long int"而不仅仅是"int",范围随着宽度每增加一点而加倍。您还可以使用无符号类型进一步加倍,因为负数没有使用范围。