Eu li sobre círculos em algum lugar e agora aprendi sobre discos ( na verdade é um conceito bastante comum ) e pensei sobre codegolf.
Sua tarefa é aleatoriamente um ponto / vários pontos em um disco com o raio 1.
Regras:
- Todos os pontos devem ter igual probabilidade de serem gerados
- Coordenadas de ponto flutuante devem ser usadas; o requisito mínimo é de duas casas decimais (por exemplo, os pontos
(0.12, -0.45)
ou(0.00, -1.00)
são válidos) - Você recebe -20 bytes se o seu programa realmente exibir o círculo delimitador e os pontos gerados nele. As coordenadas ainda precisam ser válidas, mas não exibidas, e a imagem gerada deve ter pelo menos 201 por 201 pixels de tamanho
- Você obtém -5 bytes se seu programa usa o número de pontos a serem gerados como entrada no stdin
- Se você decidir não plotar o círculo delimitador e o (s) ponto (s), seu programa precisará gerar o (s) ponto (s) gerado (s) no formato
(x, y)
ou(x,y)
no stdout - Se você decidir usar o número de pontos gerados como entrada, mas não plotá-lo - o seu programa precisará gerar todos os pontos aleatórios no formato indicado acima, com ou sem um espaço entre eles.
Menor envio em bytes ganha!
code-golf
math
graphical-output
random
sweerpotato
fonte
fonte
0.3503082505747327+0.13499221288682994j
.Respostas:
Pitão, 26-5 = 21 bytes
Pega o número de coordenadas a serem geradas no stdin e as gera no stdout da seguinte forma:
Usa uma estratégia semelhante ao @ MartinBüttner, gerando coordenadas polares e raios, exceto que o faz usando exponenciação complexa.
fonte
p
, não pode? Apenas altera a saída para linhas separadas.CJam,
2827 bytesEsta solução não é baseada em rejeição. Estou gerando os pontos em coordenadas polares, mas com uma distribuição não uniforme dos raios para obter uma densidade uniforme dos pontos.
Teste aqui.
Explicação
Por que isso funciona? Considere um anel estreito de raio
r
e largura (pequena)dr
. A área é aproximadamente2π*r*dr
(se o anel for estreito, a circunferência interna e externa são quase idênticas e a curvatura pode ser ignorada, de modo que a área possa ser tratada como a de um retângulo com comprimentos laterais da circunferência e a largura da anel). Portanto, a área aumenta linearmente com o raio. Isso significa que também queremos uma distribuição linear dos raios aleatórios, a fim de obter uma densidade constante (com o dobro do raio, há o dobro da área a ser preenchida, portanto, queremos o dobro do número de pontos).Como geramos uma distribuição aleatória linear de 0 a 1? Vejamos o caso discreto primeiro. Digamos, temos uma distribuição desejada de 4 valores, como
{0.1, 0.4, 0.2, 0.3}
(ou seja, queremos1
ser 4 vezes mais comuns que0
e duas vezes mais comuns que2
; queremos3
três vezes mais comuns que0
):Como escolher um dos quatro valores com a distribuição desejada? Podemos empilhá-los, escolher um valor aleatoriamente uniforme entre 0 e 1 no eixo y e escolher o segmento nesse ponto:
Existe uma maneira diferente de visualizar essa seleção. Em vez disso, poderíamos substituir cada valor da distribuição pela acumulação dos valores até esse ponto:
E agora tratamos a linha superior deste gráfico como uma função
f(x) = y
e a invertemos para obter uma função , que podemos aplicar a um valor aleatoriamente uniforme em :g(y) = f-1(y) = x
y ∈ [0,1]
Legal, então como usar isso para gerar uma distribuição linear de raios? Esta é a distribuição que queremos:
O primeiro passo é acumular os valores da distribuição. Mas a distribuição é contínua, portanto, em vez de somar todos os valores anteriores, usamos uma integral de
0
parar
. Podemos facilmente resolver esse analiticamente: . No entanto, queremos que isso seja normalizado, ou seja, multiplicá-lo por uma constante de modo que isso dê o valor máximo de , então o que realmente queremos é :∫0r r dr = 1/2 r2
1
r
r2
E, finalmente, invertemos isso para obter uma função na qual podemos aplicar um valor uniforme
[0,1]
, o que podemos fazer novamente analiticamente: é apenasr = √y
, ondey
está o valor aleatório:Essa é uma técnica bastante útil que geralmente pode ser usada para gerar exatamente distribuições simples (funciona para qualquer distribuição, mas para complicadas, as duas últimas etapas podem ter que ser resolvidas numericamente). No entanto, eu não o usaria neste caso específico no código de produção, porque a raiz quadrada, o seno e o cosseno são proibitivamente caros: o uso de um algoritmo baseado em rejeição é, em média, muito mais rápido, porque só precisa de adição e multiplicação.
fonte
Mathematica,
6844 - 20 = 24 bytesMuito obrigado a David Carraher por me informar
RandomPoint
, que economizou 24 (!) Bytes. Mathematica não tem um built-in para tudo.Isso representa o ponto e o círculo delimitador para se qualificar para o bônus:
O resultado é uma imagem vetorial; portanto, a especificação de tamanho de 201x201 pixels não faz muito sentido, mas, por padrão, é maior que isso.
fonte
Graphics[{Circle[], Point@RandomPoint@Disk[]}]
?Graphics@{Circle[], Point@RandomPoint@Disk[]}
,
?CJam,
3126 bytesIsso funciona gerando repetidamente pontos aleatórios em um quadrado de comprimento lateral 2 e mantendo o primeiro que cai dentro do disco da unidade.
Obrigado a @ MartinBüttner por jogar fora 3 bytes!
Experimente on-line no intérprete CJam .
Como funciona
fonte
iKe ,
5351 bytesNada de especial, mas acho que devemos ter pelo menos uma solução gráfica:
Experimente no seu navegador .
Edit: Eu posso raspar dois bytes aplicando a abordagem de @ MartinBüttner para modificar a distribuição de coordenadas polares. Eu acho que também é um pouco mais direto:
fonte
Perl, 59 bytes
Esta é apenas uma solução simples, gerando pontos em um quadrado e rejeitando aqueles muito distantes. Meu truque de golfe singular é incluir as tarefas dentro da condição.
Edit: No processo de golfe, eu achei uma maneira interessante de imprimir pontos aleatórios em um círculo .
fonte
Oitava,
2453 - 20 = 33 bytesGera 501 valores teta igualmente espaçados mais um número aleatório e dimensiona todos eles para [0..2π]. Em seguida, gera 501 1 para o raio do círculo, mais um raio aleatório para o ponto e pega a raiz quadrada para garantir uma distribuição uniforme sobre o disco. Em seguida, plota todos os pontos como coordenadas polares.
Aqui está uma demonstração rápida da distribuição (sem o círculo unitário):
fonte
Oitava / Matlab,
7464 bytesMétodo de rejeição , 64 bytes:
Método direto , 74 bytes (obrigado a Martin Büttner por me ajudar a corrigir dois erros):
fonte
R,
999581-20 =797561 bytesUse a construção de números complexos para construir os x / ys a partir de coordenadas polares. Receber a entrada foi um pouco caro e provavelmente existe uma maneira melhor de fazer isso. O
ylim
eé para garantir que todo o círculo seja plotado e oxlim
asp
garante que os pontos sejam mostrados sob o símbolo do círculo.Graças a @jbaums e @flodel pela economia
Experimente aqui
fonte
runif(9,0,1)
pode ser simplificado pararunif(9)
symbols(0,0,1,i=F,asp=1,ylim=c(-1,1));points(complex(,,,runif(9),runif(9,-1)*pi))
yli
trabalha no lugar deylim
.Processando / Java 141 bytes-20 = 121
o requisito de tamanho mínimo de 201 * 201 exige que eu insira o
setup
método, já que o Processing.org padroniza 200x200 :(fonte
QBasic, 138 bytes - 20 - 5 = 113
Pega a entrada do usuário e desenha o disco e os pontos. Testado em QB64 .
Esta é uma estratégia bastante básica "jogue no alvo e mantenha o que fica". O problema é que "o que cola" não é determinado matematicamente, mas graficamente: um disco branco é plotado em um fundo preto e os pontos gerados aleatoriamente são rejeitados até que não sejam pretos. Os pontos em si são desenhados em azul (embora seja difícil dizer quando são pixels únicos - clique na imagem para ampliar).
fonte
awk - 95-5 = 90
Como não tinha muita certeza da parte rand () <. 5, fiz alguns testes de distribuição com isso, usando este script:
que para uma entrada de 1e7 me dá esse resultado, depois de tomar uma ou duas vezes no meu café:
o que eu acho que está bem.
Uma pequena explicação:
depois de rabiscar por um tempo, que se você quiser dividir o disco em quatro anéis com a mesma área, os raios nos quais você precisaria cortar são sqrt (1/4), sqrt (1/2 ) e sqrt (3/4). Como o raio real do ponto que eu teste seria sqrt (x ^ 2 + y ^ 2), eu posso pular a raiz quadrada todos juntos. A 1/4, 2/4, 3/4 "coincidência" pode estar relacionada ao que M. Buettner apontou anteriormente.
fonte
HPPPL , 146 (171-20-5) bytes
Exemplo para 10000 pontos (incluindo o tempo em segundos para o dispositivo real):
A função em si é chamada por
r(n)
. O restante da imagem acima é apenas para fins de tempo.Resultado (o diâmetro do disco é 236 pixels):
A versão acima não armazena as coordenadas do ponto, então escrevi uma versão que usa dois parâmetros
r(n,p)
.n
é o número de pontos ep=0
retorna os pontos ao terminal,p=1
plota os pontos e o disco), caso o armazenamento de coordenadas seja obrigatório. Esta versão tem 283 (308-20-5) bytes de comprimento:A versão não destruída:
Saída terminal para
r(10,0)
:r(10,1)
mostra o disco com os pontos, como mostrado acima.fonte
JavaScript, 75 bytes
Baseado em rejeição:
Método direto (80 bytes):
fonte
Python,
135130 bytesRemovido o
**0.5
agradecimento à sugestão de @ jimmy23013 (por ser um círculo unitário, agora estou verificando se a distância ao quadrado entre (x, y) e (0, 0) é igual a 1 2. É a mesma coisa.Isso também me liberou para remover os parênteses.
fonte
**0.5
.