Code-Golf:円の中の格子点


15

次の図に問題を示します。

ここに画像の説明を入力してください

円の半径として整数を指定し、中心の円内(境界を含む)の格子点の数を計算する関数を作成します。

画像は次のとおりです。

f[1] = 5  (blue points)
f[2] = 13 (blue + red points)  

チェック/デバッグの他の値:

f[3]    = 29
f[10]   = 317
f[1000] = 3,141,549
f[2000] = 12,566,345  

適切なパフォーマンスが必要です。f [1000]の場合、1分未満としましょう。

最短のコードが優先されます。通常のコードゴルフ規則が適用されます。

例としてf [1001]の計算とタイミングを投稿してください。



回答:


9

J、21 19 18

+/@,@(>:|@j./~@i:)

-x-xjからx + xjの複合体を構築し、大きさを取ります。

編集:あり >:

編集2:フックとモナドで~。何らかの理由で数倍遅くなりますが、f(1000)の場合はまだ10秒です。


ああ、私は知らなかったi:、私はそれをとても盗んでいる、ありがとう!
JB

@JB:ええ、まあ...私は盗んでい>:ます。DERP
ジェシーミリカン

それらを盗むのに十分な上限を理解したいO:
JB

この答えは、憂鬱なほど短いです(ショートやゴルフのラングを習得することに悩んだことがない人にとって)>:。しかし、ちょっと、それはクールな答えです!:)
ファンドモニカの訴訟

5

J、27 21

3 :'+/,y>:%:+/~*:i:y'

非常に残忍な:[-n、n]の範囲でsqrt(x²+y²)を計算し、アイテム≤nをカウントします。1000でも非常に許容可能な時間です。

編集i:yよりもかなり短いですy-i.>:+:y。ありがとう、ジェシー・ミリカン


ハ!それがまともなパフォーマンスを求める背後にあるアイデアでした!好奇心が強い:1000のタイミングは何ですか?
ベリサリウス博士11

1
@belisarius:0.86秒。10年前のハードウェア。2000
JB

4

Ruby 1.9、 62 58 54文字

f=->r{1+4*eval((0..r).map{|i|"%d"%(r*r-i*i)**0.5}*?+)}

例:

f[1001]
=> 3147833

t=Time.now;f[1001];Time.now-t
=> 0.003361411

4

Python 55文字

f=lambda n:1+4*sum(int((n*n-i*i)**.5)for i in range(n))

f=lambda n:1+4*sum(int((n*n-i*i)**.5)for i in range(n))17文字短くなります。
ヴェンテロ

3

Haskell、41バイト

f n=1+4*sum[floor$sqrt$n*n-x*x|x<-[0..n]]

象限内のポイントをカウントし、4 x>=0, y>0で乗算し、中心点に1を加算します。


2

Haskell、44バイト

f n|w<-[-n..n]=sum[1|x<-w,y<-w,x*x+y*y<=n*n]

私はHaskellが初めてです:どのようw<-[-n..n]にして(通常)ブール値がある場所を書くことができますか?
-flawr

1
@flawrこれらはパターンガードで、パターンが一致した場合に成功しますが、ゴルフでは短いレットとして使用できます。このヒントを参照してください。
xnor

おかげで、私はこのスレッドに気付いていませんでした!
-flawr

1

JavaScript(ES6)、80バイト(ES6が新しすぎるため競合しない)

n=>(a=[...Array(n+n+1)].map(_=>i--,i=n)).map(x=>a.map(y=>r+=x*x+y*y<=n*n),r=0)|r

代替バージョン、80バイト:

n=>[...Array(n+n+1)].map((_,x,a)=>a.map((_,y)=>r+=x*x+(y-=n)*y<=n*n,x-=n),r=0)|r

ES7バージョン、80バイト:

n=>[...Array(n+n+1)].map((_,x,a)=>a.map((_,y)=>r+=(x-n)**2+(y-n)**2<=n*n),r=0)|r

1

Python 2、48バイト

f=lambda n,i=0:i>n or(n*n-i*i)**.5//1*4+f(n,i+1)

fR0DDYのsolution似ていますが、再帰的であり、floatを返します。intを返すことは51バイトです:

f=lambda n,i=0:i>n or 4*int((n*n-i*i)**.5)+f(n,i+1)


1

APL(Dyalog Extended)、14バイト

{≢⍸⍵≥|⌾⍀⍨⍵…-⍵}

オンラインでお試しください!

i:Jの組み込み(-nからnまでの範囲)が欠けているにもかかわらず、APL Extendedの構文は他の領域では短くなっています。

