你已经给出了聪明的答案:无符号算术是模算术,因此结果将保持不变,你可以通过数学证明...
计算机的一个很酷的特点是它们非常快。事实上,它们如此之快,以合理的时间内枚举所有32位的有效组合是可能的(不要尝试64位)。
因此,在你的情况下,我个人喜欢直接将其交给计算机;我花费的时间比说服自己程序是正确的所需的时间少,而证明数学证明是正确的并且我没有在规范中忽略细节则需要更多的时间1:
#include <iostream>
#include <limits>
int main() {
std::uint64_t const MAX = std::uint64_t(1) << 32;
for (std::uint64_t i = 0; i < MAX; ++i) {
for (std::uint64_t j = 0; j < MAX; ++j) {
std::uint32_t const a = static_cast<std::uint32_t>(i);
std::uint32_t const b = static_cast<std::uint32_t>(j);
auto const champion = (a + (b & 255)) & 255;
auto const challenger = (a + b) & 255;
if (champion == challenger) { continue; }
std::cout << "a: " << a << ", b: " << b << ", champion: " << champion << ", challenger: " << challenger << "\n";
return 1;
}
}
std::cout << "Equality holds\n";
return 0;
}
这个程序枚举了32位空间中所有可能的a
和b
的值,并检查是否成立。如果不成立,它会打印出未能成功的情况,你可以用作合理性检查。
而且,根据Clang的说法:等式成立。
此外,鉴于算术规则不受位宽限制(在int
位宽以上),这个等式对于任何32位或更多位的无符号整数类型都成立,包括64位和128位。
注意:一个编译器如何在合理的时间范围内枚举所有的64位模式? 它不能。循环已被优化掉了。否则我们在执行结束之前都会死亡。
我最初只证明了16位无符号整数的情况;不幸的是,C++是一种疯狂的语言,小于int
的小整数会先转换为int
。
#include <iostream>
int main() {
unsigned const MAX = 65536;
for (unsigned i = 0; i < MAX; ++i) {
for (unsigned j = 0; j < MAX; ++j) {
std::uint16_t const a = static_cast<std::uint16_t>(i);
std::uint16_t const b = static_cast<std::uint16_t>(j);
auto const champion = (a + (b & 255)) & 255;
auto const challenger = (a + b) & 255;
if (champion == challenger) { continue; }
std::cout << "a: " << a << ", b: " << b << ", champion: "
<< champion << ", challenger: " << challenger << "\n";
return 1;
}
}
std::cout << "Equality holds\n";
return 0;
}
根据Clang的说法,平等成立。
好了,就是这样 :)
1 当然,如果程序意外触发了未定义行为,这并不能证明什么。
Math.random()
在[0,1)范围内返回整数还是双精度浮点数?我认为你的脚本(就我所知)根本没有反映出你提出的问题。 - Brick&
和+
的行为。 - Barmar