Gere 1 e 2 com 55% e 45% de probabilidade - Java

E ai galera , blz?

sou novato em java, estou tentando aumentar a probabilidade de aparecer mais vezes o número ‘1’ …gostaria de saber como eu faço isso ?

estou usando Random, para gerar os números entre 1 e 2.

muito obrigado desde já…

  • Segue o código abaixo:

int probabilidade, cont1=0, cont2=0;
double[] vetor = new double[2];
double soma = 0, N1=0, N2=0;

	for (int i = 0; i < 10; i++) {

		probabilidade = (int) (1+ Math.random() * 2);
		
		System.out.println((i+1) + "°= " + probabilidade);

		if (probabilidade == 1) {
			cont1++;
			vetor[0] = cont1;
			N1 = vetor[0];
		} else if (probabilidade == 2) {
			cont2++;
			vetor[1] = cont2;
			N2 = vetor[1];
		}
		soma = vetor[0] + vetor[1];

	}
			
	System.out.println("Probabilidade: 1 = "+ (N1/soma)*100 +" % \nProbabilidade: 2 = "+ (N2/soma)*100+" %");

Acho que a partir do momento que você quer uma porcentagem de resultados, deixa de ser aleatório, pois você estará manipulando o resultado.
Neste caso: 55% a 45%, a cada 10 sorteios você precisaria de 5,5% de resultado 1 e 4,5% de resultado 2, mas como 5,5 e 4,5 não são números inteiros fica difícil.
Então acho que deva manter para cada 20 sorteios 11 resultados 1 e 9 resultados 2.
Construa um código que mantenha isso.
Essa é apenas uma ideia. Não sei também se entendi realmente o que você esta querendo.

Resolvi quebrar um pouco a cabeça e como escrevi no post anterior, com 10 sorteios fica impossível ter 55 e 45 por cento, mas com 20 sorteios a coisa funciona. Execute o código abaixo e verá:

int probabilidade, cont1=0, cont2=0;
double soma = 0, N1=0, N2=0;

for (int i = 0; i < 20; i++) {

	probabilidade = (int) (1+ Math.random() * 2);

	System.out.println((i+1) + "°= " + probabilidade);

	if(cont1 > ((i/2)+1)) probabilidade = 2;
	if(cont2 > ((i/2)-1)) probabilidade = 1;
	if (probabilidade == 1) {
		cont1++;
	} else if (probabilidade == 2) {
		cont2++;
	}
	soma = cont1 + cont2;

}

System.out.println("Probabilidade: 1 = " + ((cont1/soma)*100) + " % \nProbabilidade: 2 = "+ ((cont2/soma)*100) + " %");
public static int umOuDois (double prob) {
    return Math.random() < prob ? 1 : 2;
}

Esse método vai retornar 1 ou 2 com base na probabilidade. Como são só dois elementos, não precisa passar as duas probabilidades, apenas uma (pois a outra é inferível por 1 - a primeira).

Por exemplo, se você passar como parâmetro 0.5, vai sair 1 e 2 com a mesma probabilidade. Se você passar 0.55, vai sair 1 com 0.55 e 2 com 0.45, e etc.

Não faz sentido produzir um array com a quantidade exata de números para produzir, nesse caso, 55% e 45% dos elementos. Você não precisa produzir os números para saber a quantidade. Dado o número de repetições (100, por exemplo), e as probabilidades (55 e 45), você consegue estimar a quantidade de aparições de cada elemento fazendo uma multiplicação (100 * 0.55 e 100 * 0.45).

Se quiser testar:

public static int umOuDois (double prob) {
    return Math.random() < prob ? 1 : 2;
}

public static void main(String []args){
    int cont1 = 0;
    int cont2 = 0;
    
    int eventos = 1000000;
    
    for (int i = 0; i < eventos; i++) {
        if (umOuDois(0.55) == 1)
            cont1++;
        else
            cont2++;
    }
    
    System.out.printf("1: %.2f%n", (double)cont1/eventos);
    System.out.printf("2: %.2f", (double)cont2/eventos);
}

Eu gostaria que você explicasse um pouco mais sobre isso aqui, se possível. Mais especificamente a parte da probabilidade.

Se você tem um conjunto finito de eventos mutualmente excludentes, a soma das probabilidades de ocorrência é obrigatoriamente 1 (isso é uma definição de probabilidade). Com isso, você tem um caso interessante quando há apenas 2 eventos: a probabilidade de um deles ocorrer é igual a 1 - a probabilidade do outro. Em outras palavras, se A + B = 1, você pode inferir tanto que 1 - A = B como 1 - B = A. Se a probabilidade do primeiro é 30%, a do segundo é obrigatoriamente 70%. Se a do primeiro é 90%, a do segundo é obrigatoriamente 10%, e assim por diante.

Uma forma de simular a observação de um evento é dividir os eventos possíveis em baldes de diferentes tamanhos (proporcionais às suas probabilidades), gerar um número aleatório com distribuição uniforme (ou seja, todos os números tem a mesma chance de aparecer) e checar em qual balde esse número caiu. É como se você jogasse uma bolinha com uma determinada força e depois observasse em qual balde essa bolinha caiu.

