Doğal Pi # 1 - Kum


9

Hedef

NDüzgün uzunlukta ( ) rastgele çizgi segmentleri üretin ( ) l, eşit mesafede ( t) paralel çizgileri geçip geçmediklerini kontrol edin .

Simülasyon

Neyi simüle ediyoruz? Buffon'un iğnesi . Kum havuzunuzdaki kumları düzeltin, eşit aralıklı paralel çizgiler çizin (aradaki mesafeyi çağırın t). Uzun bir düz çubuk alın lve Nzamanları kum havuzuna bırakın . Bir çizgiyi kaç kez geçmesine izin verin c. Öyleyse Pi = (2 * l * n) / (t * c)!

Bunu nasıl simüle ediyoruz?

  • Girdi al N,t,l
  • İle N, t, ltüm varlık pozitif tamsayılar
  • Aşağıdakileri yapın N:
    • Düzgün rasgele bir tamsayı koordinatı oluşturma x,y
    • İle 1 <= x, y <= 10^6
    • x,y uzunluktaki bir çizgi bölümünün merkezidir l
    • Düzgün rastgele bir tamsayı oluşturma a
    • İle 1 <= a <= 180
    • Izin vermek Pçizgi segmenti x ekseni geçecek nokta olmak
    • O zaman aaçı(x,y), P, (inf,0)
  • Herhangi bir tamsayı ciçin çizgiyi geçen çizgi segmentlerinin sayısını,x = i*ti
  • Dönüş (2 * l * N) / (t * c)

resim açıklamasını buraya girin

resim açıklamasını buraya girin

Şartname

  • Giriş
    • Esnek, standart yollardan herhangi birinde (örn. İşlev parametresi, STDIN) ve herhangi bir standart biçimde (örn. String, Binary) girdi alın
  • Çıktı
    • Esnek, standart yollardan herhangi biriyle çıktı verin (örneğin iade, baskı)
    • Beyaz boşluk, sondaki ve önde gelen beyaz boşluk kabul edilebilir
    • Doğruluk, lütfen en az 4 ondalık doğruluk yeri sağlayın (yani 3.1416)
  • puanlama
    • En kısa kod kazanır!

Test Durumları

Rastgele şans nedeniyle çıktınız bunlarla uyumlu olmayabilir. Ancak ortalama olarak, verilen değeri için bu kadar doğruluk elde etmelisiniz 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

Bu zorluklar, Pi'ye yaklaşık olarak doğa ve beyninizi (ve belki de bazı yeniden kullanılabilir kaynakları) gerektiren algoritmaların simülasyonlarıdır. Zombi kıyameti sırasında gerçekten Pi'ye ihtiyacınız varsa, bu yöntemler cephaneyi boşa harcamaz ! Orada dokuz zorluklar toplam.


Zaten 1 numara yaptığını sanıyordum?
Conor O'Brien

1
@ ConorO'Brien I sıfırlama endeksi XD
NonlinearFruit

bununla ilgili sorun, karmaşık sayıları olmayan dillerde, 0.1080 sayısını 0..pi'ye çevirmeniz gerekir, bu da buffon'un iğne deneyinin amacını bozar.
Level River St

