ตัวประมาณค่า Monte Carlo ของ Pi


25

สวัสดีวัน Pi ทุกคน! ไม่มีเหตุผลเลยฉันพยายามสร้างตัวประมาณค่า Monte Carlo ของ Pi ที่สั้นที่สุด เราสร้างสิ่งที่สามารถพอดีกับทวีตได้หรือไม่?

สิ่งที่ฉันมีอยู่ในใจคือวิธีการทั่วไปในการวาดจุดสุ่มจากตารางหน่วยและคำนวณอัตราส่วนที่อยู่ภายในวงกลมหน่วย จำนวนตัวอย่างสามารถกำหนดรหัสยากหรือไม่ หากคุณ hardcode พวกเขาคุณต้องใช้อย่างน้อย 1,000 ตัวอย่าง ผลลัพธ์อาจถูกส่งคืนหรือพิมพ์เป็นจุดลอยตัวจุดคงที่หรือจำนวนตรรกยะ

ไม่มีฟังก์ชันตรีโกณฯ หรือค่าคงที่ Pi ต้องเป็นวิธีมอนติคาร์โล

นี่คือรหัสกอล์ฟดังนั้นการส่งที่สั้นที่สุด (เป็นไบต์) จะชนะ


2
ฟังก์ชั่นตรีโกณมิติอนุญาตหรือไม่ ฉันขอแนะนำให้คุณแบนพวกเขาอย่างชัดเจน
เลเวลริเวอร์

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

@JanDvorak มันควรจะทำงานอย่างไร ไม่mapให้คุณอาร์เรย์trueและfalse?
Martin Ender

@ MartinBüttnerอ้าโอ้ขอโทษ .filter{...}.sizeควรทำงานแม้ว่า
John Dvorak

@JanDvorak แน่นอน นั่นมันเรียบร้อยมาก :)
Martin Ender

คำตอบ:


17

รหัสเครื่อง 80386, 40 38 ไบต์

Hexdump ของรหัส:

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

วิธีรับรหัสนี้ (จากภาษาแอสเซมบลี):

    // 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;

นี่คือฟังก์ชั่นที่ใช้fastcallการประชุมแบบMS (จำนวนการทำซ้ำจะถูกส่งผ่านในการลงทะเบียนecx) มันส่งคืนผลลัพธ์ในการstลงทะเบียน

สิ่งที่สนุกเกี่ยวกับรหัสนี้:

  • rdrand - เพียง 3 ไบต์เพื่อสร้างตัวเลขสุ่ม!
  • มันใช้เลขจำนวนเต็ม (ไม่ได้ลงนาม) จนถึงการหารสุดท้าย
  • การเปรียบเทียบระยะห่างกำลังสอง ( D) กับรัศมีกำลังสอง ( 2^32) จะถูกดำเนินการโดยอัตโนมัติ - ธงยกมีผลลัพธ์
  • หากต้องการคูณจำนวนด้วย 4 จะนับตัวอย่างเป็นขั้นตอนที่ 4

ความคิดเห็นควรอ่าน "คำนวณ x ^ 2% 2 ^ 32"
โคลจอห์นสัน

@ColeJohnson - ไม่มีตัวเลขสุ่มอยู่ในeax; mulหลายคำสั่งมันด้วยตัวเองและทำให้ส่วนสูงedx; ส่วนที่ต่ำeaxจะถูกยกเลิก
Anatolyg

11

Matlab / Octave ขนาด 27 ไบต์

ฉันรู้ว่ามีคำตอบ Matlab / Octave อยู่แล้ว แต่ฉันลองใช้แนวทางของตัวเอง ฉันใช้ความจริงที่ว่าอินทิกรัล4/(1+x^2)ระหว่าง 0 และ 1 คือไพ

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

อัลกอริทึมที่แตกต่างนั้นยอดเยี่ยมเสมอ! นอกจากนี้ยังมีประสิทธิภาพมากขึ้น!
Anatolyg

