c - positivos - negativo mas negativo da positivo
¿Por qué rand()+rand() produce números negativos? (8)
Observé que la función de biblioteca
rand()
cuando se llama solo una vez dentro de un ciclo, casi siempre produce números positivos.
for (i = 0; i < 100; i++) {
printf("%d/n", rand());
}
Pero cuando agrego dos llamadas
rand()
, los números generados ahora tienen más números negativos.
for (i = 0; i < 100; i++) {
printf("%d = %d/n", rand(), (rand() + rand()));
}
¿Alguien puede explicar por qué estoy viendo números negativos en el segundo caso?
PD: inicializo la semilla antes del ciclo como
srand(time(NULL))
.
La razón por la que estaba agregando era para evitar ''0'' como el número aleatorio en mi código. rand () + rand () fue la solución rápida y sucia que me vino a la mente.
Una solución simple (bueno, llámalo "Hack") que nunca produce un resultado cero y nunca se desbordará:
x=(rand()/2)+1 // using divide -or-
x=(rand()>>1)+1 // using shift which may be faster
// compiler optimization may use shift in both cases
Esto limitará su valor máximo, pero si no le importa, entonces esto debería funcionar bien para usted.
Básicamente
rand()
produce números entre
0
y
RAND_MAX
, y
2 RAND_MAX > INT_MAX
en su caso.
Puede modular con el valor máximo de su tipo de datos para evitar el desbordamiento.
Por supuesto, esto interrumpirá la distribución de los números aleatorios, pero
rand
es solo una forma de obtener números aleatorios rápidos.
#include <stdio.h>
#include <limits.h>
int main(void)
{
int i=0;
for (i=0; i<100; i++)
printf(" %d : %d /n", rand(), ((rand() % (INT_MAX/2))+(rand() % (INT_MAX/2))));
for (i=0; i<100; i++)
printf(" %d : %ld /n", rand(), ((rand() % (LONG_MAX/2))+(rand() % (LONG_MAX/2))));
return 0;
}
El problema es la adición.
rand()
devuelve un valor
int
de
0...RAND_MAX
.
Entonces, si agrega dos de ellos, obtendrá
RAND_MAX * 2
.
Si eso excede
INT_MAX
, el resultado de la suma desborda el rango válido que puede contener un
int
.
El desbordamiento de valores firmados es un comportamiento indefinido y puede hacer que su teclado le hable en lenguas extranjeras.
Como no hay ganancia aquí al agregar dos resultados aleatorios, la idea simple es no hacerlo.
Alternativamente, puede lanzar cada resultado a
unsigned int
antes de la adición si eso puede contener la suma.
O use un tipo más grande.
Tenga en cuenta que
long
no es necesariamente más ancho que
int
, ¡lo mismo se aplica a
long long
si
int
tiene al menos 64 bits!
Conclusión: solo evite la adición.
No proporciona más "aleatoriedad".
Si necesita más bits, puede concatenar los valores
sum = a + b * (RAND_MAX + 1)
, pero eso probablemente también requiera un tipo de datos mayor que
int
.
Como su razón declarada es evitar un resultado cero: eso no se puede evitar agregando los resultados de dos llamadas
rand()
, ya que ambas pueden ser cero.
En cambio, puede simplemente incrementar.
Si
RAND_MAX == INT_MAX
, esto no se puede hacer en
int
.
Sin embargo,
(unsigned int)rand() + 1
será muy, muy probable.
Probable (no definitivamente), porque requiere
UINT_MAX > INT_MAX
, lo cual es cierto en todas las implementaciones que conozco (que cubre algunas arquitecturas integradas, DSP y todas las plataformas de escritorio, móviles y servidores de los últimos 30 años).
Advertencia:
Aunque ya aparece en los comentarios aquí, tenga en cuenta que agregar dos valores aleatorios
no
obtiene una distribución uniforme, sino una distribución triangular como lanzar dos dados: para obtener
12
(dos dados) ambos dados deben mostrar
6
.
para
11
ya hay dos variantes posibles:
6 + 5
o
5 + 6
, etc.
Entonces, la adición también es mala desde este aspecto.
También tenga en cuenta que los resultados que genera
rand()
no son independientes entre sí, ya que los genera un
generador de números pseudoaleatorios
.
Tenga en cuenta también que el estándar no especifica la calidad o la distribución uniforme de los valores calculados.
Esta es una respuesta a una aclaración de la pregunta hecha en comentario a esta respuesta ,
La razón por la que estaba agregando era para evitar ''0'' como el número aleatorio en mi código. rand () + rand () fue la solución rápida y sucia que me vino a la mente.
El problema era evitar 0. Hay (al menos) dos problemas con la solución propuesta.
Una es, como indican las otras respuestas, que
rand()+rand()
puede invocar un comportamiento indefinido.
El mejor consejo es nunca invocar un comportamiento indefinido.
Otro problema es que no hay garantía de que
rand()
no produzca 0 dos veces seguidas.
Lo siguiente rechaza cero, evita un comportamiento indefinido y, en la gran mayoría de los casos, será más rápido que dos llamadas a
rand()
:
int rnum;
for (rnum = rand(); rnum == 0; rnum = rand()) {}
// or do rnum = rand(); while (rnum == 0);
Para evitar 0, intente esto:
int rnumb = rand()%(INT_MAX-1)+1;
limits.h
incluir
limits.h
.
limits.h
Puede ser que intente un enfoque bastante complicado al asegurarse de que el valor devuelto por la suma de 2 rand () nunca exceda el valor de RAND_MAX. Un posible enfoque podría ser sum = rand () / 2 + rand () / 2; Esto garantizaría que para un compilador de 16 bits con un valor RAND_MAX de 32767, incluso si ambos rands devuelven 32767, incluso entonces (32767/2 = 16383) 16383 + 16383 = 32766, por lo tanto, no daría como resultado una suma negativa.
Si bien lo que todos los demás han dicho sobre el probable desbordamiento podría ser la causa de lo negativo, incluso cuando usa enteros sin signo. El verdadero problema es usar la funcionalidad de hora / fecha como semilla. Si realmente te has familiarizado con esta funcionalidad, sabrás exactamente por qué digo esto. Como lo que realmente hace es dar una distancia (tiempo transcurrido) desde una fecha / hora dada. Si bien el uso de la funcionalidad de fecha / hora como la semilla de un rand (), es una práctica muy común, realmente no es la mejor opción. Debes buscar mejores alternativas, ya que hay muchas teorías sobre el tema y no podría entrar en todas ellas. Agrega a esta ecuación la posibilidad de desbordamiento y este enfoque estuvo condenado desde el principio.
Aquellos que publicaron el rand () + 1 están utilizando la solución que la mayoría usa para garantizar que no obtengan un número negativo. Pero, ese enfoque tampoco es la mejor manera.
Lo mejor que puede hacer es tomarse el tiempo extra para escribir y usar el manejo adecuado de excepciones, y solo agregar al número rand () si y / o cuando termina con un resultado cero. Y, para lidiar con los números negativos correctamente. La funcionalidad rand () no es perfecta y, por lo tanto, debe usarse junto con el manejo de excepciones para garantizar que termine con el resultado deseado.
Merece la pena el tiempo y el esfuerzo extra para investigar, estudiar e implementar adecuadamente la funcionalidad rand (). Solo mis dos centavos. Buena suerte en tus esfuerzos ...
rand()
se define para devolver un número entero entre
0
y
RAND_MAX
.
rand() + rand()
podría desbordarse. Lo que observa es probablemente el resultado de un comportamiento indefinido causado por un desbordamiento de enteros.