Objetivo
Gere ( N
) segmentos de linhas aleatórias de comprimento uniforme ( l
), verifique se eles cruzam as t
linhas paralelas equidistantes ( ).
Simulação
O que estamos simulando? Agulha de Buffon . Alise a areia na sua caixa de areia, desenhe um conjunto de linhas paralelas igualmente espaçadas (chame a distância entre elas t
). Pegue um pedaço reto de comprimento l
e solte-o N
na caixa de areia. Seja o número de vezes que cruzou uma linha c
. Então Pi = (2 * l * n) / (t * c)
!
Como estamos simulando isso?
- Aceitar entrada
N,t,l
- Com
N, t, l
todos sendo inteiros positivos - Faça os seguintes
N
horários:- Gere uma coordenada inteira uniformemente aleatória
x,y
- Com
1 <= x, y <= 10^6
x,y
é o centro de um segmento de linha de comprimentol
- Gere um número inteiro uniformemente aleatório
a
- Com
1 <= a <= 180
- Seja
P
o ponto em que o segmento de linha cruzaria o eixo x - Então
a
é o ângulo(x,y), P, (inf,0)
- Gere uma coordenada inteira uniformemente aleatória
- Conte o número
c
,, de segmentos de linha que cruzam a linhax = i*t
para qualquer número inteiroi
- Retorna
(2 * l * N) / (t * c)
Especificação
- Entrada
- Flexível, receba informações de qualquer uma das formas padrão (por exemplo, parâmetro de função, STDIN) e em qualquer formato padrão (por exemplo, String, Binário)
- Resultado
- Flexível, produza de qualquer forma padrão (por exemplo, devolução, impressão)
- Espaço em branco, espaço em branco à direita e à esquerda é aceitável
- Precisão, forneça pelo menos 4 casas decimais de precisão (ou seja
3.1416
)
- Pontuação
- O menor código vence!
Casos de teste
Sua saída pode não estar alinhada com isso, por causa do acaso. Mas, em média, você deve obter tanta precisão para o valor especificado de N, t, l
.
Input (N,t,l) -> Output
----------- ------
10,10,5 -> ?.????
10,100,50 -> ?.????
1000,1000,600 -> 3.????
10000,1000,700 -> 3.1???
100000,1000,700 -> 3.14??
TL; DR
Esses desafios são simulações de algoritmos que exigem apenas a natureza e seu cérebro (e talvez alguns recursos reutilizáveis) para aproximar o Pi. Se você realmente precisa de Pi durante o apocalipse zumbi, esses métodos não desperdiçam munição ! Existem nove desafios no total.
a
também pode ser criada por outro método, se for uniforme? (pensando em uma bolha 2D Gauss)t > l
? Duas soluções abaixo fazem essa suposição, o que simplifica bastante a verificação de interseção.Respostas:
R,
1131007570686765596357 bytesComo uma linguagem de programação estatística e funcional, não é surpreendente que R seja bastante adequado para esse tipo de tarefa. O fato de que a maioria das funções pode receber entrada vetorizada é realmente útil para esse problema, pois, em vez de repetir
N
iterações, passamos apenas vetores de tamanhoN
. Obrigado a @Billywob por algumas sugestões que levam ao corte de 4 bytes. Muito obrigado ao @Primo por me explicar pacientemente como meu código não estava funcionando nos casos emt > l
que agora está corrigido.Experimente online!
Saída de amostra:
Explicação
O problema se resume a determinar se os dois
x
valores da agulha estão nos dois lados de uma linha paralela. Isso tem algumas consequências importantes:y
-valores são irrelevantesx
eixo-é irrelevante, apenas a posição relativa às linhas paralelas mais próximas.Essencialmente, esta é uma tarefa em um espaço unidimensional, onde geramos uma linha com comprimento em [0,
l
] (o ânguloa
determina esse comprimento) e depois verificamos quantas vezes esse comprimento excedet
. O algoritmo aproximado é então:x1
Valores de amostra de [0, 1000000]. Como linhas paralelas ocorrem em todos ost
pontos th ao longo dox
eixo, a posição relativax
éx
módulot
.a
.x2
posição com base ema
.x1+x2
se encaixat
, ou seja, pegue o chão(x1+x2)/t
.A amostragem de
N
números no módulo [0, 1e6]t
é equivalente a simplesmente amostragem deN
números em [0,t
]. Como(x1+x2)/t
é equivalente ax1/t + x2/t
, o primeiro passo passa a ser a amostragem de [0,t
] /t
, ou seja, [0, 1]. Para nossa sorte, esse é o intervalo padrão darunif
função R , que retornaN
números reais de 0 a 1 de uma distribuição uniforme.Repetimos esse passo para gerar
a
o ângulo da agulha.Esses números são interpretados como meia-volta (ou
.5
seja, 90 graus). (O OP solicita graus de 1 a 180, mas nos comentários é esclarecido que qualquer método é permitido se for tão ou mais preciso.) Para um ânguloθ
,sin(θ)
fornece-nos a distância do eixo x entre as extremidades da agulha. (Normalmente, você usaria o co-seno para algo como isso, mas no nosso caso, estamos considerando o ânguloθ
como sendo em relação ao eixo y, e não o eixo x (isto é, um valor de 0 graus vai -se , não à direita ) e, portanto, usamos o seno, que basicamente muda os números.) Multiplicado porl
isso, nos dá ax
localização do final da agulha.Agora dividimos por
t
e adicionamos ox1
valor. Isso produz(x1+x2)/t
, a que distância a agulha se sobressaix1
, em termos de número de linhas paralelas. Para obter o número inteiro de quantas linhas foram cruzadas, usamos ofloor
.Calculamos a soma, dando-nos a contagem
c
de quantas linhas são cruzadas por agulhas.O restante do código está apenas implementando a fórmula para aproximar pi, ou seja
(2*l*N)/(t*c)
,. Economizamos alguns bytes entre parênteses, aproveitando o fato de que(2*l*N)/(t*c) == 2*l*N/t/c
:E tudo está envolvido em uma função anônima:
fonte
(2*l*N) => 2*l*N
?(2*l*N)/(t*c) = 2*l*N/t/c
para que você possa salvar outros dois bytes, pule os parênteses na última parte também.Perl, 97 bytes
Contando o shebang como um, a entrada é obtida de stdin, com espaço separado. Se valores aleatórios não inteiros forem permitidos, isso poderá ser um pouco menor.
Tomei uma liberdade, aproximando π / 180 como 71/4068 , que é precisa dentro de 1,48 · 10 -9 .
Uso da amostra
Substituições matematicamente equivalentes mais ou menos
Assumindo que a coordenada x representa o ponto mais à esquerda da agulha, e não o meio, conforme especificado na descrição do problema:
89 bytes
O problema especifica que
x
deve ser amostrado como um número inteiro aleatório. Se projetarmos o espaçamento entre linhas com um intervalo de um, isso nos deixará com valores da forman/t
com0 <= n < t
, não necessariamente uniforme, set
não dividir uniformemente1e6
. Supondo que uma distribuição uniforme seja aceitável:76 bytes
Observe que, como
rand
sempre será menor que um (e, portanto, truncado para zero), não é necessário no início do intervalo:70 bytes
Supondo que o ângulo da agulha não precise ser um grau inteiro, mas apenas uniformemente aleatório:
59 bytes
Supondo que o ângulo possa ser qualquer distribuição uniforme:
52 bytes
A descrição acima é uma simulação matematicamente correta da agulha de Buffon. No entanto, neste ponto, acho que a maioria das pessoas concorda que isso não é realmente o que a pergunta fazia.
Realmente empurrando
Poderíamos simplesmente jogar fora metade dos casos de teste, sempre que o segundo ponto de extremidade estiver à esquerda do primeiro (em vez de trocá-los):
47 bytes
Observe que os valores
t
el
são irrelevantes para os resultados do experimento. Poderíamos simplesmente ignorá-los (assumindo implicitamente que sejam iguais):28 bytes
Obviamente não-concorrente, mas você tem que admitir, ele tem uma certa elegância.
fonte
Python 2, 141 bytes
porta descarada de rtumbull, já pulando
y
porque totalmente não é necessária.O problema é apenas que pi já é conhecido no programa.
Aqui está (golfable) com pi desconhecido e sem funções trigonométricas
x,y
ing
é apenas para a direção.fonte
from random import randint;from math import cos,pi
. Falhat < l
, por exemplo1000000,1000,70000
.