自然なPi#1-砂


9

ゴール

N均一な長さ()のランダムな線分を生成()しl、等間隔(t)の平行線と交差するかどうかを確認します。

シミュレーション

何をシミュレートしますか? ブッフォンの針。サンドボックス内の砂を滑らかにし、等間隔の平行線のセットを描画します(間の距離をと呼びます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など)および標準的な形式(文字列、バイナリなど)で入力を取得します。
  • 出力
    • 柔軟性があり、標準的な方法(たとえば、返品、印刷)で出力を提供します。
    • 空白、末尾および先頭の空白は許容されます
    • 精度、正確さの少なくとも小数点以下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を概算するために自然と脳(およびおそらくいくつかの再利用可能なリソース)のみを必要とするアルゴリズムのシミュレーションです。ゾンビの黙示録中に本当にPiが必要な場合、これらの方法は弾薬を無駄にしません!合計9つの課題があります。


もう1位だと思った?
Conor O'Brien

1
@ ConorO'Brien ゼロインデックス it XD
NonlinearFruit

これの問題は、複素数のない言語では、0..180を0..piに変換する必要があることです。これは、ブッフォンの針の実験の目的に反します。
Level River St

@NonlinearFruit方向aが均一であれば、別の方法で方向を作成することもできますか?(2Dガウスバブルを考える)
Karl Napf、2016年

1
それはそれと仮定できますt > lか?以下の2つのソリューションはこの仮定を行っているため、交差のチェックがかなり簡単になります。
プリモ

回答:


9

R、113 100 75 70 68 67 65 59 63 57バイト

統計的で関数型のプログラミング言語として、Rがこの種のタスクにかなり適していることは当然のことです。ほとんどの関数がベクトル化された入力を受け取ることができるという事実は、この問題に非常に役立ちます。N反復をループするのではなく、サイズのベクトルを渡すだけNです。4バイトの切り捨てにつながるいくつかの提案をしてくれた@Billywobに感謝します。@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は、針の2つの値が平行線の両側にあるかどうかを判断することです。これにはいくつかの重要な影響があります。

  1. y-値は関係ありません
  2. - x軸上の絶対位置は関係ありません。最も近い平行線に対する相対的な位置のみです。

基本的に、これは1次元空間でのタスクであり、[0、l] で長さの線を生成し(角度aによってこの長さが決まる)、この長さがを超える回数を確認しますt。大まかなアルゴリズムは次のとおりです。

  1. x1[0、1000000]のサンプル値。平行線tは- x軸に沿ってすべてのポイントで発生するため、相対x位置はxmodulo tです。
  2. 角度をサンプリングしaます。
  3. x2基づいて位置を計算しaます。
  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]になります。幸運なことに、これはRのrunif関数のデフォルト範囲でありN、一様分布から0から1までの実数を返します。

                          runif(N)

この手順を繰り返してa、針の角度を生成します。

                                         runif(N)

これらの数値は半回転(つまり.590度)として解釈されます。(OPは1から180度を求めたが、コメントで、のようにまたはより正確であれば任意の方法が可能であることを明らかにしています。)角度のためθsin(θ)私たちは針の端部間のX軸距離を与えます。(通常、このようなものにはコサインを使用しますが、この例では、角度θはx軸ではなくy軸に対するものと見なしています(つまり、0度の値は上がるのではなく、)、したがって、基本的には数値を位相シフトするサインを使用します。lこれを掛けるxと、針の先端の位置がわかります。

                                   sinpi(runif(N))*l

次に、除算しtx1値を追加します。これにより(x1+x2)/tx1平行線の数に関して、からの距離がわかります。交差した行数の整数を取得するには、を使用しfloorます。

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

合計を計算し、c針が何本の線と交差しているかをカウントします。

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

残りのコードは、piを概算するための式、つまりを実装しているだけ(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)))

@rturnbullいいね!最初の括弧を飛ばしてはいけませんか?(2*l*N) => 2*l*N
Billywob 2016年

@Billywob見事な!ありがとう。
rturnbull

@rturnbullああ、ちなみに、(2*l*N)/(t*c) = 2*l*N/t/c最後の部分の括弧をスキップすることで、さらに2バイト節約できます。
Billywob

@Billywob再び、よく知られています!再度、感謝します。
rturnbull

1
@primoありがとうございました。今すぐ修正する必要があります。
rturnbull 2016年

6

Perl、97バイト

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

シバンを1つとして数え、入力は標準入力から取得され、スペースで区切られます。非整数のランダム値が許可されている場合、これは多少短くなる可能性があります。

私は1つの自由を取り、π/ 18071/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は、ランダムな整数としてサンプリングされることを指定しています。行間隔を1のギャップに投影するn/t0 <= n < ttが均等に分割されない場合、必ずしもとは限らないのフォームの値が残ります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の針の数学的に正しいシミュレーションです。しかし、現時点では、ほとんどの人は、これが実際に質問されたものではないことに同意するでしょう。


本当にそれをプッシュイン

2番目のエンドポイントが最初のものの左側にあるときはいつでも(それらを交換するのではなく)、テストケースの半分を捨てることができます。

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がプログラムで既に知られていることだけです。

ここでは、(ゴルフ可能)未知の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,ygのみ方向です。


が必要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.