7

R, 40 (หรือ 28 หรือ 24 โดยใช้วิธีอื่น)

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

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

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

Python 2, 56

งูหลามตัวอื่นถ้าอนุญาตให้มีจำนวนมาก แต่ค่อนข้างคล้ายกับ Matlab / Octave:

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

6

Mathematica, 42 40 39 ไบต์ (หรือ 31/29?)

ฉันมีสามโซลูชั่นทั้งหมดที่ 42 ไบต์:

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

พวกมันเป็นฟังก์ชั่นที่ไม่มีชื่อที่รับจำนวนตัวอย่างnและส่งกลับค่าประมาณ ational ก่อนอื่นพวกเขาสร้างnคะแนนในหน่วยสี่เหลี่ยมในจตุภาคบวก 4แล้วพวกเขาก็กำหนดจำนวนของกลุ่มตัวอย่างผู้ที่อยู่ภายในวงกลมหน่วยและแล้วพวกเขาก็หารด้วยจำนวนตัวอย่างและคูณด้วย ความแตกต่างเพียงอย่างเดียวคือวิธีที่พวกเขากำหนดจำนวนตัวอย่างภายในวงกลมหน่วย:

  • คนแรกที่ใช้โดยมีเงื่อนไขว่าCountNorm[p] < 1
  • หนึ่งที่สองลบบรรทัดฐานของแต่ละจุดจาก1นั้นปัดขึ้น นี้จะเปลี่ยนหมายเลขภายในวงกลมหน่วยที่และภายนอกเหล่านั้นไป1 หลังจากนั้นผมก็เพียงแค่รวมพวกเขาทั้งหมดขึ้นกับ0Tr
  • หนึ่งในสามจะเป็นหลักเดียวกัน แต่หักจาก1.5ดังนั้นฉันสามารถใช้แทนRoundCeiling

เอาเป็นว่าในขณะที่เขียนบทความนี้เกิดขึ้นกับฉันว่ามีวิธีแก้ปัญหาที่สั้นกว่าถ้าฉันลบจาก2นั้นก็ใช้Floor:

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

หรือบันทึกไบต์อื่นโดยใช้ Unicode floor หรือเพดานโอเปอเรเตอร์:

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

โปรดทราบว่าโซลูชันที่ใช้การปัดเศษสามตัวยังสามารถเขียนด้วยMeanแทนที่จะเป็นTrและไม่มี/#อีกครั้งสำหรับไบต์เดียวกัน


หากวิธีการพื้นฐานอื่น ๆ ของ Monte Carlo นั้นดี (โดยเฉพาะอย่างยิ่งปีเตอร์ที่ได้เลือกไว้) ฉันสามารถทำได้ 31 ไบต์โดยประมาณอินทิกรัลของหรือ 29 โดยใช้อินทิกรัลของเวลานี้ให้เป็นจำนวนจุดลอยตัว:√(1-x2)1/(1+x2)

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

9
คุณมีวิธีแก้ปัญหาสามประการสำหรับชีวิตจักรวาลและทุกสิ่งและคุณตัดสินใจที่จะทำลายมันใช่ไหม บาป.
seequ


6

CJam, 27 23 22 หรือ 20 ไบต์

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

บันทึก 2 ไบต์ด้วย Runner112, ขอบคุณ 1 ไบต์ที่บันทึกไว้ด้วย Sp3000

ใช้การนับซ้ำจาก STDIN เป็นอินพุต

ตรงนี้เป็นไปตามที่ได้รับ นี่คือขั้นตอนสำคัญที่เกี่ยวข้อง:

  • อ่านอินพุตและเรียกใช้การทำซ้ำ Monte Carlo ที่หลายต่อหลายครั้ง
  • ในการวนซ้ำแต่ละครั้งให้หาผลบวกของกำลังสองของการสุ่มลอยจาก 0 ถึง 1 และดูว่ามันน้อยกว่า 1 หรือไม่
  • รับอัตราส่วนของจำนวนครั้งที่เราได้น้อยกว่า 1 โดยการวนซ้ำทั้งหมดและคูณด้วย 4 เพื่อรับ PI

