あなたはすでに賢い答えを持っています:符号なし算術はモジュロ算術であり、したがって結果が保持され、数学的にそれを証明することができます...
ただし、コンピュータの優れた点の1つは、コンピュータが高速であることです。実際、それらは非常に高速であり、妥当な時間内に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;
}
これを列挙の全ての可能な値を通るa
とb
平等が成立する、またはしないかどうかを32ビットの空間をチェックします。そうでない場合は、機能しなかったケースを出力します。これは、サニティチェックとして使用できます。
そして、クランによると:平等を保持しています。
さらに、算術規則がビット幅にとらわれない(int
ビット幅を超える)場合、この等式は、64ビットと128ビットを含む32ビット以上の符号なし整数型にも適用されます。
注:コンパイラーは、すべての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)を返しますか?あなたの脚本(私が知ることができる最良のもの)は、あなたが提起した問題をまったく反映していないと思います。