Tự nhiên số 1 - Cát


9

Mục tiêu

Tạo ( N) các đoạn đường ngẫu nhiên có độ dài đồng nhất ( l), kiểm tra xem chúng có vượt qua các tđường thẳng song song ( ) không.

Mô phỏng

Chúng ta đang mô phỏng cái gì? Kim của Buffon . Làm mịn cát trong hộp cát của bạn, vẽ một tập hợp các đường song song cách đều nhau (gọi khoảng cách ở giữa t). Lấy một thanh thẳng dài lvà thả nó Nvào hộp cát. Hãy để số lần nó vượt qua một dòng c. Sau đó Pi = (2 * l * n) / (t * c)!

Làm thế nào chúng ta mô phỏng điều này?

  • Lấy đầu vào N,t,l
  • Với N, t, ltất cả là số nguyên dương
  • Làm những Nlần sau :
    • Tạo tọa độ nguyên ngẫu nhiên đồng đều x,y
    • Với 1 <= x, y <= 10^6
    • x,y là trung tâm của một đoạn đường dài l
    • Tạo một số nguyên ngẫu nhiên đồng đều a
    • Với 1 <= a <= 180
    • Gọi Plà điểm mà đoạn thẳng sẽ đi qua trục x
    • Sau đó alà góc(x,y), P, (inf,0)
  • Đếm số lượng, ccủa các phân đoạn dòng vượt qua dòng x = i*tcho bất kỳ số nguyên nàoi
  • Trở về (2 * l * N) / (t * c)

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Sự chỉ rõ

  • Đầu vào
    • Linh hoạt, nhận đầu vào theo bất kỳ cách tiêu chuẩn nào (ví dụ: tham số hàm, STDIN) và ở bất kỳ định dạng chuẩn nào (ví dụ: Chuỗi, Nhị phân)
  • Đầu ra
    • Linh hoạt, cung cấp đầu ra theo bất kỳ cách tiêu chuẩn nào (ví dụ: trả lại, in)
    • Không gian trắng, dấu vết và khoảng trắng hàng đầu được chấp nhận
    • Độ chính xác, vui lòng cung cấp ít nhất 4 chữ số thập phân chính xác (nghĩa là 3.1416)
  • Chấm điểm
    • Mã ngắn nhất sẽ thắng!

Các trường hợp thử nghiệm

Đầu ra của bạn có thể không phù hợp với những điều này, vì cơ hội ngẫu nhiên. Nhưng trung bình, bạn sẽ nhận được nhiều về độ chính xác này cho giá trị đã cho 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

Những thách thức này là mô phỏng các thuật toán chỉ yêu cầu tự nhiên và bộ não của bạn (và có thể một số tài nguyên có thể sử dụng lại) để ước tính Pi. Nếu bạn thực sự cần Pi trong ngày tận thế zombie, những phương pháp này không lãng phí đạn ! Có chín thử thách tổng cộng.


Tôi nghĩ bạn đã làm số 1?
Conor O'Brien

1
@ ConorO'Brien Tôi không lập chỉ mục nó XD
tuyến

Vấn đề với điều này là, trong các ngôn ngữ không có số phức, bạn cần biến số 0..180 thành 0..pi, thay vào đó đánh bại mục đích của thí nghiệm kim trâu.
Cấp sông St

@NonlinearFbean có thể tạo hướng acũng bằng phương pháp khác, nếu nó đồng nhất? (nghĩ về bong bóng Gauss 2D)
Karl Napf

1
Nó có thể được giả định rằng t > l? Hai giải pháp dưới đây đưa ra giả định này, giúp đơn giản hóa việc kiểm tra giao lộ khá nhiều.
primo

Câu trả lời:


9

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