การขยายรหัส :

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";

ลองออนไลน์ได้ที่นี่


หากค่าเฉลี่ยของ1/(1+x^2)ยังถือเป็นมอนติคาร์โลก็สามารถทำได้ใน 20 ไบต์:

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

ลองที่นี่


2
ฉันลองใช้คำตอบ CJam เช่นกันและจัดการให้ได้ 2 ไบต์ภายใต้คะแนนของคุณ แต่รหัสของฉันก็ออกมาคล้าย ๆ กับคุณฉันรู้สึกสกปรกที่โพสต์มันเป็นคำตอบที่แยกจากกัน ทุกอย่างเหมือนกันยกเว้นสำหรับตัวเลือกตัวแปรและการเพิ่มประสิทธิภาพสองอย่างนี้: รับตัวเลขสุ่มจาก 0 ถึง 1 ด้วย1dmrแทนที่จะเป็นKmrK/และตรวจสอบว่าผลรวมของช่องสี่เหลี่ยมมากกว่า 1 ด้วยiแทนที่จะเป็น1>(ฉันคิดว่าอันนี้ฉลาดกว่า) .
Runer112

@ Runer112 ขอบคุณ iเคล็ดลับคือประณีตจริงๆ! และการขาดเอกสารสำหรับ1dmr
เครื่องมือเพิ่มประสิทธิภาพ

5

Python 2, 77 75 ไบต์

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

ใช้ 4000 1e3ตัวอย่างที่จะบันทึกไบต์ด้วย


5
คุณสามารถได้รับความถูกต้องเล็ก ๆ น้อย ๆ ...*8000;print a/2e3ที่ไม่มีค่าใช้จ่ายด้วย
Logic Knight

5

Commodore 64 Basic, 45 bytes

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

การแทนที่ PETSCII: = SHIFT+E, /= SHIFT+N, =SHIFT+O

สร้าง 1,000 คะแนนในจตุภาคแรก สำหรับแต่ละเพิ่ม truthness ของ "x ^ 2 + Y ^ 2 <1" ไปนับทำงานแล้วแบ่งนับ 250 piที่จะได้รับ (การปรากฏตัวของเครื่องหมายลบเป็นเพราะใน C64, "true" = -1.)


อะไร(1)ทำอย่างไร
echristopherson

@echristopherson คุณกำลังอ่านผิด /ไม่ใช่สัญลักษณ์หารมันเป็นตัวละครที่สร้างขึ้นโดยการพิมพ์SHIFT+Nบนแป้นพิมพ์ Commodore 64 R/(1)เป็นรูปแบบทางลัดสำหรับRND(1)เช่น "สร้างตัวเลขสุ่มระหว่าง 0 ถึง 1 โดยใช้เมล็ด RNG ปัจจุบัน"
Mark

โอ้คุณพูดถูก! ตัวอักษรกราฟิก PETSCII เก่าดี
echristopherson

5

J, 17 ไบต์

คำนวณค่าเฉลี่ยของ40000ค่าตัวอย่างของการทำงานในช่วง4*sqrt(1-sqr(x))[0,1]

คล่องแคล่วผลตอบแทน0 o.xsqrt(1-sqr(x))

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

4

> <> (ปลา) , 114 ไบต์

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

ตอนนี้> <> ไม่มีตัวสร้างตัวเลขสุ่มในตัว อย่างไรก็ตามมันมีฟังก์ชั่นที่ส่งตัวชี้ไปในทิศทางที่สุ่ม ตัวสร้างตัวเลขสุ่มในรหัสของฉัน:

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