@DinlinearFruit düzgünse yön abaşka bir yöntemle de oluşturulabilir mi? (2D Gauss
Baloncuğu Düşünme

1
Bunu varsayabilir miyiz t > l? Aşağıdaki iki çözüm, kavşak kontrolünü biraz basitleştiren bu varsayımı yapar.
primo

Yanıtlar:


9

R, 113 , 100 75 70 68 67 65 59 63 57 bayt

İstatistiksel, işlevsel bir programlama dili olarak, R'nin bu tür bir görev için oldukça uygun olması şaşırtıcı değildir. Çoğu fonksiyonun vektörize girdi alabilmesi, bu problem için gerçekten yararlıdır, Niterasyonlar üzerinde döngü yapmak yerine , sadece boyut vektörlerinin etrafından geçeriz N. @Billywob'a 4 baytın kesilmesine yol açan bazı öneriler için teşekkürler. @Primo'ya, kodumun t > lşu anda düzeltildiği durumlarda kodumun nasıl çalışmadığını sabırla açıkladığı için çok teşekkürler .

pryr::f(2*l*N/t/sum(floor(runif(N)+sinpi(runif(N))*l/t)))

Çevrimiçi deneyin!

Örnek çıktı:

N=1000, t=1000, l=500
3.037975

N=10000, t=1000, l=700
3.11943

N=100000, t=1000, l=700
3.140351

açıklama

Sorun x, iğnenin iki değerinin paralel bir çizginin her iki tarafında olup olmadığını belirlemek için kaynar . Bunun bazı önemli sonuçları vardır:

  1. y- değerler önemsiz
  2. x-Aksindeki mutlak konum ilgisizdir, sadece en yakın paralel çizgilere göre konumdur.

Temelde bu, 1 boyutlu bir alanda bir görevdir; burada [0, l] uzunluğunda bir çizgi oluştururuz (açı abu uzunluğu belirler) ve sonra bu uzunluğun kaç kez aşıldığını kontrol ederiz t. Kaba algoritma şu şekildedir:

  1. x1[0, 1000000] 'den örnek değerler. Paralel çizgiler, her cereyan yana tboyunca inci alanına x-Axis, göreli xpozisyonu içinde bir xmodülo t.
  2. Bir açıyı örnekleyin a.
  3. Göre x2konumu hesaplayın a.
  4. Kaç kez x1+x2oturduğunu kontrol edin t, yani zemini alın (x1+x2)/t.

Örnekleme N[0, 1E6] modülo sayıları tsadece örnekleme eşdeğerdir N[0, sayıları t]. Yana (x1+x2)/teşdeğerdir x1/t + x2/t, ilk adım numune olur [0, t] / törneğin, [0, 1]. Bizim için şanslı, bu R'nin runifişlevi için varsayılan aralıktır , bu Nda eşit sayıdaki dağılımdan 0 ile 1 arasında gerçek sayılar döndürür .

                          runif(N)

aİğnenin açısını üretmek için bu adımı tekrarlıyoruz .

                                         runif(N)

Bu sayılar yarım dönüş olarak yorumlanır (yani .590 derecedir). (OP, 1'den 180'e kadar dereceler ister, ancak yorumlarda, bir veya daha kesin olduğu takdirde herhangi bir yönteme izin verildiği açıktır.) Bir açı için θ, sin(θ)iğnenin uçları arasındaki x ekseni mesafesini verir. (Normalde kosinüsü böyle bir şey için kullanırsınız; ancak bizim durumumuzda, açıyı θx eksenine değil, y eksenine göre görüyoruz (yani 0 derecelik bir değer yükseliyor , değil sağ ), ve bu nedenle sayıları fazla değiştiren sinüsü kullanırız.) Bununla çarpıldığında lbize xiğnenin ucunun yeri verilir.

                                   sinpi(runif(N))*l

Şimdi bölünür tve x1değeri ekleriz . Bu , paralel hatların sayısı bakımından (x1+x2)/tiğnenin ne kadar uzağa çıktığını verir x1. Kaç çizginin geçtiğinin tamsayısını elde etmek için floor.

                    floor(runif(N)+sinpi(runif(N))*l/t)

Toplamı hesaplıyoruz, ciğneler tarafından kaç çizginin geçtiğini bize veriyoruz .

                sum(floor(runif(N)+sinpi(runif(N))*l/t))

Kodun geri kalanı sadece pi'ye yakınlaştırma formülünü uyguluyor, yani (2*l*N)/(t*c). Aşağıdakilerden yararlanarak parantez üzerine bazı baytlar kaydederiz (2*l*N)/(t*c) == 2*l*N/t/c:

        2*l*N/t/sum(floor(runif(N)+sinpi(runif(N))*l/t))

Ve her şey anonim bir işleve sarılmıştır:

pryr::f(2*l*N/t/sum(floor(runif(N)+sinpi(runif(N))*l/t)))

@rturnbull İyi biri! Yine de parantezleri başlangıçta atlayamaz mısınız? (2*l*N) => 2*l*N?
Billywob

@Billywob İyi tespit! Teşekkürler.
rturnbull

@rturnbull Oh ve bu arada, (2*l*N)/(t*c) = 2*l*N/t/cson bölümde parantezleri atlayarak iki bayt daha kaydedebilirsiniz.
Billywob

@Billywob Yine, iyi tespit! Tekrar teşekkürler.
rturnbull

1
@primo Tekrar teşekkürler, şimdi düzeltilmelidir.
rturnbull

6

Perl, 97 bayt

#!perl -p
/ \d+/;$_*=2*$'/$&/map{($x=(1+~~rand 1e6)/$&)-$a..$x+($a=$'/$&/2*sin~~rand(180)*71/4068)-1}1..$_

