Code-Golf: Punti reticolari all'interno di un cerchio


15

L'immagine seguente mostra il problema:

inserisci qui la descrizione dell'immagine

Scrivi una funzione che, dato un numero intero come raggio del cerchio, calcola il numero di punti reticolari all'interno del cerchio centrato (incluso il confine).

L'immagine mostra:

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

altri valori per il tuo controllo / debugging:

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

Dovrebbe avere prestazioni ragionevoli. Diciamo meno di un minuto per f [1000].

Il codice più corto vince. Si applicano le normali regole del codice golf.

Si prega di pubblicare il calcolo e la tempistica di f [1001] come esempio.



Risposte:


9

J, 21 19 18

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

Costruisce complessi da -x-xj a x + xj e assume magnitudo.

Modifica: con >:

Modifica 2: con hook e monadic ~. Viene eseguito alcune volte più lentamente per qualche motivo, ma ancora 10 secondi per f (1000).


Oh ehi, non lo sapevo i:, lo sto rubando così , grazie!
JB

@JB: Sì, beh ... sto rubando >:. derp
Jesse Millikan,

Vorrei aver capito abbastanza bene i cappucci per rubare anche quelli O :-)
JB

Questa risposta è deprimentemente breve (per qualcuno che non si è mai preso la briga di imparare una lingua breve e / o golfistica) >:. Ma hey, questa è una bella risposta! :)
Fondi Monica's Lawsuit

5

J, 27 21

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

Molto brutale: calcola sqrt (x² + y²) nell'intervallo [-n, n] e conta gli elementi ≤n . Tempi ancora accettabili per 1000.

Modifica : i:yè un po 'più breve di y-i.>:+:y. Grazie Jesse Millikan !


Ha! Questa era l'idea alla base di una performance decente! Solo curioso: qual è il tempismo per 1000?
Dr. belisarius,

1
@belisarius: 0.86s. Su hardware di 10 anni. 3.26s per il 2000.
JB

4

Ruby 1.9, 62 58 54 caratteri

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

Esempio:

f[1001]
=> 3147833

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

4

Python 55 Chars

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))è più breve di 17 caratteri.
Ventero,

3

Haskell, 41 byte

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

Conta i punti nel quadrante x>=0, y>0, si moltiplica per 4, aggiunge 1 per il punto centrale.


2

Haskell, 44 byte

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

Sono nuovo di Haskell: come puoi scrivere w<-[-n..n]dove (di solito) c'è un valore booleano?
flawr

1
@flawr Queste sono le protezioni dei modelli , che hanno successo se un modello è abbinato, ma può essere usato nel golf come let più breve. Vedi questo consiglio .
xnor

Grazie, non ero a conoscenza di questo thread!
flawr

1

JavaScript (ES6), 80 byte (non in competizione perché ES6 è troppo nuovo)

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

Versione alternativa, anche 80 byte:

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

Versione ES7, anche 80 byte:

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 byte

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

Come la soluzione di fR0DDY , ma ricorsiva e restituisce un float. Restituire un int è 51 byte:

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

1

C (gcc) , 60 byte

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

Provalo online!

Passa sopra il primo quadrante, moltiplica il risultato per 4 e ne aggiunge uno. Leggermente meno golfato

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

1

APL (Dyalog Extended) , 14 byte

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

Provalo online!

Nonostante manchi l' i:intervallo (compreso tra -n e n) di J, APL Extended ha una sintassi più breve in altre aree.

{≢⍸⍵≥|⌾⍀⍨⍵…-⍵}            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

Japt -x , 12 byte

òUn)ï Ëx²§U²

Provalo online!

Spiegazione:

ò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


1

PHP, 85 83 byte

Il codice:

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

Il suo risultato (consultare https://3v4l.org/bC0cY per più versioni di PHP):

f(1001)=3147833
time=0.000236 seconds.

Il codice ungolfed:

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

Un'implementazione ingenua che controlla i $n*($n+1)punti (ed esegue 1000 più lentamente, ma calcola ancora f(1001)in meno di 0,5 secondi) e la suite di test (usando i dati di esempio forniti nella domanda) sono reperibili su github .


0

Clojure / ClojureScript, 85 caratteri

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

Brute forza il primo quadrante, incluso l'asse y ma non l'asse x. Genera un 4 per ogni punto, quindi li aggiunge insieme a 1 per l'origine. Funziona in meno di 2 secondi per input di 1000.

Abusa al diavolo forper definire una variabile e salvare alcuni personaggi. Fare lo stesso per creare un alias per rangenon salvare alcun personaggio (e farlo funzionare in modo significativamente più lento), e sembra improbabile che salverai qualcosa facendo una funzione quadrata.


Questa è una domanda piuttosto vecchia, sei sicuro che questa risposta avrebbe funzionato in quel momento?
Blue

@muddyfish Non ho notato l'età, ho appena visto vicino alla cima. Clojure precede la domanda, ma non conosco la sua storia abbastanza da sapere sui cambiamenti della lingua.
MattPutnam,


0

Mathematica, 35 personaggi

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

Estratto da https://oeis.org/A000328

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

SquaresR[2,k]è il numero di modi per rappresentare k come la somma di due quadrati, che è lo stesso del numero di punti reticolari su un cerchio di raggio k ^ 2. Somma da k = 0 a k = n ^ 2 per trovare tutti i punti su o all'interno di un cerchio di raggio n.


1
2~SquaresR~k~Sum~{k,0,#^2}&per renderlo più breve
jaeyong cantò il

0

Tcl, 111 byte

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

Semplice ciclo x discreto sul quadrante I, contando il più grande y usando il Teorema di Pitagora ad ogni passo. Il risultato è 4 volte la somma più uno (per il punto centrale).

La dimensione del programma dipende dal valore di r . Sostituisci {1001 0 -1}con "$argv 0 -1"e puoi eseguirlo con qualsiasi valore dell'argomento della riga di comando per r .

Calcola f (1001) → 3147833.0in circa 1030 microsecondi, processore AMD Sempron 130 da 2,6 GHz a 64 bit, Windows 7.

Ovviamente, maggiore è il raggio, più vicina è l'approssimazione a PI: f (10000001) che corre in circa 30 secondi producendo un valore di 15 cifre, che è circa la precisione di un doppio IEEE.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.