โดยทั่วไปจะสร้างบิตสุ่มที่ประกอบเป็นเลขฐานสองจากนั้นแปลงเลขฐานสองแบบสุ่มนั้นเป็นทศนิยม

ส่วนที่เหลือเป็นเพียงจุดปกติในแนวทางสี่เหลี่ยม

การใช้งาน: เมื่อคุณเรียกใช้รหัสคุณต้องตรวจสอบให้แน่ใจว่าการเติมสแต็ก (-v ในตัวแปลภาษาไพ ธ อน) กับจำนวนตัวอย่างเช่น

pi.fish -v 1000

ผลตอบแทน

3.164

4

Matlab หรือ 29 ไบต์คู่ (ขอบคุณข้อบกพร่อง!)

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

(ฉันไม่แน่ใจว่า <1 ใช้ได้หรือไม่ฉันอ่านมันควรเป็น <= 1 แต่ความน่าจะเป็นที่จะวาด 1 ...

Matlab หรือ Octave 31 bytes

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

1
เป็นความคิดที่ดีมาก! mean(sum(rand(2,4e6).^2)<1)*4คุณสามารถประหยัดไบต์ที่สองเพิ่มเติมกับ
ข้อบกพร่อง

4

Java, 108 ไบต์

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

การทำซ้ำสี่พันครั้งเพิ่ม 0.001 ในแต่ละครั้งที่จุดอยู่ในวงกลม สิ่งพื้นฐานที่สวย

หมายเหตุ:ใช่ฉันรู้ว่าฉันสามารถแยกสี่ไบต์ได้ด้วยการเปลี่ยนπเป็นอักขระไบต์เดียว ฉันชอบวิธีนี้



1
@Optimizer มันทำให้ผลรวมสั้นลง สำหรับการวนซ้ำ 9999 ครั้งฉันต้องเพิ่มจำนวนที่แม่นยำยิ่งขึ้นในแต่ละครั้งแทน
Geobits

1
คุณสามารถบันทึกไบต์อื่นและปรับปรุงความแม่นยำโดยใช้ "4e5" และ "1e-5" สำหรับตัวเลข
Vilmantas Baranauskas

@VilmantasBaranauskas ขอบคุณ! ฉันมักจะลืมเรื่องนี้ :) มันเป็นการดึงดูดให้ใช้ 4e9 และ 1e-9 แทน แต่มันใช้เวลา
ซักพัก

Protip: เมื่อเล่นกอล์ฟคุณควรลดจำนวนไบต์ลง แต่ไม่เพิ่มจำนวนเทียม
Lemon ที่สามารถทำลายได้

3

Javascript: 62 Bytes

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

ฉันใช้ javascript ก่อนหน้านี้ (ตอนนี้ถูกลบ) แล้วโกน 5 ไบต์


คุณสามารถลิงก์ไปยังคำตอบของ cfernเพื่อให้เครดิตได้อย่างถูกต้อง
Jonathan Frech

คำตอบของคุณดูเหมือนจะเป็นเศษเล็กเศษน้อยซึ่งเป็นไม่ได้รับอนุญาต I / O โปรดแก้ไขหรือลบโพสต์ของคุณ
Jonathan Frech

ขออภัยฉันใหม่ฉันไม่รู้ว่าจะใส่ลิงก์ไปยังโซลูชันก่อนหน้าซึ่งปรากฏขึ้นในขณะนี้ซึ่งถูกลบไปแล้ว เกี่ยวกับตัวอย่าง: ฉันเห็นด้วยอย่างสมบูรณ์ แต่นั่นเป็นรหัสของโซลูชันจาวาสคริปต์ก่อนหน้าซึ่งฉันคิดว่าเหตุผลนั้นไม่ถูกต้อง ฉันดัดแปลงของฉันให้เป็นโปรแกรม
Guzman Tierno

