Pi # 1 ธรรมชาติ - ทราย


9

เป้าหมาย

สร้าง ( N) ส่วนของเส้นสุ่มที่มีความยาวเหมือนกัน ( l) ตรวจสอบว่าพวกเขาข้ามtเส้นขนานเท่ากัน ( ) หรือไม่

การจำลอง

เรากำลังจำลองอะไร เข็มของ Buffon ทำให้ทรายเรียบในกล่องทรายของคุณวาดชุดของเส้นคู่ขนานที่เว้นระยะเท่ากัน (โทรหาระยะห่างระหว่างกันt) นำแท่งไม้ที่มีความยาวตรงlแล้วหยดNลงในกล่องทราย cให้จำนวนครั้งที่มันข้ามเส้นเป็น จากนั้นPi = (2 * l * n) / (t * c)!

เราจำลองสิ่งนี้ได้อย่างไร

  • รับอินพุต N,t,l
  • ด้วยN, t, lจำนวนเต็มบวกทั้งหมด
  • ทำตามNเวลาต่อไปนี้:
    • สร้างพิกัดจำนวนเต็มสุ่มอย่างสม่ำเสมอ x,y
    • กับ 1 <= x, y <= 10^6
    • x,y เป็นศูนย์กลางของส่วนของเส้นที่มีความยาว l
    • สร้างจำนวนเต็มสุ่มอย่างสม่ำเสมอ a
    • กับ 1 <= a <= 180
    • อนุญาตPเป็นจุดที่ส่วนของเส้นตรงข้ามแกน x
    • จากนั้นaเป็นมุม(x,y), P, (inf,0)
  • นับจำนวน, cของส่วนของเส้นตรงที่ตัดข้ามx = i*tจำนวนเต็มใด ๆi
  • กลับ (2 * l * N) / (t * c)

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

สเปค

  • อินพุต
    • ยืดหยุ่นรับอินพุตด้วยวิธีมาตรฐานใด ๆ (เช่นฟังก์ชันพารามิเตอร์ STDIN) และในรูปแบบมาตรฐานใด ๆ (เช่น String, Binary)
  • เอาท์พุต
    • ยืดหยุ่นให้ผลลัพธ์ในรูปแบบมาตรฐาน (เช่นผลตอบแทนการพิมพ์)
    • พื้นที่สีขาวพื้นที่ต่อท้ายและพื้นที่สีขาวชั้นนำเป็นที่ยอมรับ
    • ความแม่นยำโปรดระบุความแม่นยำอย่างน้อย 4 ตำแหน่ง (เช่น3.1416)
  • เกณฑ์การให้คะแนน
    • รหัสที่สั้นที่สุดชนะ!

กรณีทดสอบ

ผลลัพธ์ของคุณอาจไม่สอดคล้องกับสิ่งเหล่านี้เนื่องจากมีโอกาสสุ่ม 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

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


ฉันคิดว่าคุณทำหมายเลข 1 แล้ว
Conor O'Brien

1
@ ConorO'Brien ฉันจัดทำดัชนีเป็น XD
NonlinearFruit

ปัญหาในเรื่องนี้คือในภาษาที่ไม่มีตัวเลขที่ซับซ้อนคุณจะต้องเปลี่ยนจำนวน 0..180 เป็น 0..pi ซึ่งค่อนข้างจะเอาชนะวัตถุประสงค์ของการทดลองเข็มของควาย
เลเวลริเวอร์เซนต์

@Nonlinear ทิศทางผลไม้aสามารถถูกสร้างขึ้นด้วยวิธีอื่นได้หรือไม่ถ้ามันสม่ำเสมอ? (คิดถึงฟองเกาส์ 2D)
Karl Napf

1
สามารถสันนิษฐานได้t > lไหม? วิธีแก้ปัญหาด้านล่างสองข้อทำให้สมมติฐานนี้ซึ่งทำให้การตรวจสอบสี่แยกง่ายขึ้นเล็กน้อย
primo

คำตอบ:


9

R, 113 100 75 70 68 67 65 59 63 57 ไบต์

ในฐานะที่เป็นภาษาการเขียนโปรแกรมเชิงสถิติจึงไม่น่าแปลกใจที่ R เหมาะสำหรับงานประเภทนี้ ความจริงที่ว่าฟังก์ชั่นส่วนใหญ่สามารถรับอินพุตแบบเวกเตอร์ได้มีประโยชน์จริง ๆ สำหรับปัญหานี้แทนที่จะวนNซ้ำการวนซ้ำเราแค่ผ่านขนาดเวกเตอร์Nไป ขอบคุณ @Billywob สำหรับคำแนะนำที่นำไปสู่การตัด 4 ไบต์ ขอบคุณมาก @Primo ที่อธิบายให้ฉันฟังอย่างอดทนว่ารหัสของฉันไม่ทำงานในกรณีที่t > lตอนนี้ได้รับการแก้ไขแล้ว

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

