Corrigir uma função aleatória interrompida

18

Um amigo possui um cartão complementar em seu computador que gera um número perfeitamente aleatório de 1 a 5, inclusive. Infelizmente, eles derramaram cola de alguma forma, e agora gera apenas 2 para todos os números de 1 a 4. Felizmente, a aleatoriedade é preservada, mas 2 tem uma probabilidade de 80% e 5 tem uma probabilidade de 20%, e não há 1, 3 ou 4 gerados. Usando essa fonte aleatória (chame-a BrokenRand()ou algo similar), escreva um gerador de números aleatórios que produza números de 1 a 5, cada um com uma probabilidade igual de 20% com a mesma aleatoriedade perfeita que a fonte original.

O programa mais curto vence. Pontos de bônus concedidos pelo número mínimo de chamadas a serem BrokenRandprestadas imparcialmente por uma consultoria de atendimento ao cliente selecionada demograficamente, discriminada por idade e sexo - ou seja, eu.

Thomas O
fonte

Respostas:

10

JavaScript - 69 caracteres

Isso usa o extrator de von Neumann para gerar bits imparciais; o algoritmo geral também é descrito no site do HotBits . Três bits são usados ​​para formar um número de 0 a 7. Todos os números 5 e acima são descartados e 1 é adicionado a cada um dos demais antes de serem impressos. Fiz uma simulação para mostrar que isso não é muito tendencioso .

Você precisa fornecer sua própria função r()para acessar o RNG.

 for(;;v<5&&alert(v+1))for(v=i=0;i<3;a-b&&(v*=2,v+=a<b,i++))b=r(a=r())
PleaseStand
fonte
Isso é realmente bem feito! Eu gosto de como você curto-circuito o valor do incremento.
snmcdonald
Você poderia gerar 7 bits e extrair 3 números aleatórios para reduzir as chamadas para BrokenRand, mas que poderia custar mais alguns golpes
gnibbler
5

scala 79 caracteres:

// preparation: 
val r = util.Random 
def defektRNG = if (r.nextInt (5) == 0) 5 else 2 

(1 to 20).foreach (_ => print (" " + defektRNG))
// first impression:
// 2 2 2 2 2 2 2 5 2 2 5 2 2 2 5 2 2 2 2 2

def rnd : Int = { val k = (1 to 5).map (_ => defektRNG)
  if (k.sum == 13) k.findIndexOf (_ == 5) + 1 else rnd } 

// first impression:
(1 to 20).foreach (_ => print (" " + rnd))             
// 3 3 2 3 5 2 2 5 1 1 3 4 3 2 5 3 3 1 5 4
// control:
(1 to 50000).map (_ => rnd).groupBy (identity) .map (_._2.length) 
// scala.collection.immutable.Iterable[Int] = List(10151, 9997, 9971, 9955, 9926)

Agora, para o golfe real, o apelido defektRNG brokenRand é renomeado para b.

def r:Int={val k=(1 to 5).map(_=>b)
if(k.sum==13)k.findIndexOf(_==5)+1 else r} 

Como funciona: Na maioria das vezes, b retorna uma sequência de 2s. Mas se você fizer 5 chamadas para b, muitas vezes terminará com um resultado de 4x2 e 1x5, é o segundo evento mais provável e poderá ser 5-2-2-2-2, 2-5-2-2 -2, 2-2-5-2-2, 2-2-2-5-2 e 2-2-2-2-5.

Estes têm em comum que a soma é 4 * 2 + 5 = 13. O índice dos cinco primeiros pode ser usado para definir um número aleatório válido. Se houver mais ou menos de um 5, uma soma maior ou menor 13, repita.

Um contador em 'rnd' aka 'r' pode mostrar quantas chamadas são necessárias, em média, para produzir os números. Existem 121 200 chamadas para r para 50 000 números aleatórios, o que não é impressionante. :)

Usuário desconhecido
fonte
3

> <> (Peixe) - 55 bytes

Atualizado para usar o mesmo algoritmo que @user desconhecido em sua resposta scala

<v? = d + &: i & + &: i & + &: i & + &: i &: i
 0 0
 > 1 + $ 5 (? Vnao;
 ^ <

Ele espera que o gerador quebrado seja conectado ao stdin; aqui está o script python que eu usei . O código corresponde à especificação atual do Fish, mas usei uma versão modificada do antigo intérprete.

bash:$ for i in $(seq 1000); do ./bad_rand.py | ./myfish.py rand.fish; done >res.txt
bash:$ for i in $(seq 5); do echo -n "$i : "; grep -c $i res.txt; done
1 : 193
2 : 204
3 : 198
4 : 206
5 : 199

Eu faria uma amostra maior, mas é lenta.

cthom06
fonte
2

GolfScript, 23 bytes

Resposta tardia, mas como isso apareceu na primeira página ...

0{;[{r}5*].5?)\5-,4-}do

Usa o mesmo algoritmo que a solução Scala do usuário desconhecido . Assume que o gerador de números aleatórios tendenciosos é fornecido como uma sub-rotina GolfScript denominada r; você pode definir um RNG tendencioso adequado, por exemplo, como:

{5rand!3*2+}:r;

Aqui está um teste rápido que demonstra falta de viés. Infelizmente, o servidor GolfScript on-line é meio lento, então tive que reduzir a demonstração para apenas 100 amostras para concluir a tempo. Se estiver executando o teste localmente com o intérprete GolfScript , tente aumentar 100*para 1000*ou mesmo 10000*.

(O servidor GolfScript também às vezes congela e expira aleatoriamente de qualquer maneira. Se isso acontecer com você, tentar novamente normalmente o soluciona. Isso acontece com outro código também e só acontece no servidor, não no meu próprio computador, por isso estou confiante que é um problema com o servidor e não com o meu código.)

Ilmari Karonen
fonte
-1

javascript, 160 caracteres sem reduzir a legibilidade, também conhecido como otimização

function giveRandom(){
    var result = Math.floor(5 * Math.random()) + 1;
    while(BrockenRand() != 5){
        result = Math.floor(5 * Math.random()) + 1;
    }
    return result;
}
www0z0k
fonte
@ Snmcdonald -alguns de que não é um erro de digitação, é uma maneira de melhorar js aleatórios por um gerador aleatório perfeito aprovando somente (totalmente aleatória!) 20% dos resultados
www0z0k
Gostaria de explicar o que BrockenBand()é, então?
Mateen Ulhaq
6
Eu acho que você perdeu o ponto
cthom06
@muntoo - meaningBrockenRand
www0z0k
Salve alguns bytes desta maneira:function giveRandom(){return Math.ceil(Math.random()*5)}
user300375