Là một ngôn ngữ lập trình chức năng, thống kê, không có gì đáng ngạc nhiên khi R khá phù hợp với loại nhiệm vụ này. Thực tế là hầu hết các hàm có thể lấy đầu vào véc tơ thực sự hữu ích cho vấn đề này, thay vì lặp qua các Nlần lặp, chúng ta chỉ chuyển qua các vectơ kích thước N. Cảm ơn @Billywob vì một số gợi ý dẫn đến việc cắt đi 4 byte. Rất cám ơn @Primo đã kiên nhẫn giải thích cho tôi cách mã của tôi không hoạt động cho các trường hợp t > l, hiện đã được sửa.

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

Hãy thử trực tuyến!

Đầu ra mẫu:

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

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

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

Giải trình

Vấn đề sôi nổi để xác định xem hai xgiá trị của kim nằm ở hai bên của một đường thẳng song song. Điều này có một số hậu quả quan trọng:

  1. y-giá trị không liên quan
  2. Vị trí tuyệt đối trên x-axis là không liên quan, chỉ có vị trí liên quan đến các đường song song gần nhất.

Về cơ bản, đây là một nhiệm vụ trong không gian 1 chiều, trong đó chúng ta tạo ra một dòng có độ dài trong [0, l] (góc axác định độ dài này), và sau đó chúng ta kiểm tra xem độ dài này vượt quá bao nhiêu lần t. Thuật toán thô là:

  1. x1Giá trị mẫu từ [0, 1000000]. Vì các đường song song xảy ra tại mọi tđiểm dọc theo xtrục -axis, nên xvị trí tương đối là xmodulo t.
  2. Mẫu một góc a.
  3. Tính toán x2vị trí dựa trên a.
  4. Kiểm tra bao nhiêu lần x1+x2phù hợp với t, tức là lấy sàn của (x1+x2)/t.

Các Nsố lấy mẫu trong [0, 1e6] modulo ttương đương với các Nsố lấy mẫu đơn giản trong [0, t]. Vì (x1+x2)/ttương đương với x1/t + x2/t, bước đầu tiên trở thành lấy mẫu từ [0, t] / t, tức là [0, 1]. May mắn cho chúng tôi, đó là phạm vi mặc định cho runifhàm R , trả về Ncác số thực từ 0 đến 1 từ một phân phối thống nhất.

                          runif(N)

Chúng tôi lặp lại bước này để tạo ra a, góc của kim.

                                         runif(N)

Những con số này được hiểu là một nửa quay (tức .5là 90 độ). (OP yêu cầu độ từ 1 đến 180, nhưng trong các bình luận, người ta đã làm rõ rằng mọi phương pháp đều được phép nếu nó chính xác hoặc chính xác hơn.) Đối với một góc θ, sin(θ)cho chúng ta khoảng cách trục x giữa hai đầu kim. (Thông thường bạn sẽ sử dụng cosin cho một cái gì đó như thế này, nhưng trong trường hợp của chúng tôi, chúng tôi đang xem xét góc θlà tương đối với trục y, không phải trục x (nghĩa là giá trị 0 độ tăng lên , không phải bên phải ), và do đó chúng tôi sử dụng sin, về cơ bản là dịch chuyển các số.) Nhân với lđiều này cho chúng ta xvị trí của đầu kim.

                                   sinpi(runif(N))*l

Bây giờ chúng tôi chia tvà thêm x1giá trị. Điều này mang lại (x1+x2)/t, đó là khoảng cách mà kim nhô ra từ bao xa x1, về số lượng các đường song song. Để lấy số nguyên có bao nhiêu dòng được giao nhau, chúng ta lấy floor.

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

Chúng tôi tính toán tổng, cho chúng tôi đếm cxem có bao nhiêu dòng được gạch chéo.

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

Phần còn lại của mã chỉ là thực hiện công thức tính gần đúng số pi, nghĩa là (2*l*N)/(t*c). Chúng tôi lưu một số byte trên dấu ngoặc đơn bằng cách tận dụng thực tế rằng (2*l*N)/(t*c) == 2*l*N/t/c:

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

