C ++中带负数的模数[重复]
Posted
技术标签:
【中文标题】C ++中带负数的模数[重复]【英文标题】:Modulus with negative numbers in C++ [duplicate] 【发布时间】:2012-08-29 21:24:10 【问题描述】:我一直在为以下递归关系编写程序:
An = 5An-1 - 2An-2 - An-3 + An-4
输出应该是答案模数 10^9 + 7.. 我为此编写了一种蛮力方法,如下所示...
long long int t1=5, t2=9, t3=11, t4=13, sum;
while(i--)
sum=((5*t4) - 2*t3 - t2 +t1)%MOD;
t1=t2;
t2=t3;
t3=t4;
t4=sum;
printf("%lld\n", sum);
MOD= 10^9 +7
每件事似乎都是真的..但我对某些值得到否定的答案..由于这个问题,我无法找到正确的解决方案......
请帮助有关保留Modulus
的正确位置
【问题讨论】:
你不应该用unsigned long long
代替sum
吗?
@Alex1985 如果%
运算符总是返回一个正值,这不会有任何区别,但由于它有时会给出一个负值,所以应该使用带符号的变量。
@Hurkyl-你是对的。评论已删除。
Does either ANSI C or ISO C specify what -5 % 10 should be?, Modulo operation with negative numbers, Why is the behavior of the modulo operator (%) different between C and Ruby for negative integers?
【参考方案1】:
只需将%
替换为处理负值的函数即可:
long long int mod(long long int a, long long int b)
long long int ret = a % b;
if (ret < 0)
ret += b;
return ret;
编辑:将数据类型更改为long long int
。
【讨论】:
【参考方案2】:问题是 % 运算符不是“模运算符”,而是具有以下相等性的“除余”运算符
(a/b)*b + a%b == a (for b!=0)
因此,如果您的整数除法向零舍入(我认为这是自 C99 和 C++11 以来强制要求的),-5/4 将是 -1,我们有
(-5/4)*4 + -5%4 == -5
-1 *4 -1 == -5
为了得到正的结果(对于模运算),您需要添加除数以防余数为负或执行以下操作:
long mod(long a, long b)
return (a%b+b)%b;
【讨论】:
【参考方案3】:正如其他人所说,%
只是一个余数运算符,而不是mod
。但是,mod/remainder 操作通过这样的递归关系正确分布,所以如果你只是将最终解决方案调整为正数,就像这样,
if (sum < 0) sum = sum + MOD;
那么你应该得到正确的答案。这样做的好处是每次循环迭代都少了一个函数调用和/或分支。 (取决于你的编译器有多聪明,这可能会或可能不会重要)。
【讨论】:
请注意,如果您使用模矩阵求幂而不是直接使用递归关系(即O(N)
),则可以在O(log(N))
时间内解决此问题。【参考方案4】:
当 abs(a) > b 时,所有在公式中一次性添加的答案都是错误的。使用这个或类似的:
int modulo (int a, int b) return a >= 0 ? a % b : ( b - abs ( a%b ) ) % b;
【讨论】:
【参考方案5】:在@sellibitze 和@liquidblueocean 的答案中第二次使用%
可能不会像%
通常那样慢,因为它归结为b
的减法之一或没有。其实,让我检查一下...
int main(int argc, char **argv)
int a = argc; //Various tricks to prevent the
int b = 7; //compiler from optimising things out.
int c[10]; //Using g++ 4.8.1
for (int i = 0; i < 1000111000; ++i)
c[a % b] = 3;
//c[a < b ? a : a-b] = 3;
return a;
或者用%
或其他行注释该行,我们得到:
%
:14 秒
?
:7 秒
所以%
没有我想象的那么优化。可能是因为优化会增加开销。
因此,出于性能原因,最好不要使用两次%
。
相反,正如this answer 建议和解释的那样,这样做:
int mod(int k, int n)
return ((k %= n) < 0) ? k+n : k;
需要a bit more work if you want it to work properly for negative n
too,但这几乎没有必要。
【讨论】:
以上是关于C ++中带负数的模数[重复]的主要内容,如果未能解决你的问题,请参考以下文章
jQuery Inputmask - 输入元素中带有掩码的十进制负数或正数