Công cụ ước tính Monte Carlo của Pi


25

Chúc mừng ngày Pi mọi người! Không có lý do nào cả, tôi đang cố gắng xây dựng một công cụ ước tính Pi của Monte Carlo càng ngắn càng tốt. Chúng ta có thể xây dựng một cái có thể phù hợp trong một tweet không?

Để làm rõ, những gì tôi có trong đầu là cách tiếp cận điển hình của việc vẽ các điểm ngẫu nhiên từ bình phương đơn vị và tính tỷ lệ nằm trong vòng tròn đơn vị. Số lượng mẫu có thể được mã hóa cứng hoặc không. Nếu bạn mã hóa chúng, bạn phải sử dụng ít nhất 1000 mẫu. Kết quả có thể được trả về hoặc in dưới dạng dấu phẩy động, điểm cố định hoặc số hữu tỷ.

Không có chức năng trig hoặc hằng số Pi, phải là một cách tiếp cận Monte Carlo.

Đây là mã golf, vì vậy bài nộp ngắn nhất (tính bằng byte) sẽ thắng.


2
chức năng trig được phép? Tôi đề nghị bạn rõ ràng cấm chúng.
Cấp sông St

((0..4e9).map{rand**2+rand**2<1}.to_s.sub(/./,"$1.")
John Dvorak

@JanDvorak Làm thế nào mà nó hoạt động được? Không phải là mapcung cấp cho bạn một mảng truefalse?
Martin Ender

@ MartinBüttner À, xin lỗi, xin lỗi. .filter{...}.sizenên làm việc, mặc dù.
John Dvorak

@JanDvorak Thật vậy. Điều đó thực sự gọn gàng :)
Martin Ender

Câu trả lời:


17

Mã máy 80386, 40 38 byte

Mã thập phân của mã:

60 33 db 51 0f c7 f0 f7 e0 52 0f c7 f0 f7 e0 58
03 d0 72 03 83 c3 04 e2 eb 53 db 04 24 58 db 04
24 58 de f9 61 c3

Cách lấy mã này (từ ngôn ngữ hợp ngữ):

    // ecx = n (number of iterations)
    pushad;
    xor ebx, ebx; // counter
    push ecx; // save n for later
myloop:
    rdrand eax; // make a random number x (range 0...2^32)
    mul eax; // calculate x^2 / 2^32
    push edx;
    rdrand eax; // make another random number y
    mul eax; // calculate y^2 / 2^32
    pop eax;
    add edx, eax; // calculate D = x^2+y^2 / 2^32 (range 0...2^33)
    jc skip; // skip the following if outside the circle
    add ebx, 4; // accumulate the result multiplied by 4
skip:
    loop myloop;
    push ebx; // convert the result
    fild dword ptr [esp]; // to floating-point
    pop eax;
    fild dword ptr [esp]; // convert n to floating-point
    pop eax;
    fdivp st(1), st; // divide

    popad;
    ret;

Đây là một hàm sử dụng fastcallquy ước gọi MS (số lần lặp được truyền trong thanh ghi ecx). Nó trả về kết quả trong stsổ đăng ký.

Những điều thú vị về mã này:

  • rdrand - chỉ cần 3 byte để tạo một số ngẫu nhiên!
  • Nó sử dụng số học số nguyên (không dấu) cho đến khi chia cuối cùng.
  • Việc so sánh khoảng cách bình phương ( D) với bán kính bình phương ( 2^32) được thực hiện tự động - cờ mang chứa kết quả.
  • Để nhân số đếm với 4, nó đếm các mẫu trong các bước của 4.

Nhận xét nên đọc "Tính x ^ 2% 2 ^ 32"
Cole Johnson

@ColeJohnson Không - số ngẫu nhiên nằm trong eax; các mullệnh bội nó bằng cách riêng của mình và puts phần cao trong edx; phần thấp trong eaxbị loại bỏ.
anatolyg

11

Matlab / Octave, 27 byte

Tôi biết đã có câu trả lời Matlab / Octave, nhưng tôi đã thử cách tiếp cận của riêng mình. Tôi đã sử dụng thực tế là tích phân 4/(1+x^2)giữa 0 và 1 là pi.

mean(4./(1+rand(1,1e5).^2))

