模运算符(%)会产生不一致的结果。

6

鉴于这个例子:

std::vector<int> numbers = {5,6,7}; //size is 3
int i = -1; 
std::cout << i % 3 <<"\n";                  // output: -1
std::cout << i % numbers.size() << "\n";    // output: 0

基本上,在这两个语句中,我都在处理-1 % 3,但编译器输出的数字不同。我不理解这个结果,希望有人能解释一下。
编辑:如@Chris、@Keith Thompson和@AnT所建议的代码段。
std::cout << std::numeric_limits<std::size_t>::max() % 3 <<"\n";     //output: 0
std::cout << i % numbers.size() << "\n";                            // output: 0

打印出期望的输出。感谢每个人提供的有用建议!


请看这里:https://dev59.com/6msz5IYBdhLWcg3w47-m - Rollen
2
@RollenD'Souza:那其实是无关的。 - Deduplicator
2
问题在于,“numbers.size()”恰好是“unsigned int”; 在你不知情的情况下,“-1”被转换为“0xffffffff”(或者对于你的架构的任何值)。 :( - FoggyDay
1
@FoggyDay:不,-1 没有被转换成 1。它被转换成了 SIZE_MAX - Keith Thompson
@Grundkurs: i % numbers.size() 不是 -1 % 3。实际上它是 (std::vector<int>::size_type) i % numbers.size()。而 (std::vector<int>::size_type) i 不再是 -1,而是一些大的无符号值。 - AnT stands with Russia
2个回答

8
i % 3 是你所期望的,并且自 C++11 起,它具有定义良好的语义,而不是具有实现定义的结果(如果我记得正确的话)。numbers.size() 具有无符号类型 (std::size_t)。假设 size_tint 一样大或更大,则在执行操作之前将 i 转换为相同的无符号类型。 i 的值将成为该类型的最大值,看起来可以被 3 整除。

3
顺便提一下,提高编译器的警告级别应该可以发现符号不匹配的问题。 - Deduplicator
@Deduplicator,有趣,我不知道。 显然Clang不支持GCC也不支持,或者至少这些版本不支持。 - chris
尝试使用-Weverything,并查看它从-Wextra中抛出了哪个警告。 - Deduplicator
@Deduplicator,啊,我明白了。现在我在考虑是否值得将特定的警告(-Wsign-conversion)添加到我的选项中。谢谢! - chris

0

问题在于C++中负数的百分比没有明确定义。


除了C++11及以后的版本。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接