Code-Golf: Kraty Punkty wewnątrz Koła

15

Poniższy obrazek pokazuje problem:

wprowadź opis zdjęcia tutaj

Napisz funkcję, która, biorąc pod uwagę liczbę całkowitą jako promień okręgu, oblicza liczbę punktów sieci wewnątrz wyśrodkowanego koła (łącznie z granicą).

Obraz pokazuje:

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

inne wartości dla twojego sprawdzania / debugowania:

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

Powinien mieć rozsądną wydajność. Powiedzmy, że mniej niż minuta dla f [1000].

Najkrótszy kod wygrywa. Obowiązują zwykłe zasady gry w golfa.

Proszę zamieścić obliczenie i czas dla f [1001] jako przykład.

Dr Belizariusz
źródło
4
oeis.org/A328
msh210
Wersja trójkątna .
user202729

Odpowiedzi:

9

J, 21 19 18

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

Buduje kompleksy od -x-xj do x + xj i nabiera wielkości.

Edycja: Z >:

Edycja 2: Z hakiem i monadycznie ~. Działa kilka razy wolniej z jakiegoś powodu, ale wciąż 10-sekundowych sekund dla f (1000).

Jesse Millikan
źródło
Och, hej, nie wiedziałem o tym i:, tak bardzo to kradnę, dzięki!
JB
@JB: Tak, cóż ... Kradnę >:. derp
Jesse Millikan,
Żałuję, że nie rozumiem czapek wystarczająco dobrze, aby je też ukraść O :-)
JB
Ta odpowiedź jest przygnębiająco krótka (dla kogoś, kto nigdy nie zadał sobie trudu, aby nauczyć się krótkiego i / lub golfowego języka) >:. Ale hej, to fajna odpowiedź! :)
Pozew Fund Moniki
5

J, 27 21

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

Bardzo brutalny: oblicza sqrt (x² + y²) w zakresie [-n, n] i zlicza elementy ≤n . Nadal bardzo dopuszczalne czasy dla 1000.

Edycja : i:yjest nieco krótsza niż y-i.>:+:y. Dzięki Jesse Millikan !

JB
źródło
Ha! Taki był pomysł na przyzwoite wykonanie! Ciekawe: jaki jest czas na 1000?
Dr Belisarius,
1
@belisarius: 0,86s. Na 10-letnim sprzęcie. 3,26s na rok 2000.
JB
4

Ruby 1.9, 62 58 54 znaków

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

Przykład:

f[1001]
=> 3147833

t=Time.now;f[1001];Time.now-t
=> 0.003361411
Ventero
źródło
4

Python 55 znaków

f=lambda n:1+4*sum(int((n*n-i*i)**.5)for i in range(n))
fR0DDY
źródło
f=lambda n:1+4*sum(int((n*n-i*i)**.5)for i in range(n))ma 17 znaków krótszy.
Ventero,
3

Haskell, 41 bajtów

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

Liczy punkty w kwadrancie x>=0, y>0, mnoży przez 4, dodaje 1 do punktu środkowego.

xnor
źródło
2

Haskell, 44 bajty

f n|w<-[-n..n]=sum[1|x<-w,y<-w,x*x+y*y<=n*n]
Damien
źródło
Jestem nowy w Haskell: Jak napisać, w<-[-n..n]gdzie (zwykle) jest wartość logiczna?
flawr
1
@flawr Są to strażnicy wzorów , które odnoszą sukces, jeśli wzór jest dopasowany, ale mogą być używane w golfie jako krótszy let. Zobacz tę wskazówkę .
xnor
Dzięki, nie byłem świadomy tego wątku!
flawr
1

JavaScript (ES6), 80 bajtów (niekonkurencyjny, ponieważ ES6 jest zbyt nowy)

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

Alternatywna wersja, także 80 bajtów:

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

Wersja ES7, również 80 bajtów:

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

Python 2, 48 bajtów

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

Podobnie jak rozwiązanie fR0DDY , ale rekurencyjne i zwraca liczbę zmiennoprzecinkową. Zwrócenie liczby całkowitej wynosi 51 bajtów:

f=lambda n,i=0:i>n or 4*int((n*n-i*i)**.5)+f(n,i+1)
xnor
źródło
1

C (gcc) , 60 bajtów

r,a;f(x){for(a=r=x*x;a--;)r-=hypot(a%x+1,a/x)>x;x=4*r+1;}

