3

En este script de c++ la función rando_btw debería devolver un número aleatorio entre min y max (en este caso entre 0 y 100) pero por algún motivo siempre devuelve 83 ¿Alguien sabría decirme por qué?

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int rando_btw(int min, int max)
{
    return rand() % (max - min) + min;
}

int foo = rando_btw(0,100);

int main()
{
    srand(time (NULL));
    cout << time (NULL);
    cout << foo << endl; 
} 
MahaSaka
  • 185
  • 2
  • 14
  • En relación a lo que la usuaria Paula_Plus_Plus menciona sobre el uso de `std::rand` puedes revisar el siguiente [video](https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful). – Xam Mar 09 '18 at 16:59

2 Answers2

5

Es porque llamas a rando_btw() antes de entrar en main() y por tanto antes de inicializar la semilla. Cambia el lugar donde la llamas, así:

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int rando_btw(int min, int max)
{
    return rand() % (max - min) + min;
}

int foo;
int main()
{
    srand(time (NULL));
    foo = rando_btw(0,100);

    cout << time (NULL);
    cout << foo << endl; 
} 
abulafia
  • 53,696
  • 3
  • 45
  • 80
4

En este script de c++

El lenguaje C++ es compilado, no interpretado. El código de C++ son programas, no scripts.

Siempre devuelve 83 ¿Alguien sabría decirme por qué?

La respuesta de abulafia ha señalado el problema, pero no ha mencionado otros problemas que presenta tu código que podría valer la pena tratar:

Ámbito de variables.

En C++ se aconseja que el ámbito de las variables sea lo más pequeño posible. En tu caso, has declarado el entero foo en el ámbito global pudiendo pertenecer al ámbito de la función main.

Función main.

Has olvidado añadir el retorno a la función main, yo aconsejo ponerlo siempre, consulta este hilo para más información al respecto.

Evita std::endl.

En la mayoría de casos no es necesario usar std::endl, consulta este hilo para más detalles al respecto.

Cláusula using.

En general, se aconseja evitar el using namespace std o si se usa, limitarlo al ámbito más pequeño posible, consulta este hilo para más información al respecto.

Se desaconsjea el uso de std::rand.

El algoritmo de std::rand no forma parte de la especificación de C++ y en consecuencia puede no ser portable con resultados y rendimiento cuestionables. Por ello se está estudiando deprecarlo.

La librería estándar de C++ ofrece utilidades estándar de generación de números pseudo-aleatorios desde 2011.

Estás falseando la distribución.

La distribución numérica de std::rand es homogénea entre 0 y RAND_MAX, esto significa que cualquier número dentro de dicho rango tiene las mismas probabilidades de ser esogido (1 entre RAND_MAX).

Al hacer módulo (%) sobre el resultado de std::rand rompes la homogeneidad si el divisor no es múltiplo de RAND_MAX. Suponiendo un RAND_MAX de 32767 con un módulo sobre 100 obtenemos que los números del 0 al 67 tienen una probabilidad de aparición mayor que los números del 68 al 99.

Propuesta.

Teniendo en cuenta todo lo anterior, tu código podría quedar de la siguiente manera:

#include <iostream>
#include <random>
// No se incluye ninguna cabecera de C

int rando_btw(int min, int max)
{
    // Tenemos control sobre el algoritmo y distribución a usar.
    static std::random_device device;
    static std::mt19937 generador(device());
    std::uniform_int_distribution<> distribucion(min, max);

    /* Generamos un número pseudo-aleatorio con el algoritmo
    mt19937 distribuido uniformemente entre min y max */
    return distribucion(generador);
}

int main()
{
    // La cláusula using sólo afecta a main
    using namespace std;
    // La variable foo sólo existe en main
    int foo = rando_btw(0,100);
    // No usamos endl.
    cout << foo << '\n';

    return 0;
} 
PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82