Masz już sprytną odpowiedź: arytmetyka bez znaku to arytmetyka modulo i dlatego wyniki będą się utrzymywać, możesz to udowodnić matematycznie ...
Jednak jedną fajną rzeczą dotyczącą komputerów jest to, że są szybkie. Rzeczywiście, są tak szybkie, że wyliczenie wszystkich poprawnych kombinacji 32 bitów jest możliwe w rozsądnym czasie (nie próbuj z 64 bitami).
Tak więc w twoim przypadku osobiście lubię po prostu rzucić to w komputer; mniej czasu zajmuje mi przekonanie samego siebie, że program jest poprawny, niż przekonanie samego siebie, niż dowód matematyczny jest poprawny i że nie przeoczyłem szczegółów w specyfikacji 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;
}
To wylicza wszystkie możliwe wartości a
i b
w przestrzeni 32-bitów i sprawdza, czy równość, czy nie. Jeśli tak się nie stanie, drukuje przypadek, który nie zadziałał, co można wykorzystać jako kontrolę poczytalności.
I, zgodnie z Clang : równość .
Ponadto, biorąc pod uwagę, że reguły arytmetyczne są niezależne od szerokości bitów (powyżej int
niezależne od szerokości bitów szerokości bitowej), ta równość będzie obowiązywać dla dowolnego typu liczby całkowitej bez znaku o 32 bitach lub więcej, w tym 64 bitach i 128 bitach.
Uwaga: w jaki sposób kompilator może wyliczyć wszystkie wzorce 64-bitowe w rozsądnych ramach czasowych? Nie może. Pętle zostały zoptymalizowane. W przeciwnym razie wszyscy zginęlibyśmy przed zakończeniem egzekucji.
Początkowo udowodniłem to tylko dla 16-bitowych liczb całkowitych bez znaku; niestety C ++ to szalony język, w którym małe liczby całkowite (mniejsze niż int
) są najpierw konwertowane naint
.
#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;
}
I jeszcze raz, według Clanga : Równość obowiązuje .
Cóż, proszę bardzo :)
1 Oczywiście, gdyby program kiedykolwiek przypadkowo wyzwolił niezdefiniowane zachowanie, niewiele by to udowodniło.
Math.random()
zwraca liczbę całkowitą lub podwójną na [0,1)? Nie sądzę, aby Twój scenariusz (najlepiej, co mogę powiedzieć) odzwierciedlał problem, który w ogóle postawiłeś.