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 al 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é veo números negativos en el segundo caso?
PD: inicializo la semilla antes del bucle como srand(time(NULL)) .
rand() está definido 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.
El problema es la adición. rand() devuelve un valor int de 0...RAND_MAX . Entonces, si agrega dos de ellos, obtendrá hasta 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 simplemente no hacerlo. Alternativamente, puede convertir cada resultado en un unsigned int antes de la suma si eso puede contener la suma. O utilice 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 evita 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 más grande 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 su lugar, puede simplemente incrementar. Si RAND_MAX == INT_MAX , esto no se puede hacer en int . Sin embargo, (unsigned int)rand() + 1 funcionará muy, muy probablemente. Probablemente (no definitivamente), porque requiere UINT_MAX > INT_MAX , lo cual es cierto en todas las implementaciones que conozco (que cubre bastantes arquitecturas integradas, DSP y todas las plataformas de escritorio, móviles y servidores de los últimos 30 años).
Advertencia:
Aunque ya se mencionó 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 el 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 son generados por un generador de números pseudoaleatorios . Tenga en cuenta también que la norma 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 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 el 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);