{≢⍸⍵≥|⌾⍀⍨⍵…-⍵}            Monadic function taking an argument n.
           ⍵…-⍵             n, n-1, ..., -n
      ⌾⍀                   Make a table of complex numbers
                            (equivalent to ∘.{⍺+1J×⍵} in Dyalog APL)
                           with both real and imaginary parts from that list.
      |                       Take their magnitudes.
    ⍵≥                        1 where a magnitude are is at most n, and 0 elsewhere.
                            Get all indices of truthy values.
                            Find the length of the resulting list.


1

PHP、85 83バイト

コード:

function f($n){for($x=$n;$x;$c+=$x,$y++)for(;$n*$n<$x*$x+$y*$y;$x--);return$c*4+1;}

その結果(複数のPHPバージョンについてはhttps://3v4l.org/bC0cYを確認してください):

f(1001)=3147833
time=0.000236 seconds.

改変されていないコード:

/**
 * Count all the points having x > 0, y >= 0 (a quarter of the circle)
 * then multiply by 4 and add the origin.
 *
 * Walk the lattice points in zig-zag starting at ($n,0) towards (0,$n), in the
 * neighbourhood of the circle. While outside the circle, go left.
 * Go one line up and repeat until $x == 0.
 * This way it checks about 2*$n points (i.e. its complexity is linear, O(n))
 *
 * @param int $n
 * @return int
 */
function countLatticePoints2($n)
{
    $count = 0;
    // Start on the topmost right point of the circle ($n,0), go towards the topmost point (0,$n)
    // Stop when reach it (but don't count it)
    for ($y = 0, $x = $n; $x > 0; $y ++) {
        // While outside the circle, go left;
        for (; $n * $n < $x * $x + $y * $y; $x --) {
            // Nothing here
        }
        // ($x,$y) is the rightmost lattice point on row $y that is inside the circle
        // There are exactly $x lattice points on the row $y that have x > 0
        $count += $x;
    }
    // Four quarters plus the center
    return 4 * $count + 1;
}

$n*($n+1)ポイントをチェックする(そして1000 f(1001)秒遅くなりますが、0.5秒未満で計算する)素朴な実装とテストスイート(質問で提供されるサンプルデータを使用)はgithubで見つけることができます。


0

Clojure / ClojureScript、85文字

#(apply + 1(for[m[(inc %)]x(range 1 m)y(range m):when(<=(+(* x x)(* y y))(* % %))]4))

ブルートは、x軸ではなくy軸を含む第1象限を強制します。すべてのポイントに対して4を生成し、それらを原点の1とともに追加します。1000の入力に対して2秒未満で実行されます。

地獄を悪用しforて変数を定義し、数文字を保存します。エイリアスを作成するために同じことをrangeしても、文字は保存されず(実行速度が大幅に低下します)、平方関数を作成して保存する可能性は低いようです。


これは非常に古い質問ですが、この答えはその時点で機能していましたか?
ブルー

@muddyfish私は年齢に気付かなかった、ちょうどトップ近くでそれを見た。Clojureは質問の前に存在しますが、言語の変更について知るのに十分なほどその歴史を知りません。
-MattPutnam


0

Mathematica、35文字

f[n_]:=Sum[SquaresR[2,k],{k,0,n^2}]

https://oeis.org/A000328から削除

https://reference.wolfram.com/language/ref/SquaresR.html

SquaresR[2,k]は、2つの正方形の合計としてkを表す方法の数です。これは、半径k ^ 2の円上の格子点の数と同じです。k = 0からk = n ^ 2までを合計して、半径nの円上または円内のすべてのポイントを見つけます。


1
2~SquaresR~k~Sum~{k,0,#^2}&短くするために
ジェヨンは

0

Tcl、111バイト

lassign {1001 0 -1} r R x
while {[incr x]<$r} {set R [expr {$R+floor(sqrt($r*$r-$x*$x))}]}
puts [expr {4*$R+1}]

各ステップでピタゴラスの定理を使用して最大のyをカウントする、象限I上の単純な離散xループ。結果は合計の4倍に1を加えたものです(中心点の場合)。

プログラムのサイズはrの値に依存します。に置き換え{1001 0 -1}"$argv 0 -1"rのコマンドライン引数値で実行できます。

f(1001)を計算→ 3147833.0約1030マイクロ秒で、AMD Sempron 130 2.6GHz 64ビットプロセッサ、Windows 7

明らかに、半径が大きいほど、PI:f(10000001)の近似は約30秒で実行され、15桁の値を生成します。これは、IEEE倍精度の精度です。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.