Và toàn bộ điều được gói vào một chức năng ẩn danh:

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

@rturnbull Đẹp một! Bạn không nên bỏ qua dấu ngoặc đơn ngay từ đầu chứ? (2*l*N) => 2*l*N?
Billywob

@Billywob Phát hiện tốt! Cảm ơn.
rturnbull

@rturnbull Oh và nhân tiện, (2*l*N)/(t*c) = 2*l*N/t/cvì vậy bạn có thể lưu hai byte khác bằng cách bỏ qua dấu ngoặc đơn trên phần cuối cùng.
Billywob

@Billywob Một lần nữa, phát hiện tốt! Cảm ơn một lần nữa.
rturnbull

1
@primo Cảm ơn một lần nữa, nó sẽ được sửa ngay bây giờ.
rturnbull

6

Perl, 97 byte

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

Đếm shebang là một, đầu vào được lấy từ stdin, phân tách không gian. Nếu các giá trị ngẫu nhiên không nguyên được cho phép, giá trị này có thể ngắn hơn một chút.

Tôi đã lấy một quyền tự do, xấp xỉ π / 18071/4068 , chính xác trong vòng 1,48 · 10 -9 .

Sử dụng mẫu

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

Thay thế tương đương nhiều hơn hoặc ít hơn về mặt toán học

Giả sử tọa độ x đại diện cho điểm cực trái của kim, chứ không phải giữa của nó, như được chỉ định trong mô tả vấn đề:

89 byte

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

Vấn đề chỉ định rằng xsẽ được lấy mẫu dưới dạng một số nguyên ngẫu nhiên. Nếu chúng ta chiếu khoảng cách dòng đến một khoảng cách của một, điều này sẽ để lại cho chúng ta các giá trị của biểu mẫu n/tvới 0 <= n < t, không nhất thiết phải đồng nhất, nếu tkhông chia đều 1e6. Giả sử rằng một phân phối thống nhất dù sao cũng được chấp nhận:

76 byte

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

Lưu ý rằng vì randsẽ luôn nhỏ hơn một (và do đó bị cắt cụt về 0), nên không cần thiết khi bắt đầu phạm vi:

70 byte

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

Giả sử rằng góc của kim không cần phải là một số nguyên, mà chỉ là ngẫu nhiên đồng nhất:

59 byte

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

Giả sử rằng góc có thể là bất kỳ phân phối đồng đều:

52 byte

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

Trên đây là mô phỏng toán học chính xác về kim của Buffon. Tuy nhiên, tại thời điểm này tôi nghĩ rằng hầu hết mọi người sẽ đồng ý rằng đây thực sự không phải là câu hỏi yêu cầu.


Thực sự thúc đẩy nó

Chúng tôi chỉ có thể vứt bỏ một nửa các trường hợp thử nghiệm, bất cứ khi nào điểm cuối thứ hai ở bên trái của trường hợp đầu tiên (thay vì hoán đổi chúng):

47 byte

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

Lưu ý rằng các giá trị của tlkhông liên quan đến kết quả của thí nghiệm. Chúng ta chỉ có thể bỏ qua chúng (mặc nhiên cho rằng chúng bằng nhau):

28 byte

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

Rõ ràng là không cạnh tranh, nhưng bạn phải thừa nhận, nó có một sự thanh lịch nhất định với nó.


4

Python 2, 141 byte

cổng không biết xấu hổ của rtumbull, đã bỏ qua yvì hoàn toàn không cần thiết.

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)))

Vấn đề là duy nhất, pi đó đã được biết đến trong chương trình.

Đây là (golfable) với pi không xác định và không có chức năng lượng giác

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,ytrong gchỉ dành cho hướng.


Yêu cầu from random import randint;from math import cos,pi. Thất bại cho t < l, ví dụ 1000000,1000,70000.
primo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.