Nesse caso dele, existem 2 eventos: aparecer o número 1 e aparecer o número 2. O primeiro balde tem tamanho 55 e o segundo 45. Dá pra visualizar assim:

[–55–][–45–]

Se você joga uma bolinha do lado esquerdo para o direito, com força 30, ela vai cair dentro do primeiro balde. Se jogar com força 56, ela vai passar do primeiro balde e cair no segundo. Se jogar com força 1, vai cair no primeiro, e assim por diante.

A implementação que eu fiz, utiliza o método Math.random() que convenientemente retorna um número no intervalo [0.0, 1.0[ com distribuição uniforme. Como só existem 2 “baldes”, 0.55 e 0.45, só precisa checar se o resultado do random é menor ou maior/igual ao tamanho do primeiro balde. Isso explica a linha Math.random() < prob ? 1 : 2. Se existissem mais do que 2 eventos, seria necessário fazer uma espécie de laço que verifica em qual balde caiu a bolinha, ou então fazer um hashmap que mapeia de um número entre 0 e 1 para um evento.

É difícil explicar isso sem desenhar e sem definições formais de probabilidade, mas acho que dá para entender.

Se quiser a descrição formal, lê a sessão “One-Dimensional Random Walk” aqui:

1 curtida

Entendi. Na verdade, eu estava apenas querendo entender como o Math.random ia funcionar nessa caso, interagindo com a probabilidade. Eu realmente não sabia que ele retornava o intervalo 0.0 - 1.0, achei que retornava apenas um número aleatório qualquer. Pelo visto, a ausência de parâmetros na chamada do método faz com que ele forneça esse intervalo, é isso?

O retorno no intervalo [0.0, 1.0[ é algo bem comum. É tudo o que você precisa para gerar um número em um determinado intervalo. Por exemplo, se você quiser gerar um inteiro aleatório, é só multiplicar esse double aleatório pelo maior inteiro possível e arredondar. Se quiser um número inteiro aleatório dentro de um determinado intervalo, é só fazer algo como:

static int randomBetween (int a, int b) {
    return a + round(random() * (b - a));
}

Dá pra fazer qualquer tipo de função para gerar números aleatórios só com essa aí da classe Math.

Interessante, é um conceito de matemática que não pensei que veria aqui.

Me diga, você sabe se isso é utilizado em outros paradigmas de programação, como a programação funcional? Ouvi dizer que há muita matemática envolvida, e achei curioso o seu conhecimento sobre isso tudo.

Esse conceito é utilizado em praticamente todas as linguagens. Na biblioteca Numpy do Python, por exemplo, existe um método que você passa dois arrays que mapeiam possíveis eventos e a distribuição de probabilidades, e ele devolve uma observação de forma aleatória levando em conta a distribuição. Nesse caso do tópico, a chamada seria algo como:

numpy.random.choice([1, 2], p=[0.55, 0.45])

A questão da matemática na programação funcional é um pouco diferente. Dá pra fazer isso lá, obviamente. Contudo, o ponto mais atraente da programação funcional para fins matemáticos é que é muito mais fácil provar matematicamente que um programa funcional é correto. Isso não se faz na prática em softwares “comuns”. Ao invés de utilizar um método de prova formal e analítico, a gente faz um método empírico, que é basicamente teste de software (unitário, funcional, etc).

Além disso, linguagens de programação funcional tornam um pouco mais fácil fazer coisas como composição de funções, passagem parcial de argumentos, passagem de parâmetro por lista (cada elemento da lista vira um argumento da função, tipo xargs), etc. Lisp, JavaScript e Python são exemplos de linguagens com esse tipo de funcionalidade. Tem problemas que são resolvidos muito mais facilmente com esses recursos.

1 curtida

Obrigado pelos esclarecimentos. Estava pensando em estudar Clojure, por isso a pergunta.

Eu gastei um tempo estudando Clojure e aprendi muita coisa. Estudei só por diversão mesmo, não tinha nenhuma necessidade, só queria me expor a um paradigma diferente. Aprendi muita coisa, influenciou bastante meu estilo de programação. Eu li um monte de livros até chegar nesses dois aqui, que com certeza foram os melhores pra mim:

O primeiro livro é a base de um dos cursos de introdução à programação no MIT. Inclusive, tem um monte de aula do livro no YouTube. Eu fazia assim: lia o capítulo, fazia os exercícios e depois assistia as aulas referentes ao capítulo. Os exemplos são todos em Elixir, um dialeto de lisp que eles usavam lá. Clojure é muito parecido, dá pra fazer os exercícios e acompanhar os exemplos fazendo em Clojure mesmo.

1 curtida

Obrigado, meu caro. Em adição, pretendo fazer o curso da Alura sobre Programação Funcional. Muito me interessa, uma vez que uma das empresas que almejo trabalhar usa bastante.