Hai già la risposta intelligente: l'aritmetica senza segno è modulo aritmetica e quindi i risultati manterranno, puoi dimostrarlo matematicamente ...
Una cosa interessante dei computer, tuttavia, è che i computer sono veloci. In effetti, sono così veloci che è possibile enumerare tutte le combinazioni valide di 32 bit in un ragionevole lasso di tempo (non provare con 64 bit).
Quindi, nel tuo caso, personalmente mi piace semplicemente lanciarlo su un computer; mi ci vuole meno tempo per convincermi che il programma è corretto di quanto ci vuole per convincermi che la dimostrazione matematica sia corretta e che non ho supervisionato un dettaglio nella specifica 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;
}
Questo enumera tutti i possibili valori di a
e b
nello spazio a 32 bit e controlla se l'uguaglianza è valida o meno. In caso contrario, stampa il caso che non ha funzionato, che puoi utilizzare come controllo di integrità.
E, secondo Clang : l' uguaglianza vale .
Inoltre, dato che le regole aritmetiche sono indipendenti dalla larghezza di bit (sopra la int
larghezza di bit), questa uguaglianza sarà valida per qualsiasi tipo di intero senza segno di 32 bit o più, inclusi 64 bit e 128 bit.
Nota: come può un compilatore enumera tutti i modelli a 64 bit in un lasso di tempo ragionevole? Non può. I loop sono stati ottimizzati. Altrimenti saremmo morti tutti prima che l'esecuzione terminasse.
Inizialmente l'ho provato solo per interi senza segno a 16 bit; sfortunatamente C ++ è un linguaggio folle in cui int
vengono prima convertiti piccoli interi (larghezze di bit più piccole di ) 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;
}
E ancora una volta, secondo Clang : l' uguaglianza vale .
Bene, eccoti :)
1 Naturalmente, se un programma inavvertitamente innesca un comportamento indefinito, non si dimostrerebbe molto.
Math.random()
restituire un numero intero o una doppia [0,1)? Non credo che la tua sceneggiatura (la cosa migliore che posso dire) rifletta il problema che hai posto.