ใช่; คำตอบก่อนหน้านี้ถูกลบเนื่องจากมันไม่ถูกต้อง - ฉันเห็นคำตอบของคุณก่อนที่ฉันจะแนะนำให้ลบดังนั้นความคิดเห็น +1 สำหรับการส่งคำตอบที่ถูกต้อง; ยินดีต้อนรับสู่ PPCG!
Jonathan Frech

2

GolfScript (34 ตัวอักษร)

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

การสาธิตออนไลน์

สิ่งนี้ใช้จุดตายตัวเนื่องจาก GS ไม่มีจุดลอยตัวจริงๆ มันเป็นการละเมิดการใช้จุดคงที่เล็กน้อยดังนั้นหากคุณต้องการเปลี่ยนจำนวนการทำซ้ำตรวจสอบให้แน่ใจว่ามันเป็นสองเท่าของกำลังสิบ

ขอมอบเครดิตให้แก่xnorสำหรับวิธีการมอนติคาร์โลโดยเฉพาะ


2

Python 2, 90 85 81 ไบต์

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

ผลตอบแทน3.14120037157เช่น จำนวนตัวอย่างคือ 4782969 (9 ^ 7) คุณจะได้รับ Pi ที่ดีขึ้นด้วย 9 ^ 9 แต่คุณจะต้องอดทน


คุณสามารถบันทึก 3 โดยการแทนที่range(9**7)ด้วยหรือบางสิ่งบางอย่างเนื่องจากคุณไม่ได้ใช้[0]*9**7 iและรายการไม่นานเกินไปที่จะพบปัญหาหน่วยความจำ
Sp3000

ขอบคุณ ฉันต้องการกำจัดrange()แต่ฉันลืมเคล็ดลับนั้นไปหมดแล้ว
Logic Knight

ฉันรู้สึกว่า[0]9**7มันไม่ถูกต้อง
seequ

คุณพูดถูก ฉันแนบเครื่องหมายดอกจันที่สูญหายไปอีกครั้ง (มันอยู่ใต้โต๊ะของฉัน)
Logic Knight

2

Ruby, 39 ไบต์

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

หนึ่งในไฮไลท์คือหนึ่งในนี้สามารถใช้รูปแบบ8e5ซึ่งทำให้มันขยายได้ถึง ~ 8e9 ตัวอย่างในจำนวนไบต์โปรแกรมเดียวกัน



1

สกาลา, 87 77 66 ไบต์

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

หากคุณแทนที่1000ด้วย8000และ250dด้วย2e4คุณบันทึกทั้งไบต์และเพิ่มจำนวนตัวอย่างด้วยปัจจัย 8
เดฟ Swartz

1

Pure Bash ขนาด 65 ไบต์

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

รับพารามิเตอร์บรรทัดคำสั่งเดียวซึ่งคูณด้วย 4 เพื่อให้จำนวนตัวอย่าง Bash arithmetic เป็นจำนวนเต็มเท่านั้นดังนั้น rational คือเอาต์พุต สิ่งนี้อาจถูกส่งไปยังbc -lสำหรับส่วนสุดท้าย:

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

1

โจ , 20 19 ไบต์

หมายเหตุ: คำตอบนี้ไม่ใช่การแข่งขันเนื่องจากเวอร์ชั่น 0.1.2 ซึ่งเพิ่มการสุ่มได้รับการปล่อยตัวหลังจากการท้าทายนี้

ฟังก์ชันที่มีชื่อ F:

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

ฟังก์ชั่นไม่มีชื่อ:

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

ทั้งสองนี้จะนับจำนวนตัวอย่างเป็นอาร์กิวเมนต์และส่งคืนผลลัพธ์ พวกเขาทำงานอย่างไร

