Pergunta

Dado o início e o fim de um intervalo inteiro, como calculo um número inteiro aleatório normalmente distribuído entre esse intervalo?

Percebo que a distribuição normal vai para -+ infinito.Eu acho que as caudas podem ser cortadas, então quando um aleatório for computado fora do intervalo, recalcule.Isso eleva a probabilidade de números inteiros no intervalo, mas desde que esse efeito seja tolerável (<5%), tudo bem.

public class Gaussian
{
    private static bool uselast = true;
    private static double next_gaussian = 0.0;
    private static Random random = new Random();

    public static double BoxMuller()
    {
        if (uselast) 
        { 
            uselast = false;
            return next_gaussian;
        }
        else
        {
            double v1, v2, s;
            do
            {
                v1 = 2.0 * random.NextDouble() - 1.0;
                v2 = 2.0 * random.NextDouble() - 1.0;
                s = v1 * v1 + v2 * v2;
            } while (s >= 1.0 || s == 0);

            s = System.Math.Sqrt((-2.0 * System.Math.Log(s)) / s);

            next_gaussian = v2 * s;
            uselast = true;
            return v1 * s;
        }
    }

    public static double BoxMuller(double mean, double standard_deviation)
    {
        return mean + BoxMuller() * standard_deviation;
    }

    public static int Next(int min, int max)
    {
        return (int)BoxMuller(min + (max - min) / 2.0, 1.0); 
    }
}

Provavelmente preciso dimensionar o desvio padrão de alguma forma em relação ao intervalo, mas não entendo como.

Responder:

    // Will approximitely give a random gaussian integer between min and max so that min and max are at
    // 3.5 deviations from the mean (half-way of min and max).
    public static int Next(int min, int max)
    {
        double deviations = 3.5;
        int r;
        while ((r = (int)BoxMuller(min + (max - min) / 2.0, (max - min) / 2.0 / deviations)) > max || r < min)
        {
        }

        return r;
    }
Foi útil?

Solução

Se o método Box-Muller retornar uma distribuição normal “padrão”, terá média 0 e desvio padrão 1.Para transformar uma distribuição normal padrão, você multiplica seu número aleatório por X para obter o desvio padrão X e adiciona Y para obter a média Y, se não me falha a memória.

Veja o Seção do artigo da Wikipedia sobre normalização de variáveis ​​normais padrão (propriedade 1) para uma prova mais formal.


Em resposta ao seu comentário, a regra geral é que 99,7% de uma distribuição normal estará dentro de +/- 3 vezes o desvio padrão.Se você precisar de uma distribuição normal de 0 a 100, por exemplo, sua média será a metade e seu SD será (100/2)/3 = 16,667.Portanto, quaisquer valores que você obtiver do algoritmo Box-Muller, multiplique por 16,667 para "esticar" a distribuição e, em seguida, adicione 50 para "centrá-la".


John, em resposta ao seu comentário mais recente, não tenho certeza de qual é o objetivo do Next função.Ele sempre usa um desvio padrão de 1 e uma média a meio caminho entre o mínimo e o máximo.

Se você quiser uma média de Y, com ~99,7% dos números no intervalo -X a +X, basta ligar BoxMuller(Y, X/3).

Outras dicas

Bem, o -2*Sigma ..+2*Sigma fornecerá 95% da curva da campainha. (Verifique a seção "Intervalos de desvio e confiança padrão" no artigo wiki já mencionado).

Portanto, modifique esta peça:

return (int)BoxMuller(min + (max - min) / 2.0, 1.0);

e altere 1.0 (desvio padrão) para 2,0 (ou ainda mais se você quiser mais de 95% de cobertura)

return (int)BoxMuller(min + (max - min) / 2.0, 2.0);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top