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

Самый короткий код выигрывает. Применяются обычные правила Code-Golf.

Пожалуйста, опубликуйте расчет и время f [1001] в качестве примера.

Доктор Велизарий
источник

Ответы:

9

J, 21 19 18

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

Строит комплексы от -x-xj до x + xj и принимает величину.

Изменить: с >:

Изменить 2: с крюком и монадическим ~. По какой-то причине работает в несколько раз медленнее, но все равно на 10 секунд для f (1000).

Джесси Милликен
источник
О, эй, я не знал о i:, я так краду это, спасибо!
JB
@JB: Да, хорошо ... Я краду >:. сумасшедший
Джесси Милликен
Хотелось бы, чтобы я достаточно хорошо разбирался в кепках, чтобы их тоже украсть O :-)
JB
Этот ответ удручающе короткий (для того, кто никогда не удосужился выучить короткий и / или игра в гольф) >:. Но это крутой ответ! :)
Фонд Моники судебный процесс
5

J, 27 21

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

Очень брутально: вычисляет sqrt (x² + y²) в диапазоне [-n, n] и считает ≤n . Все еще очень приемлемые времена для 1000.

Редактировать : i:yнемного короче, чем y-i.>:+:y. Спасибо Джесси Милликен !

JB
источник
Ха! Это была идея просить достойного выступления! Просто любопытно: какое время для 1000?
Доктор Велизарий
1
@belisarius: 0,86 с. На 10-летнем железе. 3.26s за 2000
JB
4

Рубин 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
Ventero
источник
4

Python 55 символов

f=lambda n:1+4*sum(int((n*n-i*i)**.5)for i in range(n))
fR0DDY
источник
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]]

Подсчитывает точки в квадранте x>=0, y>0, умножает на 4, добавляет 1 к центральной точке.

XNOR
источник
2

Haskell, 44 байта

f n|w<-[-n..n]=sum[1|x<-w,y<-w,x*x+y*y<=n*n]
Damien
источник
Я новичок в 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 , но рекурсивно и возвращает число с плавающей запятой. Возвращение int составляет 51 байт:

f=lambda n,i=0:i>n or 4*int((n*n-i*i)**.5)+f(n,i+1)
XNOR
источник
1

C (gcc) , 60 байтов

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

Попробуйте онлайн!

Зацикливает первый квадрант, умножает результат на 4 и добавляет один. Немного меньше в гольф

r,a;
f(x){
  for(a=r=x*x;a--;)
    r-=hypot(a%x+1,a/x)>x;
  x=4*r+1;
}
ceilingcat
источник
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.
lirtosiast
источник
1

Japt -x , 12 байт

òUn)ï Ëx²§U²

Попробуйте онлайн!

Объяснение:

ò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
12 байт
Shaggy
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;}

Его результат (проверьте https://3v4l.org/bC0cY для нескольких версий PHP):

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

На github можно найти простую реализацию, которая проверяет $n*($n+1)точки (и работает на 1000 медленнее, но все еще вычисляет f(1001)менее чем за 0,5 секунды) и набор тестов (с использованием данных примера, приведенных в вопросе) .

axiac
источник
0

Clojure / ClojureScript, 85 символов

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

Грубая сила заставляет первый квадрант, включая ось Y, но не ось X. Создает 4 для каждой точки, затем добавляет их вместе с 1 для начала координат. Запускается менее чем за 2 секунды для ввода 1000.

Злоупотребляет, forчтобы определить переменную и сохранить несколько символов. Делая то же самое для создания псевдонима range, вы не сохраняете никаких символов (и делаете его значительно медленнее), и кажется маловероятным, что вы собираетесь что-либо сохранить, создав квадратную функцию.

MattPutnam
источник
Это довольно старый вопрос, вы уверены, что этот ответ сработал бы в то время?
Blue
@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]число способов представить k как сумму двух квадратов, которая равна числу точек решетки на окружности радиуса k ^ 2. Суммируйте от k = 0 до k = n ^ 2, чтобы найти все точки на или внутри круга радиуса n.

Спарр
источник
1
2~SquaresR~k~Sum~{k,0,#^2}&чтобы сделать его короче
jaeyong спел
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}]

Простая дискретная петля x над квадрантом I, подсчитывающая наибольшее y с помощью теоремы Пифагора на каждом шаге. Результат в 4 раза больше суммы плюс один (для центральной точки).

Размер программы зависит от значения r . Замените {1001 0 -1}на, "$argv 0 -1"и вы можете запустить его с любым значением аргумента командной строки для r .

Вычисляет f (1001) → 3147833.0примерно за 1030 микросекунд, AMD Sempron 130, 2,6 ГГц, 64-разрядный процессор, Windows 7.

Очевидно, что чем больше радиус, тем ближе приближение к PI: f (10000001) выполняется примерно за 30 секунд, создавая 15-значное значение, что примерно соответствует точности двойного IEEE.

Dúthomhas
источник