ลองออนไลน์!

ตัวอย่างผลลัพธ์:

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

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

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

คำอธิบาย

ปัญหาเดือดลงไปเพื่อพิจารณาว่าxค่าสองค่าของเข็มอยู่ที่ด้านใดด้านหนึ่งของเส้นขนาน สิ่งนี้มีผลที่สำคัญบางประการ:

  1. y- ค่าไม่เกี่ยวข้อง
  2. ตำแหน่งสัมบูรณ์บนx-axis ไม่เกี่ยวข้องเฉพาะตำแหน่งที่สัมพันธ์กับเส้นขนานที่ใกล้ที่สุด

หลักนี้เป็นงานในพื้นที่ที่ 1 มิติที่เราสร้างเส้นที่มีความยาวใน [0, เป็นl] (มุมที่aกำหนดระยะเวลานี้) tและจากนั้นเราจะตรวจสอบเพื่อดูว่าหลายครั้งความยาวเกินกว่านี้ อัลกอริทึมคร่าวๆคือ:

  1. x1ค่าตัวอย่างจาก [0, 1000000] เนื่องจากเส้นคู่ขนานที่เกิดขึ้นในทุกtจุด TH ตามแนวxแกน, ญาติx-position เป็นโมดูโลxt
  2. aตัวอย่างมุม
  3. คำนวณตำแหน่งที่อยู่บนพื้นฐานของx2a
  4. ตรวจสอบวิธีการหลายครั้งx1+x2พอดีเข้าไปเช่นใช้พื้นของt(x1+x2)/t

Nหมายเลขสุ่มตัวอย่างใน [0, 1e6] โมดูโลtเทียบเท่ากับการสุ่มNตัวเลขใน [0, t] เนื่องจาก(x1+x2)/tเทียบเท่ากับx1/t + x2/tขั้นตอนแรกจะเป็นการสุ่มตัวอย่างจาก [0, t] / t, เช่น [0, 1] โชคดีสำหรับเรานั่นคือช่วงเริ่มต้นสำหรับrunifฟังก์ชั่นของ R ซึ่งจะส่งกลับNตัวเลขจริงจาก 0 ถึง 1 จากการแจกแจงแบบเดียวกัน

                          runif(N)

เราทำขั้นตอนนี้ซ้ำเพื่อสร้างaมุมของเข็ม

                                         runif(N)

ตัวเลขเหล่านี้ถูกตีความว่าเป็นครึ่งทาง (เช่น.590 องศา) (สหกรณ์ขอองศา 1-180 แต่ในความคิดเห็นก็ชี้แจงว่าวิธีการใด ๆ ที่ได้รับอนุญาตถ้ามันจะเป็นหรือแม่นยำมากขึ้น.) สำหรับมุมθ, sin(θ)ช่วยให้เรามีระยะทางแกน x ระหว่างปลายของเข็ม (โดยปกติคุณจะใช้โคไซน์เป็นอย่างนี้ แต่ในกรณีของเราเรากำลังพิจารณามุมθว่าสัมพันธ์กับแกน y ไม่ใช่แกน x (นั่นคือค่า 0 องศาเพิ่มขึ้นไม่ใช่ถูกต้อง ) และดังนั้นเราใช้ไซน์ซึ่งโดยทั่วไปแล้วเปลี่ยนเฟสตัวเลข) คูณด้วยlสิ่งนี้ทำให้เราทราบxตำแหน่งของจุดสิ้นสุดของเข็ม

                                   sinpi(runif(N))*l

ตอนนี้เราหารด้วยtและเพิ่มx1ค่า อัตราผลตอบแทนนี้(x1+x2)/tซึ่งเป็นเท่าที่เข็มยื่นออกมาจากx1ในแง่ของจำนวนของเส้นคู่ขนาน floorที่จะได้รับจำนวนเต็มของวิธีการหลายสายถูกข้ามที่เราใช้

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

เราคำนวณผลรวมทำให้เรานับcจำนวนเส้นที่ถูกเข็ม

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

ส่วนที่เหลือของรหัสเป็นเพียงการใช้สูตรสำหรับปี่ใกล้เคียง, (2*l*N)/(t*c)ที่อยู่, เราบันทึกบางส่วนในวงเล็บด้วยการใช้ประโยชน์จากข้อเท็จจริงที่(2*l*N)/(t*c) == 2*l*N/t/c:

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

