Estoy intentando generar variables aleatorias intentando generar dos variables normales estándar r1, r2, utilizando coordenadas polares junto con un valor medio y sigma. Sin embargo, cuando ejecuto mi código, sigo obteniendo un "-nan (ind)" como salida.

¿Qué estoy haciendo mal aquí? El código es el siguiente:

static double saveNormal;
static int NumNormals = 0;
static double PI = 3.1415927;

double fRand(double fMin, double fMax)
{
    double f = (double)rand() / RAND_MAX;
    return fMin + f * (fMax - fMin);
}

static double normal(double r, double mean, double sigma) {
    double returnNormal;
    if (NumNormals == 0) {
        //to get next double value
        double r1 = fRand(0, 20);
        double r2 = fRand(0, 20);
        returnNormal = sqrt(-2 * log(r1)) * cos(2 * PI*r2);
        saveNormal = sqrt(-2 * log(r1)) * sin(2 * PI*r2);
    }
    else {
        NumNormals = 0;
        returnNormal = saveNormal;
    }
    return returnNormal*sigma + mean;
}
4
random_x_y_z 15 nov. 2017 a las 11:40

2 respuestas

La mejor respuesta

Por lo tanto, está utilizando el método Box – Muller para muestrear pseudoaleatoriamente una variante aleatoria normal. Para que esta transformación funcione, r1 y r2 deben ser variantes independientes distribuidas uniformemente en [0,1].

En cambio, sus r1/r2 son [0,20] compatibles, lo que da como resultado un argumento sqrt negativo cuando> 1, esto le dará nans. Reemplazar con

double r1 = fRand(0, 1);
double r2 = fRand(0, 1);

Además, debería usar C ++ 11 <random> para una mejor generación de números pseudoaleatorios; a partir de ahora, su fRand tiene mala calidad debido a la conversión de rand() - a - double y posibles correlaciones falsas entre llamadas adyacentes. Además, su función carece de una verificación básica de errores y depende en gran medida de variables globales y es intrínsecamente insegura para los subprocesos.

Para su información, así es como se vería una versión de C ++ 11

#include <random>
#include <iostream>

int main()
{
  auto engine = std::default_random_engine{ std::random_device{}() };
  auto variate = std::normal_distribution<>{ /*mean*/0., /*stddev*/ 1. };

  while(true) // a lot of normal samples ...
    std::cout << variate(engine) << std::endl;
}
3
Arne Vogel 15 nov. 2017 a las 11:31

R1 puede ser cero, por lo que log(r1) no está definido.


Además, no uses rand() excepto cuando necesites que tus números parezcan aleatorios para un humano apurado. Utilice <random> en su lugar

1
peterchen 20 nov. 2017 a las 15:34