Mesele bir olarak sayılır, girdi boşluktan ayrılmış stdin'den alınır. Tamsayı olmayan rastgele değerlere izin verildiyse, bu biraz daha kısa olabilir.

1.48 · 10-9 içinde doğru olan π / 180'i 71/4068 olarak tahmin eden bir özgürlük aldım .

Örnek Kullanımı

$ echo 1000000 1000 70000 | perl pi-sand.pl
3.14115345174061

Aşağı yukarı matematiksel olarak eşdeğer ikameler

X koordinatının, iğnenin orta yerine değil, en sol noktasını temsil ettiği varsayıldığında, problem açıklamasında belirtildiği gibi:

89 bayt

#!perl -p
/ \d+/;$_*=2*$'/$&/map{($x=(1+~~rand 1e6)/$&)..$x+($'/$&*sin~~rand(180)*71/4068)-1}1..$_

Sorun x, rastgele bir tamsayı olarak örnekleneceğini belirtir . Biz tek bir aralığa kadar satır aralığı proje, bu formun değerlerle bizi bırakacaktır n/tile 0 <= n < teğer ille üniforma değil, teşit bölmek değil 1e6. Bununla birlikte, tekdüze bir dağılımın kabul edilebilir olduğunu varsayarsak:

76 bayt

#!perl -p
/ \d+/;$_*=2*$'/$&/map{($x=rand)..$x+($'/$&*sin~~rand(180)*71/4068)-1}1..$_

Çünkü o Not randher zaman daha az bir (ve dolayısıyla sıfıra kesilir) olacaktır, bu aralığın başında gerekli değildir:

70 bayt

#!perl -p
/ \d+/;$_*=2*$'/$&/map{1..(rand)+($'/$&*sin~~rand(180)*71/4068)}1..$_

İğnenin açısının bir tamsayı derecesi değil, sadece eşit olarak rastgele olması gerektiğini varsayarsak:

59 bayt

#!perl -p
/ \d+/;$_*=2*$'/$&/map{1..(rand)+abs$'/$&*sin rand$`}1..$_

Açının herhangi bir homojen dağılım olabileceğini varsayarsak:

52 bayt

#!perl -p
/ \d+/;$_*=2*$'/$&/map{1..(rand)+abs$'/$&*sin}1..$_

Yukarıdaki, Buffon'un İğnesinin matematiksel olarak doğru bir simülasyonudur. Bununla birlikte, bu noktada çoğu insan bunun aslında sorunun istediği şey olmadığını kabul eder.


Gerçekten itiyorum

İkinci uç nokta birincinin solunda olduğunda (takas etmek yerine) test vakalarının yarısını atabiliriz:

47 bayt

#!perl -p
/ \d+/;$_*=$'/$&/map{1..(rand)+$'/$&*sin}1..$_

Değerleri unutmayın tve ldeney sonuçlarına önemsiz. Onları görmezden gelebiliriz (örtük olarak eşit olduklarını varsayarak):

28 bayt

#!perl -p
$_/=map{1..(rand)+sin}1..$_

Açıkçası rekabet etmiyor, ama itiraf etmelisiniz, bunun belirli bir zarafeti var.


4

Python 2, 141 bayt

utanmaz liman rtumbull, zaten atlama yçünkü tamamen gerekli değil.

from math import*
from random import*
lambda N,t,l:(2.*l*N)/(t*sum(randint(1,1e6)%t+abs(cos(randint(1,180)*pi/180))*l>t for _ in range(N)))

Sorun sadece, pi programda zaten biliniyor.

Burada bilinmeyen pi ve trigonometrik fonksiyonları olmayan (golf edilebilir)

def g(N,t,l):
 c=0
 for _ in range(N):
    x,y=gauss(0,1),gauss(0,1);c+=randint(1,1e6)%t+abs(x/sqrt(x*x+y*y))*l>t
 return(2.*l*N)/(t*c)

x,yiçinde gsadece yöndür.


Gerektirir from random import randint;from math import cos,pi. İçin başarısız t < l, örn 1000000,1000,70000.
primo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.