และสิ่งทั้งหมดนั้นถูกห่อหุ้มด้วยฟังก์ชั่นนิรนาม:

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

@rtbullbull หนึ่งที่ดี! คุณไม่ควรข้ามวงเล็บในตอนแรกใช่ไหม (2*l*N) => 2*l*N?
Billywob

@Billywob ดีด่าง! ขอบคุณ
rturnbull

@rturnbull โอ้และโดยวิธีการ(2*l*N)/(t*c) = 2*l*N/t/cดังนั้นคุณสามารถบันทึกอีกสองไบต์โดยการข้ามวงเล็บในส่วนสุดท้ายเช่นกัน
Billywob

@Billywob อีกครั้งดีด่าง! ขอบคุณอีกครั้ง.
rturnbull

1
@primo ขอบคุณอีกครั้งมันควรได้รับการแก้ไขแล้ว
rturnbull

6

Perl, 97 ไบต์

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

นับ Shebang เป็นหนึ่งอินพุทถูกนำมาจาก stdin คั่นด้วยช่องว่าง หากอนุญาตให้มีการสุ่มค่าที่ไม่ใช่จำนวนเต็มค่านี้อาจจะค่อนข้างสั้น

ฉันได้นำหนึ่งเสรีภาพใกล้เคียงกับπ / 180เป็น71/4068ซึ่งมีความถูกต้องภายใน1.48 · 10 -9

ตัวอย่างการใช้งาน

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

การทดแทนที่เทียบเท่าในเชิงคณิตศาสตร์มากกว่าหรือน้อยกว่า

สมมติว่าพิกัด x เป็นจุดซ้ายสุดของเข็มแทนที่จะเป็นจุดกึ่งกลางดังที่ระบุไว้ในคำอธิบายปัญหา:

89 ไบต์

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

ปัญหาระบุว่าxต้องสุ่มตัวอย่างเป็นจำนวนเต็มแบบสุ่ม ถ้าเราคาดสายระยะห่างระหว่างช่องว่างของหนึ่งนี้จะปล่อยให้เรามีค่าของแบบฟอร์มn/tที่มี0 <= n < tไม่จำเป็นต้องเหมือนกันถ้าไม่เท่ากันแบ่งt 1e6สมมติว่าการแจกจ่ายแบบสม่ำเสมอนั้นเป็นที่ยอมรับได้:

76 ไบต์

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

โปรดทราบว่าเนื่องจากrandจะน้อยกว่าหนึ่งเสมอ (และถูกตัดให้เหลือศูนย์) จึงไม่จำเป็นในช่วงเริ่มต้นของช่วง:

70 ไบต์

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

สมมติว่ามุมของเข็มไม่จำเป็นต้องเป็นจำนวนเต็ม แต่สุ่มอย่างสม่ำเสมอ:

59 ไบต์

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

สมมติว่ามุมอาจมีการกระจายสม่ำเสมอ:

52 ไบต์

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

ด้านบนเป็นแบบจำลองทางคณิตศาสตร์ที่ถูกต้องของเข็มของ Buffon อย่างไรก็ตาม ณ จุดนี้ฉันคิดว่าคนส่วนใหญ่จะเห็นด้วยว่านี่ไม่ใช่คำถามที่ถาม


ผลักดันมันจริงๆ

เราสามารถทิ้งกรณีทดสอบไปครึ่งหนึ่งเมื่อใดก็ตามที่จุดปลายที่สองอยู่ทางซ้ายของจุดแรก (แทนที่จะสลับไปมา):

47 ไบต์

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

โปรดทราบว่าค่าของtและlไม่สำคัญกับผลลัพธ์ของการทดสอบ เราสามารถเพิกเฉยพวกเขาได้ (โดยปริยายสมมติว่าพวกเขาเท่าเทียมกัน):

28 ไบต์

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

เห็นได้ชัดว่าไม่ใช่การแข่งขัน แต่คุณต้องยอมรับว่ามันมีความสง่างามบางอย่าง


4

Python 2, 141 ไบต์

พอร์ตไร้ยางอาย rtumbull ข้ามไปแล้วyเพราะไม่ต้องการทั้งหมด

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

ปัญหาเป็นเพียง pi ที่เป็นที่รู้จักกันในโปรแกรม

นี่คือ (golfable) พร้อม pi ที่ไม่รู้จักและไม่มีฟังก์ชันตรีโกณมิติ

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,yในgเป็นเพียงทิศทาง


from random import randint;from math import cos,piต้องใช้ ล้มเหลวเช่นt < l 1000000,1000,70000
primo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.