Ya tienes la respuesta inteligente: la aritmética sin firmar es aritmética de módulo y, por lo tanto, los resultados se mantendrán, puedes probarlo matemáticamente ...
Sin embargo, una cosa interesante de las computadoras es que las computadoras son rápidas. De hecho, son tan rápidos que es posible enumerar todas las combinaciones válidas de 32 bits en un período de tiempo razonable (no intente con 64 bits).
Entonces, en su caso, personalmente me gusta lanzarlo a una computadora; me toma menos tiempo convencerme de que el programa es correcto que el que se necesita para convencerme a mí mismo que la prueba matemática es correcta y que no supervisé un detalle en la especificación 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;
}
Esto enumera todos los valores posibles de a
y b
en el espacio de 32 bits y verifica si la igualdad se cumple o no. Si no es así, imprime el caso que no funcionó, que puede usar como verificación de cordura.
Y, según Clang : la igualdad se mantiene .
Además, dado que las reglas aritméticas son independientes del ancho de bits (por encima int
del ancho de bits), esta igualdad se mantendrá para cualquier tipo de entero sin signo de 32 bits o más, incluidos 64 bits y 128 bits.
Nota: ¿Cómo puede un compilador enumerar todos los patrones de 64 bits en un período de tiempo razonable? No puede. Los bucles se optimizaron. De lo contrario, todos hubiéramos muerto antes de que terminara la ejecución.
Inicialmente solo lo probé para enteros sin signo de 16 bits; desafortunadamente, C ++ es un lenguaje loco donde los pequeños enteros (anchos de bits más pequeños queint
) se convierten primero a 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;
}
Una vez mas, según Clang : la igualdad se mantiene .
Bueno, allá vas :)
1 Por supuesto, si un programa desencadena un comportamiento indefinido sin darse cuenta, no resultaría mucho.
Math.random()
Devuelve un entero o un doble en [0,1)? No creo que tu guión (lo mejor que puedo decir) refleja en absoluto el problema que planteaste.