%$,(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

ตัวอย่างการทำงาน:

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

1

dc, 59 ตัวอักษร (ช่องว่างถูกละเว้น)

[? 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

ผมทดสอบนี้ในแผน 9 และ OpenBSD ดังนั้นฉันคิดว่ามันจะทำงานบนลินุกซ์ dc(GNU?)

คำอธิบายตามบรรทัด:

  1. รหัสร้านค้าเพื่อ [อ่านและตารางสองลอย; ดำเนินการลงทะเบียนiถ้า 1 เป็นมากกว่าผลรวมของสี่เหลี่ยมของพวกเขา] uในการลงทะเบียน
  2. รหัสร้านค้าที่ [ลงทะเบียนเพิ่มขึ้นxโดย 1] iในการลงทะเบียน
  3. รหัสร้านค้าที่ [ดำเนินการลงทะเบียนuลงทะเบียนเพิ่มขึ้นmและจากนั้นดำเนินการลงทะเบียนzถ้าลงทะเบียนmมีค่ามากกว่าการลงทะเบียนn] zในการลงทะเบียน
  4. ตั้งขนาด 5 จุดทศนิยม

  5. อ่านจำนวนจุดที่จะสุ่มตัวอย่างจากอินพุตบรรทัดแรก
  6. zดำเนินการลงทะเบียน
  7. แบ่งการลงทะเบียนx(จำนวนครั้ง) โดยการลงทะเบียนn(จำนวนจุด) คูณผลโดย 4 และการพิมพ์
  8. เลิก.

อย่างไรก็ตามฉันโกง:

โปรแกรมต้องการการสุ่มลอยตัวระหว่าง 0 ถึง 1

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

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

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

การใช้งาน:

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

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

ทดสอบการทำงาน:

% runpi 10000
3.14840

ตอนนี้มีการโกงน้อยกว่า (100 ไบต์)

มีคนชี้ให้เห็นว่าฉันสามารถรวม prng ง่ายๆ
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

Ungolfed

[
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

ทดสอบการทำงาน:

$ echo 10000 | dc pigolf.dc
3.13640

1

Pyth, 19

c*4sm<sm^OQ2 2*QQQQ

กำหนดจำนวนการวนซ้ำตามที่ต้องการเป็นอินพุต

สาธิต

เนื่องจาก Pyth ไม่มีฟังก์ชั่น "Random floating number" ฉันจึงต้องพูดโพล่งออกมา โปรแกรมเลือกจำนวนเต็มบวกแบบสุ่มสองตัวน้อยกว่าอินพุทสี่เหลี่ยมผลรวมและเปรียบเทียบกับอินพุทกำลังสอง สิ่งนี้ดำเนินการหลายครั้งเท่ากับอินพุตแล้วผลลัพธ์จะถูกคูณด้วย 4 และหารด้วยอินพุต

ในข่าวที่เกี่ยวข้องฉันจะเพิ่มการดำเนินการจำนวนจุดลอยตัวแบบสุ่มไปที่ Pyth ในไม่ช้า อย่างไรก็ตามโปรแกรมนี้ไม่ได้ใช้คุณสมบัตินั้น


หากเราตีความ "ผลลัพธ์อาจถูกส่งคืนหรือพิมพ์เป็นจุดลอยตัวจุดคงที่หรือจำนวนตรรกยะ" อย่างอิสระจากนั้นจึงพิมพ์ตัวเลขและตัวหารของเศษส่วนที่เกิดขึ้นให้เพียงพอ ในกรณีนั้น:

Pyth, 18

*4sm<sm^OQ2 2*QQQQ

นี่เป็นโปรแกรมที่เหมือนกันโดยการcลบส่วนการดำเนินการจุดลอยตัว ( ) ออก


1

Julia, 37 ไบต์

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

จำนวนตัวอย่างคือ 65536 (= 4 ^ 8)

ตัวแปรที่ยาวกว่า sligthly: ฟังก์ชันที่มีจำนวนตัวอย่างsเป็นอาร์กิวเมนต์เท่านั้น:

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

1

C, 130 ไบต์

#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);}

Ungolfed:

#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);
}

แน่นอนคุณจะยังคงอาจจะโพสต์รุ่นที่ไม่มีช่องว่าง (เก็บรุ่นปัจจุบันที่มีส่วนหัว "/ ungolfed ด้วยช่องว่าง" หรือบางอย่าง)
ทำลายมะนาว

@ ทำลายทำลายแตงโมได้!
Karl Napf

การแก้ปัญหาไม่ทำงานใน GCC f()โดยไม่ต้องขึ้นบรรทัดใหม่ก่อน คุณใช้คอมไพเลอร์อะไร? ดูtio.run/##Pc49C4JAHIDx3U9xGMG9ZdYgwWkgtNbQ1BZ6L/UHO8M07hA/...
eush77


1

จริงแล้ว 14 ไบต์ (ไม่ใช่การแข่งขัน)

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

ลองออนไลน์!

โซลูชันนี้ไม่สามารถแข่งขันกันได้เนื่องจากภาษาจะลงวันที่ท้าทาย จำนวนตัวอย่างถูกกำหนดให้เป็นอินพุต (แทนที่จะเขียนตายยาก)

คำอธิบาย:

`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
ทำไมต้องลงคะแนน
เลมอนที่ทำลายได้

1

แร็กเก็ต 63 ไบต์

การใช้วิธีการตอบภาษา R โดย @Matt:

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

Ungolfed:

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

การทดสอบ:

(f 10000)

เอาท์พุท (เศษส่วน):

3 31491308966059784/243801776017028125

เป็นทศนิยม:

(exact->inexact(f 10000))

3.13583200307849

1

Fortran (GFortran) , 84 83 ไบต์

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

ลองออนไลน์!

รหัสนี้เขียนแย่มาก มันจะล้มเหลวถ้า gfortran ตัดสินใจที่จะเริ่มต้นตัวแปรAด้วยค่าอื่นแล้ว 0 (ซึ่งเกิดขึ้น 50% ของการคอมไพล์โดยประมาณ) และถ้าAถูกกำหนดเป็น 0 มันจะสร้างลำดับสุ่มแบบเดียวกันเสมอสำหรับเมล็ดที่กำหนด จากนั้นค่าเดียวกันสำหรับ Pi จะถูกพิมพ์เสมอ

นี่เป็นโปรแกรมที่ดีกว่ามาก:

Fortran (GFortran) , 100 99 ไบต์

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

ลองออนไลน์!

(บันทึกหนึ่งไบต์ในแต่ละเวอร์ชัน; ขอบคุณ Penguino)


1
ในแต่ละรุ่นคุณสามารถบันทึกไบต์โดยเปลี่ยน 'DO I = 1,1E3' เป็น 'DO I = 1,4E3' เปลี่ยน 'A = A + 1' เป็น 'A = A + 1E-3' และเปลี่ยน ' PRINT *, A / 250 'ถึง' PRINT *, A '
Penguino

ใช่คุณแน่ใจ! ขอบคุณสำหรับคำแนะนำ!
rafa11111

1

Japt 26 หรือ 18 ไบต์

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

ลองออนไลน์!

คำตอบของ Analogous to Optimizerส่วนใหญ่แค่พยายามเรียนรู้ Japt ใช้เวลาจำนวนซ้ำในการทำงานสำหรับการป้อนข้อมูลโดยปริยาย
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.

หาก1/(1+x^2)ได้รับอนุญาต (แทนที่จะเป็นสอง randoms แยกกัน) จากนั้นเราสามารถบรรลุ 18 ไบต์ด้วยตรรกะเดียวกัน

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

1
คุณสามารถบันทึกไม่กี่ไบต์โดยให้Mhคำนวณด้านตรงข้ามมุมฉากมากกว่าที่จะทำมันเอง ;-) นอกจากนี้คุณสามารถใช้xเพื่อรวมผลรวมของอาร์เรย์แทนที่จะลดโดยเพิ่ม:o x@MhMr Mr)<1Ã*4/U
ETHproductions

@ETHproductions เรียบร้อยฉันไม่ทราบว่าคุณสามารถใช้Mhแบบนั้นขอบคุณ! คำตอบแบบสุ่มสองข้อของคุณใกล้จะสั้นเท่ากับคำตอบของฉันที่มีเพียงการสุ่มเพียงคำเดียวนั่นก็ค่อนข้างดี ฉันจะxจำไว้ฉันมักจะใช้การลดจำนวนมากเมื่อพยายามตีกอล์ฟดังนั้นมันจะมีประโยชน์มาก
นิด

1

F #, 149 ไบต์

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

ลองออนไลน์!

เท่าที่ฉันสามารถทำได้เพื่อทำผลรวมการวิ่งประเภทนี้ใน F # มันสั้นกว่าเพื่อสร้างอาร์เรย์ของตัวเลขและใช้ Seq.sumByวิธีการมากกว่าการใช้for..to..doบล็อก

รหัสนี้ทำอะไรได้บ้างที่จะสร้างคอลเลกชันของตัวเลขทศนิยมจาก 1 ถึงsดำเนินการฟังก์ชันfun x->...สำหรับจำนวนขององค์ประกอบในคอลเลกชันและผลรวม มีsองค์ประกอบในคอลเลกชันดังนั้นการทดสอบแบบสุ่มจะทำsเวลา ตัวเลขจริงในคอลเลกชันจะถูกละเว้น (fun x->แต่xไม่ได้ใช้)

นอกจากนี้ยังหมายความว่าแอปพลิเคชันจะต้องสร้างและเติมอาร์เรย์ก่อนแล้วจึงวนซ้ำ ดังนั้นอาจช้ากว่าสองเท่าfor..to..doลูปและด้วยการใช้หน่วยความจำในการสร้างอาร์เรย์อยู่ในภูมิภาคของ O (f ** k)!

สำหรับการทดสอบจริงแทนที่จะใช้ if then elseข้อความว่ามันคืออะไรคำนวณหาระยะทาง ( q()+q()|>Math.Sqrt) และปัดมันด้วยMath.Floorและรอบมันลงด้วย ถ้าระยะทางอยู่ในวงกลมมันจะถูกปัดเศษเป็น 0 หากระยะทางอยู่นอกวงกลมก็จะถูกปัดลงเป็น 1Seq.sumByวิธีจะรวมผลลัพธ์เหล่านี้

โปรดทราบว่าสิ่งที่Seq.sumByรวมกันนั้นไม่ใช่จุดภายในวงกลม แต่เป็นคะแนนนอกมัน ดังนั้นสำหรับผลลัพธ์ที่ได้s (ขนาดตัวอย่างของเรา) และลบผลรวมจากมัน

นอกจากนี้ยังปรากฏว่าการใช้ขนาดตัวอย่างเป็นพารามิเตอร์จะสั้นกว่าการเข้ารหัสค่าอย่างหนัก ดังนั้นฉันจึงโกงเล็กน้อย ...


1

Haskell, 116 114 110 96 ไบต์

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

เพราะการจัดการกับimport System.Random; r=randoms(mkStdGen 2)จะใช้เวลาไบต์มีค่ามากเกินไปผมสร้างรายการที่ไม่มีที่สิ้นสุดของตัวเลขสุ่มกับตัวสร้างความสอดคล้องแบบเชิงเส้นที่บอกว่าบางอย่างเกือบจะแข็งแกร่งเข้ารหัส: x↦x*9+1 mod 8^9ซึ่งโดยฮัลล์-Dobell 8^9ทฤษฎีบทมีระยะเวลาทั้งหมด

gผลผลิต4ถ้าจุดสุ่มตัวเลขอยู่ภายในวงกลมสำหรับคู่ของตัวเลขสุ่ม[0..8^9-1]เพราะสิ่งนี้จะกำจัดการคูณในสูตรที่ใช้

การใช้งาน:

> p 100000
3.14208

ลองออนไลน์!


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.