Một thuật toán khác nhau luôn luôn là tuyệt vời! Ngoài ra, hiệu quả hơn!
anatolyg

7

R, 40 (hoặc 28 hoặc 24 bằng các phương pháp khác)

mean(4*replicate(1e5,sum(runif(2)^2)<1))

mean(4*sqrt(1-runif(1e7)^2))

mean(4/(1+runif(1e7)^2))

Con trăn 2, 56

Một Python khác, nếu numpy được cho phép, nhưng khá giống với Matlab / Octave:

import numpy;sum(sum(numpy.random.rand(2,8e5)**2)<1)/2e5

6

Mathicala , 42 40 39 byte (hoặc 31/29?)

Tôi đã có ba giải pháp tất cả ở 42 byte:

4Count[1~RandomReal~{#,2},p_/;Norm@p<1]/#&
4Tr@Ceiling[1-Norm/@1~RandomReal~{#,2}]/#&
4Tr@Round[1.5-Norm/@1~RandomReal~{#,2}]/#&

Chúng đều là các hàm chưa được đặt tên, lấy số lượng mẫu nvà trả về một giá trị gần đúng hợp lý. Đầu tiên tất cả chúng tạo ra ncác điểm trong ô vuông đơn vị trong góc phần tư dương. Sau đó, họ xác định số lượng các mẫu nằm trong vòng tròn đơn vị, và sau đó họ chia cho số lượng mẫu và nhân với 4. Sự khác biệt duy nhất là cách họ xác định số lượng sampples bên trong vòng tròn đơn vị:

  • Người đầu tiên sử dụng Countvới điều kiện đó Norm[p] < 1.
  • Cái thứ hai trừ đi định mức của từng điểm 1và sau đó làm tròn lên. Điều này biến các số bên trong vòng tròn đơn vị thành 1và những người bên ngoài 0. Sau đó tôi chỉ tổng hợp tất cả lên Tr.
  • Cái thứ ba về cơ bản giống nhau, nhưng trừ từ 1.5, vì vậy tôi có thể sử dụng Roundthay vì Ceiling.

Aaaaaand trong khi viết nó lên, tôi nhận ra rằng thực sự có một giải pháp ngắn hơn, nếu tôi chỉ trừ đi 2và sau đó sử dụng Floor:

4Tr@Floor[2-Norm/@1~RandomReal~{#,2}]/#&

hoặc lưu một byte khác bằng cách sử dụng các toán tử sàn hoặc trần Unicode:

4Tr@⌊2-Norm/@1~RandomReal~{#,2}⌋/#&
4Tr@⌈1-Norm/@1~RandomReal~{#,2}⌉/#&

Lưu ý rằng ba giải pháp dựa trên làm tròn cũng có thể được viết Meanthay vì Trvà không có /#, một lần nữa cho cùng một byte.


Nếu các cách tiếp cận dựa trên Monte Carlo khác là tốt (cụ thể, phương pháp mà Peter đã chọn), tôi có thể thực hiện 31 byte bằng cách ước tính tích phân hoặc 29 bằng cách sử dụng tích phân của , lần này được đưa ra dưới dạng số dấu phẩy động:√(1-x2)1/(1+x2)

4Mean@Sqrt[1-1~RandomReal~#^2]&
Mean[4/(1+1~RandomReal~#^2)]&

9
Bạn đã có ba giải pháp cho cuộc sống, vũ trụ và mọi thứ và bạn quyết định hủy hoại nó? Dị giáo.
xem


6

CJam, 27 23 22 hoặc 20 byte

4rd__{{1dmr}2*mhi-}*//

2 byte được lưu nhờ Runner112, 1 byte được lưu nhờ Sp3000

Nó lấy số lần lặp từ STDIN làm đầu vào.

Điều này là thẳng về phía trước như nó được. Đây là các bước chính liên quan:

  • Đọc đầu vào và chạy lặp đi lặp lại Monte Carlo nhiều lần
  • Trong mỗi lần lặp, lấy tổng bình phương của hai số float ngẫu nhiên từ 0 đến 1 và xem nó có nhỏ hơn 1 không
  • Lấy tỷ lệ số lần chúng tôi nhận được ít hơn 1 lần tổng số lần lặp và nhân nó với 4 lần để có PI

Mở rộng mã :

4rd                     "Put 4 on stack, read input and convert it to a double";
   __{            }*    "Take two copies, one of them determines the iteration"
                        "count for this code block";
      {1dmr}2*          "Generate 2 random doubles from 0 to 1 and put them on stack";
              mh        "Take hypot (sqrt(x^2 + y^2)) where x & y are the above two numbers";
                i       "Convert the hypot to 0 if its less than 1, 1 otherwise";
                 -      "Subtract it from the total sum of input (the first copy of input)";
                    //  "This is essentially taking the ratio of iterations where hypot";
                        "is less than 1 by total iterations and then multiplying by 4";

Dùng thử trực tuyến tại đây


Nếu giá trị trung bình của 1/(1+x^2)cũng được coi là Monte Carlo, thì điều này có thể được thực hiện trong 20 byte:

Urd:K{4Xdmr_*)/+}*K/

Hãy thử nó ở đây


2
Tôi cũng đã thử một câu trả lời của CJam và đã đạt được 2 byte theo số điểm của bạn. Nhưng mã của tôi xuất hiện rất giống với mã của bạn, tôi cảm thấy bẩn khi đăng nó dưới dạng một câu trả lời riêng biệt. Mọi thứ đều giống nhau ngoại trừ lựa chọn thay đổi và hai tối ưu hóa này: lấy một số ngẫu nhiên từ 0 đến 1 1dmrthay vì KmrK/và kiểm tra xem tổng bình phương có lớn hơn 1 hay ikhông 1>(tôi nghĩ rằng số này đặc biệt thông minh) .
Runer112

@ Runer112 Cảm ơn. các iBí quyết là thực sự gọn gàng! Và chết tiệt, thiếu tài liệu cho1dmr
Trình tối ưu hóa

5

Python 2, 77 75 byte

from random import*;r=random;a=0;exec"a+=r()**2+r()**2<1;"*4000;print a/1e3

Sử dụng 4000 mẫu để lưu byte với 1e3.


5
Bạn có thể có được một chút chính xác hơn mà không mất phí ...*8000;print a/2e3.
Logic Knight

5

Hàng hóa 64 cơ bản, 45 byte

1F┌I=1TO1E3:C=C-(R/(1)↑2+R/(1)↑2<1):N─:?C/250

Thay thế PETSCII: = SHIFT+E, /= SHIFT+N, =SHIFT+O

Tạo 1000 điểm trong góc phần tư thứ nhất; đối với mỗi, thêm tính trung thực của "x ^ 2 + y ^ 2 <1" vào số đếm đang chạy, sau đó chia số đếm cho 250 để có được pi. (Sự hiện diện của dấu trừ là vì trên C64, "true" = -1.)


Không gì (1)làm gì?
echristopherson

@echristopherson, bạn đang đọc sai nó. /không phải là biểu tượng phân chia, đó là ký tự được tạo bằng cách gõ SHIFT+Ntrên bàn phím Commodore 64. R/(1)là hình thức phím tắt cho RND(1), tức là. "Tạo số ngẫu nhiên trong khoảng từ 0 đến 1 bằng cách sử dụng hạt giống RNG hiện tại".
Đánh dấu

Oh bạn nói đúng! Tốt nhân vật đồ họa PETSCII.
echristopherson

5

J, 17 byte

Tính giá trị trung bình của 40000các giá trị mẫu của hàm 4*sqrt(1-sqr(x))trong phạm vi [0,1].

Trả 0 o.xlại một cách khéo léo sqrt(1-sqr(x)).

   1e4%~+/0 o.?4e4$0
3.14915

4

> <> (Cá) , 114 byte

:00[2>d1[   01v
1-:?!vr:@>x|  >r
c]~$~< |+!/$2*^.3
 .41~/?:-1r
|]:*!r$:*+! \
r+)*: *:*8 8/v?:-1
;n*4, $-{:~ /\r10.

Bây giờ,> <> không có trình tạo số ngẫu nhiên tích hợp. Tuy nhiên, nó có một chức năng gửi con trỏ theo một hướng ngẫu nhiên. Trình tạo số ngẫu nhiên trong mã của tôi:

______d1[   01v
1-:?!vr:@>x|  >r
_]~$~< |+!/$2*^__
 __________
___________ _
_____ ____ _______
_____ ____~ ______

Về cơ bản, nó tạo ra các bit ngẫu nhiên tạo nên một số nhị phân và sau đó chuyển đổi số nhị phân ngẫu nhiên đó thành số thập phân.

Phần còn lại chỉ là các điểm thông thường trong cách tiếp cận vuông.

Cách sử dụng: khi bạn chạy mã, bạn phải đảm bảo chuẩn bị trước ngăn xếp (-v trong trình thông dịch python) với số lượng mẫu, ví dụ

pi.fish -v 1000

trả lại

3.164

4

Matlab hoặc Octave 29 byte (nhờ flawr!)

mean(sum(rand(2,4e6).^2)<1)*4

(Tôi không chắc lắm nếu <1 có ổn không. Tôi đọc nó phải là <= 1. Nhưng xác suất để vẽ chính xác là bao nhiêu ...)

Matlab hoặc Octave 31 byte

sum(sum(rand(2,4e3).^2)<=1)/1e3

1
Ý tưởng rất hay! Bạn có thể lưu hai byte bổ sung với mean(sum(rand(2,4e6).^2)<1)*4.
flawr

4

Java, 108 byte

double π(){double π=0,x,i=0;for(;i++<4e5;)π+=(x=Math.random())*x+(x=Math.random())*x<1?1e-5:0;return π;}

Bốn nghìn lần lặp, thêm 0,001 mỗi lần điểm nằm trong vòng tròn đơn vị. Công cụ khá cơ bản.

Lưu ý: Có, tôi biết tôi có thể giảm bốn byte bằng cách thay đổi πthành một ký tự một byte. Tôi thích cách này.


Tại sao không lặp lại 9999?
Tối ưu hóa

1
@Optimizer Nó làm cho tổng số ngắn hơn. Thay vào đó, với 9999 lần lặp, tôi phải thêm một số chính xác hơn mỗi lần, điều này làm tôi mất các chữ số.
Geobits 14/03/2015

1
Bạn có thể lưu một byte khác và cải thiện độ chính xác bằng cách sử dụng "4e5" và "1e-5" cho các số.
Vilmantas Baranauskas

@VilmantasBaranauskas Cảm ơn! Tôi luôn quên về điều đó :) Thật hấp dẫn khi sử dụng 4e9 và 1e-9, nhưng điều đó khá mất thời gian ...
Geobits

Protip: khi chơi golf, bạn thực sự nên giảm byte, không tăng chúng một cách giả tạo
Lemon

3

Javascript: 62 byte

for(r=Math.random,t=c=8e4;t--;c-=r()**2+r()**2|0);alert(c/2e4)

Tôi đã sử dụng câu trả lời javascript (hiện đã xóa) trước đó và cạo 5 byte.


Bạn có thể liên kết đến câu trả lời của cfern để cung cấp tín dụng đúng cách.
Jonathan Frech

Câu trả lời của bạn dường như là một đoạn trích I / O không được phép . Vui lòng sửa hoặc xóa bài viết của bạn.
Jonathan Frech

Xin lỗi, tôi là người mới Tôi không biết cách đặt liên kết đến giải pháp trước đây hiện đã bị xóa. Về đoạn trích: Tôi hoàn toàn đồng ý, nhưng đó là mã của giải pháp javascript trước đó mà tôi cũng nghĩ rằng đó là lý do không hợp lệ. Tôi đã sửa đổi tôi thành một chương trình.
Guzman Tierno

Vâng; câu trả lời trước đó đã bị xóa vì nó không hợp lệ - Tôi đã thấy câu trả lời của bạn trước khi tôi đề nghị xóa, do đó, nhận xét. +1 để gửi câu trả lời hợp lệ; Chào mừng đến với PPCG!
Jonathan Frech

2

GolfScript (34 ký tự)

0{^3?^rand.*^.*+/+}2000:^*`1/('.'@

Bản demo trực tuyến

Điều này sử dụng điểm cố định vì GS không thực sự có điểm nổi. Nó hơi lạm dụng việc sử dụng điểm cố định, vì vậy nếu bạn muốn thay đổi số lần lặp, hãy đảm bảo rằng nó gấp hai lần công suất mười.

Tín dụng cho xnor cho phương pháp Monte Carlo cụ thể được sử dụng.


2

Python 2, 90 85 81 byte

from random import*;r=random;print sum(4.for i in[0]*9**7if r()**2+r()**2<1)/9**7

trả về 3.14120037157chẳng hạn. Số lượng mẫu là 4782969 (9 ^ 7). Bạn có thể có được số pi tốt hơn với 9 ^ 9 nhưng bạn sẽ phải kiên nhẫn.


Bạn có thể lưu 3 bằng cách thay thế range(9**7)bằng [0]*9**7hoặc một cái gì đó, vì bạn không sử dụng i. Và danh sách không quá dài để chạy vào các vấn đề bộ nhớ.
Sp3000

Cảm ơn. Tôi muốn thoát khỏi range()nhưng tôi đã hoàn toàn quên đi mánh khóe đó.
Logic Knight

Tôi có một cảm giác [0]9**7không hợp lệ cú pháp.
xem

Bạn đúng rồi. Tôi đã gắn lại dấu hoa thị bị mất (nó nằm dưới bàn của tôi).
Logic Knight

2

Ruby, 39 byte

p (1..8e5).count{rand**2+rand**2<1}/2e5

Một trong những điểm nổi bật là cái này có thể sử dụng 8e5ký hiệu, làm cho nó có thể mở rộng lên tới ~ 8e9 mẫu trong cùng một số byte chương trình.



1

Scala, 87 77 66 byte

def s=math.pow(math.random,2);Seq.fill(1000)(s+s).count(_<1)/250d

Nếu bạn thay thế 1000với 8000250dvới 2e4cả hai bạn tiết kiệm một byte và tăng số lượng mẫu theo hệ số 8.
Dave Swartz

1

Bash thuần túy, 65 byte

for((;i++<$1*4;a+=RANDOM**2+RANDOM**2<32767**2));{ :;}
echo $a/$1

Lấy một tham số dòng lệnh duy nhất được nhân với 4 để đưa ra số lượng mẫu. Số học Bash là chỉ số nguyên, vì vậy một hợp lý là đầu ra. Điều này có thể được dẫn đến bc -lphân chia cuối cùng:

$ ./montepi.sh 10000
31477/10000
$ ./montepi.sh 10000|bc -l
3.13410000000000000000
$ 

1

Joe , 20 19 byte

Lưu ý: câu trả lời này không cạnh tranh, vì phiên bản 0.1.2, có thêm tính ngẫu nhiên, đã được phát hành sau thử thách này.

Hàm được đặt tên F:

:%$,(4*/+1>/+*,?2~;

Hàm không tên:

%$,(4*/+1>/+*,?2~;)

Cả hai đều lấy số lượng mẫu làm đối số và trả về kết quả. Họ làm việc như thế nào?

%$,(4*/+1>/+*,?2~;)
   (4*/+1>/+*,?2~;) defines a chain, where functions are called right-to-left
               2~;  appends 2 to the argument, giving [x, 2]
              ?     create a table of random values from 0 to 1 with that shape
            *,      take square of every value
          /+         sum rows, giving a list of (x**2+y**2) values
        1>           check if a value is less than 1, per atom
      /+             sum the results
    4*               multiply by four
%$,                  divide the result by the original parameter

Ví dụ chạy:

   :%$,(4*/+1>/+*,?2~;
   F400000
3.14154
   F400000
3.14302

1

dc, 59 ký tự (khoảng trắng bị bỏ qua)

[? 2^ ? 2^ + 1>i]su
[lx 1+ sx]si
[lu x lm 1+ d sm ln>z]sz

5k
?sn
lzx
lx ln / 4* p
q

Tôi đã thử nghiệm điều này trên Plan 9 và OpenBSD, vì vậy tôi tưởng tượng nó sẽ hoạt động trên Linux (GNU?) dc.

Giải thích theo dòng:

  1. Lưu trữ mã để [đọc và vuông hai phao; thực hiện thanh ghi inếu 1 lớn hơn tổng bình phương của chúng] trong thanh ghi u.
  2. Lưu mã vào [đăng ký tăng thêm x1] trong đăng ký i.
  3. Lưu mã vào [thanh ghi thực thi u, thanh ghi tăng m, rồi thực hiện thanh ghi znếu thanh ghi mlớn hơn thanh ghi n] trong thanh ghi z.
  4. Đặt tỷ lệ thành 5 điểm thập phân.

  5. Đọc số lượng điểm cần lấy mẫu từ dòng đầu tiên.
  6. Thực hiện đăng ký z.
  7. Chia thanh ghi x(số lần truy cập) cho thanh ghi n(số điểm), nhân kết quả với 4 và in.
  8. Thoát

Tuy nhiên, tôi đã lừa dối:

Chương trình cần một nguồn cung cấp phao ngẫu nhiên trong khoảng từ 0 đến 1.

/* frand.c */
#include <u.h>
#include <libc.h>

void
main(void)
{
    srand(time(0));

    for(;;)
        print("%f\n", frand());
}

Sử dụng:

#!/bin/rc
# runpi <number of samples>

{ echo $1; frand } | dc pi.dc

Chạy thử nghiệm:

% runpi 10000
3.14840

Bây giờ với ít gian lận hơn (100 byte)

Ai đó đã chỉ ra rằng tôi có thể bao gồm một prng đơn giản.
http://en.wikipedia.org/wiki/RANDU

[lrx2^lrx2^+1>i]su[lx1+sx]si[luxlm1+dsmln>z]sz[0kls65539*2 31^%dsslkk2 31^/]sr?sn5dksk1sslzxlxlm/4*p

Bị đánh cắp

[
Registers:
u - routine : execute i if sum of squares less than 1
i - routine : increment register x
z - routine : iterator - execute u while n > m++
r - routine : RANDU PRNG
m - variable: number of samples
x - variable: number of samples inside circle
s - variable: seed for r
k - variable: scale for division
n - variable: number of iterations (user input)
]c
[lrx 2^ lrx 2^ + 1>i]su
[lx 1+ sx]si
[lu x lm 1+ d sm ln>z]sz
[0k ls 65539 * 2 31^ % d ss lkk 2 31 ^ /]sr
? sn
5dksk
1 ss
lzx
lx lm / 4*
p

Chạy thử nghiệm:

$ echo 10000 | dc pigolf.dc
3.13640

1

Bình thường, 19

c*4sm<sm^OQ2 2*QQQQ

Đưa ra số lần lặp mong muốn làm đầu vào.

Trình diễn

Vì Pyth không có chức năng "Số nổi ngẫu nhiên", tôi phải ứng biến. Chương trình chọn hai số nguyên dương ngẫu nhiên nhỏ hơn đầu vào, bình phương, tổng và so với bình phương đầu vào. Điều này thực hiện một số lần bằng với đầu vào, sau đó kết quả được nhân với 4 và chia cho đầu vào.

Trong các tin tức liên quan, tôi sẽ sớm thêm một hoạt động số dấu phẩy động ngẫu nhiên vào Pyth. Chương trình này không sử dụng tính năng đó, tuy nhiên.


Nếu chúng tôi giải thích "Kết quả có thể được trả về hoặc in dưới dạng dấu phẩy động, điểm cố định hoặc số hữu tỷ." một cách tự do, sau đó in tử số và mẫu số của phân số kết quả là đủ. Trong trường hợp đó:

Bình thường, 18

*4sm<sm^OQ2 2*QQQQ

Đây là một chương trình giống hệt nhau, với thao tác phân chia dấu phẩy động ( c) được loại bỏ.


1

Julia, 37 byte

4mean(1-floor(sum(rand(4^8,2).^2,2)))

Số lượng mẫu là 65536 (= 4 ^ 8).

Một biến thể dài hơn: một hàm có số lượng mẫu slà đối số duy nhất:

s->4mean(1-floor(sum(rand(s,2).^2,2)))

1

C, 130 byte

#include<stdlib.h>f(){double x,y,c=0;for(int i=0;i<8e6;++i)x=rand(),y=rand(),c+=x*x+y*y<1.0*RAND_MAX*RAND_MAX;printf("%f",c/2e6);}

Ung dung:

#include <stdlib.h>
f(){
 double x,y,c=0;
 for(int i=0; i<8e6; ++i) x=rand(), y=rand(), c+=x*x+y*y<1.0*RAND_MAX*RAND_MAX;
 printf("%f",c/2e6);
}

tất nhiên, bạn vẫn có thể nên đăng phiên bản mà không có khoảng trắng (giữ phiên bản hiện tại với tiêu đề "vô dụng / với khoảng trắng" hoặc một cái gì đó)
Lemon

@DeststallibleWateriwi đã hoàn thành!
Karl Napf

Giải pháp không hoạt động trong GCC mà không có dòng mới trước đó f(). Trình biên dịch nào bạn đã sử dụng? Xem tio.run/##Pc49C4JAHIDx3U9xGMG9ZdYgwWkgtNbQ1BZ6L/UHO8M07hA/ phe
eush77


1

Trên thực tế , 14 byte (không cạnh tranh)

`G²G²+1>`nkæ4*

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

Giải pháp này không cạnh tranh vì ngôn ngữ sau ngày thử thách. Số lượng mẫu được đưa ra làm đầu vào (thay vì mã hóa cứng).

Giải trình:

`G²G²+1>`nkæ4*
`G²G²+1>`n      do the following N times:
 G²G²+            rand()**2 + rand()**2
      1>          is 1 greater?
          kæ    mean of results
            4*  multiply by 4

2
Tại sao các downvote?
Lemon phá hủy

1

Vợt 63 byte

Sử dụng phương thức trả lời ngôn ngữ R của @Matt:

(/(for/sum((i n))(define a(/(random 11)10))(/ 4(+ 1(* a a))))n)

Ung dung:

(define(f n)
   (/
    (for/sum ((i n))
      (define a (/(random 11)10))
      (/ 4(+ 1(* a a))))
    n))

Kiểm tra:

(f 10000)

Đầu ra (phân số):

3 31491308966059784/243801776017028125

Là số thập phân:

(exact->inexact(f 10000))

3.13583200307849

1

Fortran (GFortran) , 84 83 byte

CALL SRAND(0)
DO I=1,4E3
X=RAND()
Y=RAND()
IF(X*X+Y*Y<1)A=A+1E-3
ENDDO
PRINT*,A
END

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

Mã này được viết rất xấu. Sẽ không thành công nếu gfortran quyết định khởi tạo biến Avới giá trị khác là 0 (xảy ra 50% tổng hợp, xấp xỉ) và, nếu Ađược khởi tạo là 0, nó sẽ luôn tạo cùng một chuỗi ngẫu nhiên cho hạt giống đã cho. Sau đó, giá trị tương tự cho Pi được in luôn.

Đây là một chương trình tốt hơn nhiều:

Fortran (GFortran) , 100 99 byte

A=0
DO I=1,4E3
CALL RANDOM_NUMBER(X)
CALL RANDOM_NUMBER(Y)
IF(X*X+Y*Y<1)A=A+1E-3
ENDDO
PRINT*,A
END

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

(Một byte được lưu trong mỗi phiên bản; cảm ơn Penguino).


1
Trong mỗi phiên bản, bạn có thể lưu một byte bằng cách thay đổi 'DO I = 1,1E3' thành 'DO I = 1,4E3', thay đổi 'A = A + 1' thành 'A = A + 1E-3' và thay đổi ' IN *, A / 250 'đến' IN *, A '
Penguino

Vâng, bạn chắc chắn! Cảm ơn lời đề nghị!
rafa11111

1

Japt , 26 hoặc 18 byte

o r_+ÂMhMr p +Mr p <1Ã*4/U

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

Tương tự như câu trả lời của Trình tối ưu hóa , chủ yếu chỉ là cố gắng học Japt.
Lấy số lần lặp để chạy như là đầu vào ẩn U.

o                           Take the input and turn it into a range [0, U),
                            essentially a cheap way to get a large array.
  r_                        Reduce it with the default initial value of 0.
    +Â                      On each iteration, add one if
      MhMr p +Mr p          the hypotenuse of a random [0,1)x[0,1) right triangle
                   <1       is smaller than one.
                     Ã*4/U  Multiply the whole result by four and divide by input.

Nếu 1/(1+x^2)được cho phép (thay vì hai randoms riêng biệt), thì chúng ta có thể đạt được 18 byte với cùng logic.

o r_Ä/(1+Mr pÃ*4/U

1
Bạn có thể lưu một vài byte bằng cách Mhtính toán cạnh huyền thay vì tự mình làm điều đó ;-) Ngoài ra, bạn có thể sử dụng xđể lấy tổng của một mảng, thay vì giảm bằng cách thêm:o x@MhMr Mr)<1Ã*4/U
ETHproductions

@ETHproductions Neat, tôi không biết bạn có thể sử dụng Mhnhư vậy, cảm ơn! Câu trả lời hai ngẫu nhiên của bạn ngắn gần bằng câu trả lời của tôi chỉ với một lần ngẫu nhiên, điều đó thật tuyệt. Tôi sẽ ghi xnhớ, tôi có xu hướng sử dụng giảm rất nhiều khi cố gắng chơi golf, vì vậy điều này sẽ rất hữu ích.
Nit

1

F #, 149 byte

open System;
let r=new Random()
let q()=
 let b=r.NextDouble()
 b*b
let m(s:float)=(s-Seq.sumBy(fun x->q()+q()|>Math.Sqrt|>Math.Floor)[1.0..s])*4.0/s

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

Theo như tôi có thể nhận ra, để thực hiện loại tổng chạy này trong F #, nó ngắn hơn để tạo ra một dãy số và sử dụng Seq.sumByphương thức hơn là sử dụng một for..to..dokhối.

Mã này làm gì mà nó tạo ra một tập hợp các số dấu phẩy động từ 1 đến s, thực hiện chức năng fun x->...cho số lượng phần tử trong bộ sưu tập và tính tổng kết quả. Có scác yếu tố trong bộ sưu tập, do đó, thử nghiệm ngẫu nhiên được thực hiện slần. Các số thực tế trong bộ sưu tập bị bỏ qua ( fun x->, nhưng xkhông được sử dụng).

Điều đó cũng có nghĩa là ứng dụng trước tiên phải tạo và điền vào mảng, sau đó lặp lại trên nó. Vì vậy, nó có thể chậm gấp đôi for..to..dovòng lặp. Và với việc sử dụng bộ nhớ tạo mảng nằm trong vùng O (f ** k)!

Đối với bản thân bài kiểm tra thực tế, thay vì sử dụng một if then elsecâu lệnh, nó sẽ tính khoảng cách ( q()+q()|>Math.Sqrt) và làm tròn nó xuống Math.Floor. Nếu khoảng cách nằm trong vòng tròn, nó sẽ được làm tròn xuống 0. Nếu khoảng cách nằm ngoài vòng tròn, nó sẽ được làm tròn xuống 1. Seq.sumByPhương thức sau đó sẽ tính tổng các kết quả này.

Lưu ý rằng những gì Seq.sumByđã có tổng không phải là các điểm bên trong vòng tròn, mà là các điểm bên ngoài nó. Vì vậy, đối với kết quả phải mất s(kích thước mẫu của chúng tôi) và trừ tổng số từ nó.

Nó cũng xuất hiện rằng lấy kích thước mẫu làm tham số ngắn hơn giá trị mã hóa cứng. Vì vậy, tôi đang lừa dối một chút ...


1

Haskell, 116 114 110 96 byte

d=8^9
g[a,b]=sum[4|a*a+b*b<d*d]
p n=(sum.take(floor n)$g<$>iterate((\x->mod(9*x+1)d)<$>)[0,6])/n

Bởi vì việc xử lý import System.Random; r=randoms(mkStdGen 2)sẽ mất quá nhiều byte quý giá, tôi tạo ra một danh sách vô số các số ngẫu nhiên với trình tạo đồng quy tuyến tính mà một số người cho rằng gần như mạnh về mặt mật mã x↦x*9+1 mod 8^9:, theo Định lý Hull-Dobell có toàn bộ thời gian 8^9.

gmang lại 4nếu điểm số ngẫu nhiên nằm trong vòng tròn cho các cặp số ngẫu nhiên [0..8^9-1]vì điều này loại bỏ phép nhân trong công thức được sử dụng.

Sử dụng:

> p 100000
3.14208

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


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.