Wypróbuj online!

Pętle w pierwszym kwadrancie mnoży wynik przez 4 i dodaje jeden. Nieco mniej golfa

r,a;
f(x){
  for(a=r=x*x;a--;)
    r-=hypot(a%x+1,a/x)>x;
  x=4*r+1;
}
sufitowy
źródło
1

APL (Dyalog Extended) , 14 bajtów

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

Wypróbuj online!

Pomimo braku i:wbudowanego J (włącznie z zakresu od -n do n), APL Extended ma krótszą składnię w innych obszarach.

{≢⍸⍵≥|⌾⍀⍨⍵…-⍵}            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.
lirtosiast
źródło
1

Japt -x , 12 bajtów

òUn)ï Ëx²§U²

Wypróbuj online!

Wyjaśnienie:

òUn)            #Get the range [-input ... input]
    ï           #Get each pair of numbers in that range
      Ë         #For each pair:
       x        # Get the sum...
        ²       # Of the squares
         §      # Check if that sum is less than or equal to...
          U²    # The input squared
                #Output the number of pairs that passed the check
Kamil Drakari
źródło
1
12 bajtów
Kudłaty
1

PHP, 85 83 bajtów

Kod:

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

Jego wynik (sprawdź https://3v4l.org/bC0cY dla wielu wersji PHP):

f(1001)=3147833
time=0.000236 seconds.

Nieskluczony kod:

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

Naiwną implementację, która sprawdza $n*($n+1)punkty (i działa 1000 wolniej, ale nadal oblicza f(1001)w czasie krótszym niż 0,5 sekundy) oraz zestaw testów (używając przykładowych danych podanych w pytaniu) można znaleźć na github .

aksjomat
źródło
0

Clojure / ClojureScript, 85 znaków

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

Brute wymusza pierwszą ćwiartkę, w tym oś y, ale nie oś x. Generuje 4 dla każdego punktu, a następnie dodaje je razem z 1 dla początku. Działa w czasie poniżej 2 sekund dla wejścia 1000.

Nadużywają, foraby zdefiniować zmienną i zapisać kilka znaków. Robiąc to samo, aby utworzyć alias dla range, nie zapisujesz żadnych znaków (i sprawia, że ​​działa on znacznie wolniej) i wydaje się mało prawdopodobne, że cokolwiek uratujesz, wykonując kwadratową funkcję.

MattPutnam
źródło
To dość stare pytanie, czy na pewno ta odpowiedź zadziałaby w tym czasie?
Niebieski
@muddyfish Nie zauważyłem wieku, po prostu widziałem go u góry. Clojure poprzedza pytanie, ale nie znam jego historii wystarczająco dobrze, aby wiedzieć o zmianach językowych.
MattPutnam,
0

Pyke, 14 bajtów, niekonkurujący

QFXQX-_,B)s}}h

Wypróbuj tutaj!

niebieski
źródło
0

Mathematica, 35 znaków

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

Odebrano z https://oeis.org/A000328

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

SquaresR[2,k]jest liczbą sposobów przedstawienia k jako sumy dwóch kwadratów, która jest taka sama jak liczba punktów sieci na okręgu o promieniu k ^ 2. Suma od k = 0 do k = n ^ 2, aby znaleźć wszystkie punkty na lub wewnątrz okręgu o promieniu n.

Sparr
źródło
1
2~SquaresR~k~Sum~{k,0,#^2}&aby było krótsze
jaeyong śpiewał
0

Tcl, 111 bajtów

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}]

Prosta dyskretna pętla x w kwadrancie I, licząc największe y, używając twierdzenia Pitagorasa na każdym kroku. Wynik to 4-krotność sumy plus jeden (dla punktu środkowego).

Rozmiar programu zależy od wartości r . Wymień {1001 0 -1}się "$argv 0 -1"i można go uruchomić z dowolnej wartości argumentów wiersza polecenia do r .

Oblicza f (1001) → 3147833.0w około 1030 mikrosekund, 64-bitowy procesor AMD Sempron 130 2,6 GHz, Windows 7.

Oczywiście im większy promień, tym bliższe przybliżenie do PI: f (10000001) biegnie w około 30 sekund, dając 15-cyfrową wartość, która jest o precyzji podwójnej IEEE.

Dúthomhas
źródło