is_gaussian_prime (z)?


23

Завдання

Напишіть функцію, яка приймає два цілі числа, a,bякі представляють цілі числа Гаусса z = a+ib(комплексне число). Програма повинна повертати правду чи хибність залежно від того, чи a+ibє це просто Гаусс чи ні .

Визначення:

a + bi є прем'єр-міністром Гаусса тоді і лише тоді, коли він відповідає одній з наступних умов:

  • aі bвони є ненульовими і a^2 + b^2є простими
  • aдорівнює нулю, |b|є простим і|b| = 3 (mod 4)
  • bдорівнює нулю, |a|є простим і|a| = 3 (mod 4)

Деталі

Вам слід написати лише функцію. Якщо у вашій мові немає функцій, ви можете припустити, що цілі числа зберігаються у двох змінних і друкують результат або записують його у файл.

Ви не можете використовувати вбудовані функції вашої мови , як isprimeабо prime_listабо nthprimeабо factor. Виграє найменша кількість байтів. Програма повинна працювати a,bтам, де a^2+b^2є 32-бітове (підписане) ціле число і має закінчитися не більше ніж за 30 секунд.

Основний список

Точки представляють прості числа на площині Гаусса ( x= реальна, y= уявна вісь):

введіть тут опис зображення

Деякі більші розміри:

(9940, 43833)
(4190, 42741)
(9557, 41412)
(1437, 44090)

2
Чи дозволено нам використовувати функції факторизації ( factorв Bash, mfі mFв CJam, ...)

О ні, я забув, що існували методи факторизації, не будь ласка =) І 32-бітний ліміт застосовується до ^ 2 + b ^ 2, інакше не має сенсу. Дякую за вкладені дані! Я оновив питання.
flawr

2
Я додав визначення посту Гаусса до посади. Якщо вам не подобається, як я це зробив, не соромтеся повернути його назад, але я б точно рекомендував включити десь визначення.
підземниймонорельс

Це добре, я спочатку просто не хотів прямо вказувати, як визначити первинність, щоб люди стали творчими =)
flawr

1 1073741857 не здається мені прем'єр-
міністром

Відповіді:


4

Haskell - 77/ 108 107 Символів

використання: в обох рішеннях введення% b поверне, чи + bi є гауссовим простим.

найнижчий, що мені вдалося, але без творчості та продуктивності (77 годин)

p n=all(\x->rem n x>0)[2..n-1]
a%0=rem a 4==3&&p(abs a)
0%a=a%0
a%b=p$a^2+b^2

це рішення просто вправляє всі числа нижче n, щоб перевірити, чи є простим.

неозорений варіант:

isprime = all (\x -> rem n x != 0) [2..n-1] -- none of the numbers between 2 and n-1 divide n.
isGaussianPrime a 0 = rem a 4==3 && isprime (abs a)
isGaussianPrime 0 a = isGaussianPrime a 0   -- the definition is symmetric
isGaussianPrime a b = isprime (a^2 + b^2)

наступне рішення має додаткову особливість - запам'ятовування. як тільки ви перевірили, чи є деяке ціле число n простим, вам не потрібно буде перераховувати "первинність" усіх чисел, менших або рівних n, оскільки воно буде зберігатися в комп'ютері.

(107 символів. Коментарі для ясності)

s(p:x)=p:s[n|n<-x,rem n p>0] --the sieve function
l=s[2..]                     --infinite list of primes
p n=n==filter(>=n)l!!0       --check whether n is in the list of primes
a%0=rem a 4==3&&p(abs a)
0%a=a%0
a%b=p$a*a+b*b

неозорений варіант:

primes = sieve [2..] where
    sieve (p:xs) = p:filter (\n -> rem n p /= 0) xs
isprime n = n == head (filter (>=n) primes) -- checks if the first prime >= n is equal to n. if it is, n is prime.
isGaussianPrime a 0 = rem a 4==3 && isprime (abs a)
isGaussianPrime 0 a = isGaussianPrime a 0   -- the definition is symmetric
isGaussianPrime a b = isprime (a^2 + b^2)

для цього використовується сито Ератостена для обчислення нескінченного списку всіх прайменів (для списку в коді називається l). (нескінченні списки - добре відомий трюк хескелл).

як можливо мати нескінченний список? на початку програми список не оцінюється, і замість того, щоб зберігати елементи списків, комп'ютер зберігає спосіб їх обчислення. але програма отримує доступ до списку, вона частково оцінює себе відповідно до запиту. Так, якби програма запитала четвертий елемент у списку, комп'ютер обчислював би всі прайми до четвертих, які ще не оцінені, зберігає їх, а решта залишатиметься неціненою, зберігається як спосіб їх обчислити один раз потрібні.

зауважте, що все це вільно дається ледачим характером мови Haskell, нічого з цього не видно з самого коду.

обидві версії програми перевантажені, тому вони можуть обробляти дані довільного розміру.


По моєму рахунку, ваше перше рішення - це фактично 77 символів: D
убивчий

я порахував нові рядки, чи не так?
гордий haskeller

Я рахую 74 регулярних персонажа та 3 нові рядки
вбивчий

Ви маєте рацію, здається, що чомусь блокнот ++ додає символи до нових рядків. Спасибі!
гордий haskeller

тому я використовую піднесене;) радий допомогти!
убивчий

9

C, 149 118 символів

Відредагована версія (118 символів):

int G(int a,int b){a=abs(a);b=abs(b);int n=a*b?a*a+b*b:a+b,
d=2;for(;n/d/d&&n%d;d++);return n/d/d|n<2?0:(a+b&3)>2|a*b;}

Це одна функція:

  • G ( a , b ) повертає ненульове значення (true), якщо a + bi є простим гауссом, або нуль (false) в іншому випадку.

Це складе ціле тест первинності на вираз, n/d/d|n<2прихований у обчисленні повернення. Цей гольф-код також використовує a*bяк заміну a&&b(іншими словами a!=0 && b!=0) та інші хитрощі, що передбачають пріоритет оператора та ціле ділення. Наприклад n/d/d, це коротший спосіб висловлювання n/d/d>=1, який є безпечним для переповнення способом висловлювання n>=d*dабо d*d<=nабо по суті d<=sqrt(n).


Оригінальна версія (149 символів):

int Q(int n){int d=2;for(;n/d/d&&n%d;d++);return n/d/d||n<2;}
int G(int a,int b){a=abs(a);b=abs(b);return!((a|b%4<3|Q(b))*(b|a%4<3|Q(a))*Q(a*a+b*b));}

Функції:

  • Q ( n ) повертає 0 (false), якщо n є простим, або 1 (true), якщо n не є первинним. Це допоміжна функція для G ( a , b ).

  • G ( a , b ) повертає 1 (true), якщо a + bi є простим гауссом, або 0 (false) в іншому випадку.

Вибірка зразка (збільшення до 200%) для | a |, | б | ≤ 128:

Sample128


2
+1 для зображення! Чи можете ви також зробити один приблизно такого ж розміру лише в першому квадранті (тому що симетрія), він тут справді чудово виглядає =)
flawr

Ви можете зберегти пару символів, замінивши d = 2; для (; n / d / d && n% d; d ++); з для (d = 2; n / d / d && n% d ++;);
Алхімік

@Alchymist - Це дійсно зберігає символи, але дає невірні результати. Важливо, щоб це d++не сталося як частина умови, інакше це псує логіку, наступну. Крім того, переміщення d=2всередину forциклу фактично збільшує кількість символів, а не зменшує його, оскільки dвсе-таки потрібно оголосити його як intдо forциклу. Я щось пропускаю?
Тодд Леман

Занадто вірно. Небезпечно дивитися на це подалі від кодуючого середовища і недостатньо близько. Збільшення повинно залишатися там, де воно є, і ініціалізація лише допомагає вашому оригінальному рішенню. Є очевидна економія, якщо ви оголошуєте n & d поза функцією, не вказуючи int, і ініціалізуєте їх у циклі for, але я припускаю, що ви робите функцію самостійною, що є суворою інтерпретацією вимог.
Алхімік

1
Перший цикл тестування тут - вражаючий гольф! Однак можна досягти ще більшої економії, скинувши специфікатори типу int для типу повернення та аргументів, використовуючи змінну для | a | + | б | та оптимізація оператора повернення: G(a,b){int s=abs(a)+abs(b),n=a*b?a*a+b*b:s,d=2;for(;n/d/d&&n%d;d++);return n>1>n/d/d&&s%4/3|a*b;}виходить всього 97 символів.
feersum

4

APL (Dyalog Unicode) , 36 47 48 49 47 43 28 байт

Бере масив з двох цілих чисел a bі повертає булеве значення оператора a+bi is a Gaussian integer.

Редагувати: +11 байт, тому що я неправильно зрозумів визначення прем'єра Гаусса. +1 байт, щоб повторно виправити відповідь. +1 байт від третього виправлення помилки. -2 байти за рахунок використання поїзда замість dfn. -4 байти завдяки ngn за рахунок використання гвардії condition: if_true ⋄ if_falseзамість if_true⊣⍣condition⊢if_false. -15 байт завдяки ngn завдяки пошуку зовсім іншого способу записати умову, якщо так, як повний потяг.

{2=≢∪⍵∨⍳⍵}|+.×0∘∊⊃|{⍺⍵}3=4||

Спробуйте в Інтернеті!

Пояснення

{2=≢∪⍵∨⍳⍵}|+.×0∘∊⊃|{⍺⍵}3=4||

                           |   abs(a), abs(b) or abs(list)
                       3=4|    Check if a and b are congruent to 3 (mod 4)
                  |{⍺⍵}        Combine with (abs(a), abs(b))
              0∘∊⊃             Pick out the original abs(list) if both are non-zero
                               Else pick out (if 3 mod 4)
          |+.×                 Dot product with abs(list) returns any of
                               - All zeroes if neither check passed
                               - The zero and the number that IS 3 mod 4
                               - a^2 + b^2
{2=≢∪⍵∨⍳⍵}                     Check if any of the above are prime, and return

3

Haskell - 121 знак (включені нові рядки)

Ось відносно просте рішення Haskell, яке не використовує жодних зовнішніх модулів і є таким чином, як я міг би отримати його.

a%1=[]
a%n|n`mod`a<1=a:2%(n`div`a)|1>0=(a+1)%n
0#b=2%d==[d]&&d`mod`4==3where d=abs(b)
a#0=0#a
a#b=2%c==[c]where c=a^2+b^2

Викликати як ghci ./gprimes.hsі тоді ви можете використовувати його в інтерактивній оболонці. Примітка: від’ємні числа є вибагливими і повинні бути розміщені в дужках. Тобто

*Main>1#1
True
*Main>(-3)#0
True
*Main>2#2
False

3

Пітон - 121 120 символів

def p(x,s=2):
 while s*s<=abs(x):yield x%s;s+=1
f=lambda a,b:(all(p(a*a+b*b))if b else f(b,a))if a else(b%4>2)&all(p(b))

pперевіряє, чи abs(x)є простим, повторюючи всі числа від 2 до abs(x)**.5(що є sqrt(abs(x))). Це роблять, поступаючись x % sкожному s. allпотім перевіряє, чи не всі нульові значення є нульовими, і припиняє генерувати значення, як тільки стикається з дільником x. В f, f(b,a)замінює справу на b==0, натхненну @killmous 'відповідь Haskell.


-1 char та помилка від @PeterTaylor


Радий, що можу допомогти :)
вбивчий

Ви могли б замінити s<abs(x)**.5з s*s<abs(x)для економії 2. Хоча на самому ділі ви повинні перевіряти <=, так що, ймовірно баггі в даний час .
Пітер Тейлор

@PeterTaylor Дякую за вказівку на помилку ...
hlt

Подзвонимо f(0,15)врожай TypeError: unsupported operand type(s) for &: 'bool' and 'generator'моєму перекладачеві. :(
Фалько

f(0,15)дає Falseдля мене, як на 2.7.6, так і на 3.4.1 (на ОС X). На якій версії ви працюєте?
hlt

3

Python 2.7 , 341 301 253 байт, оптимізований для швидкості

lambda x,y:(x==0and g(y))or(y==0and g(x))or(x*y and p(x*x+y*y))
def p(n,r=[2]):a=lambda n:r+range(r[-1],int(n**.5)+1);r+=[i for i in a(n)if all(i%j for j in a(i))]if n>r[-1]**2else[];return all(n%i for i in r if i*i<n)
g=lambda x:abs(x)%4>2and p(abs(x))

Спробуйте в Інтернеті!

#pRimes. need at least one for r[-1]
r=[2]
#list of primes and other to-check-for-primarity numbers 
#(between max(r) and sqrt(n))
a=lambda n:r+list(range(r[-1],int(n**.5)+1))
#is_prime, using a(n)
f=lambda n:all(n%i for i in a(n))
#is_prime, using r
def p(n):
    global r
    #if r is not enough, update r
    if n>r[-1]**2:
        r+=[i for i in a(n) if f(i)]
    return all(n%i for i in r if i*i<n)
#sub-function for testing (0,y) and (x,0)
g=lambda x:abs(x)%4==3 and p(abs(x))
#the testing function
h=lambda x,y:(x==0 and g(y)) or (y==0 and g(x)) or (x and y and p(x*x+y*y))

Спасибі: 40 +48 - цілий гольф Джо Кінгу


fЛямбда також uneccesary, поряд з listвикликом. 257 байт без цього, а також деяке видалення пробілу. Це, мабуть, вже не так ефективно
Джо Кінг,

(15,0) зараз вірно в 257-байтній версії, а час виконання також збільшився на 5,5 секунди, вибачте
Олексій Бурдін

2

Perl - 110 107 105 символів

Я сподіваюся, що я правильно дотримувався пов'язаного визначення ...

sub f{($a,$b)=map abs,@_;$n=$a**(1+!!$b)+$b**(1+!!$a);(grep{$n%$_<1}2..$n)<2&&($a||$b%4>2)&&($b||$a%4>2)}

Безголовки:

sub f {
  ($a,$b) = map abs, @_;
  $n = $a**(1+!!$b) + $b**(1+!!$a);
  (grep {$n%$_<1} 2..$n)<2 && ($a || $b%4==3) && ($b || $a%4==3)
}

Пояснення, тому що хто - то запитав: Я прочитав аргументи ( @_) і помістити їх абсолютні значення в $a, $b, тому що функція не потребує в їх знак. Кожен з критеріїв вимагає перевірити первинність числа, але це число залежить від того, $aчи $bдорівнює нулю, що я спробував виразити найкоротшим чином і ввести $n. Нарешті я перевіряю, чи $nє простим, підраховуючи кількість чисел між 2 і ділить його без залишку (це grep...<2частина), а потім перевіряю, що якщо одне з чисел дорівнює нулю, то інше дорівнює 3 модулю 4. Функція значення повернення за замовчуванням - це значення його останнього рядка, і ці умови повертають деяке трибунове значення, якщо всі умови були виконані.


Я не можу змусити його працювати за негативними параметрами.
убивчий

1
@killmous Ви маєте рацію, просто виправте це
Tal

ви можете пояснити алгоритм?
гордий haskeller

1
Приємно! До речі, я думаю, ви могли б поголити пару символів, написавши $a%4>2замість цього $a%4==3.
Тодд Леман

2

гольфлуа 147 141

Вищенаведений рахунок нехтує новинками, які я додав, щоб побачити різні функції. Незважаючи на наполягання цього не робити, я жорстоко намагаюся вирішувати праймери в межах справ.

\p(x)s=2@s*s<=M.a(x)?(x%s==0)~0$s=s+1$~1$
\g(a,b)?a*b!=0~p(a^2+b^2)??a==0~p(b)+M.a(b)%4>2??b==0~p(a)+M.a(a)%4>2!?~0$$
w(g(tn(I.r()),tn(I.r())))

Повертає 1, якщо вірно, і 0, якщо ні.

Нелюбова версія Луа,

-- prime number checker
function p(x)
   s=2
   while s*s<=math.abs(x) do
      if(x%s==0) then return 0 end
      s=s+1
   end
   return 1
end

-- check gaussian primes
function g(a,b)
   if a*b~=0 then
      return p(a^2+b^2)
   elseif a==0 then
      return p(b) + math.abs(b)%4>2
   elseif b==0 then
      return p(a) + math.abs(a)%4>2
   else
      return 0
   end
end


a=tonumber(io.read())
b=tonumber(io.read())
print(g(a,b))

Ви можете зберегти 6 символів, просто підключившись tonumber(io.read())як аргумент до gкінця, та ще 2, видаливши нові рядки
mniip

@mniip: нові рядки не враховувались, я просто додав ті, які були для ясності (немає бічного прокручування). Я оновлю прочитане в г, коли трохи попрацюю. Спасибі!
Кайл Канос

Добре це все-таки працює в розумний проміжок часу для великої кількості? Я в першу чергу думав про грубе посилення в способі перевірки всіх гауссових цілих чисел, aде |a| <= |z|якщо a | z(якщо aділиться z).
flawr

@flawr: Я перевірив його з a = 2147483644, b = 896234511 і отримав 0 приблизно за 0,002 с. Я також перевірив його з 2147483629 та 2147483587 (два дуже великих праймерів) і отримав 0 ще 0,002 с. Я намагаюся знайти велику пару чисел таким, що ^ 2 + b ^ 2 є простим і гарантую, що у мене є робоче рішення для таких великих чисел.
Кайл Канос

@flawr: Протестовано з a = 4600 & b = 5603 (a ^ 2 + b ^ 2 = 2147393609 є простим & <2 ^ 32-1), і повернутись було так само 0,002 секунди. Так!
Кайл Канос

1

APL (NARS), 99 символів, 198 байт

r←p w;i;k
r←0⋄→0×⍳w<2⋄i←2⋄k←√w⋄→3
→0×⍳0=i∣w⋄i+←1
→2×⍳i≤k
r←1

f←{v←√k←+/2*⍨⍺⍵⋄0=⍺×⍵:(p v)∧3=4∣v⋄p k}

тест:

  0 f 13
0
  0 f 9
0
  2 f 3
1
  3 f 4
0
  0 f 7
1
  0 f 9
0
  4600 f 5603
1  

1

Рунічні чари , 41 байт

>ii:0)?\S:0)?\:*S:*+'PA@
3%4A|'S/;$=?4/?3

Спробуйте в Інтернеті!

Закінчилося набагато простіше, ніж я думав, і було не так багато місця для гольфіфікації. Первісна програма, яку я заблокував:

>ii:0)?\S:0)?\:*S:*+'PA@
3%4A|'S/!   S/;$=

Я розігрувався, намагаючись порівняти обидва входи одночасно (що врятувало один один байт), але коли це потрапляє в розділ "один з них дорівнює нулю", не було вдалого способу визначити, який елемент було не нульовим для того, щоб виконати останню перевірку, набагато менше способу зробити це, не витрачаючи принаймні 1 байт (без загальної економії).


1

Математика, 149 символів

If[a==0,#[[3]]&&Mod[Abs@b,4]==3,If[b==0,#[[2]]&&Mod[Abs@a,4]==3,#[[1]]]]&[(q=#;Total[Boole@IntegerQ[q/#]&/@Range@q]<3&&q!=0)&/@{a^2+b^2,Abs@a,Abs@b}]

Код не використовує жодних стандартних простих чисельних функцій математики, замість цього він рахує кількість цілих чисел у списку {n / 1, n / 2, ..., n / n}; якщо число дорівнює 1 або 2, то n просте. Розроблена форма функції:

MyIsPrime[p_] := (q = Abs@p; 
  Total[Boole@IntegerQ[q/#] & /@ Range@q] < 3 && q != 0)

Бонусний сюжет усіх Гаусських праймів від -20 до 20:

Сюжет гауссових прайменів



0

Пітон - 117 122 121

def f(a,b):
 v=(a**2+b**2,a+b)[a*b==0]
 for i in range(2,abs(v)):
  if v%i<1:a=b=0
 return abs((a,b)[a==0])%4==3or a*b!=0

Оскільки 3 - це найбільше число, яке може бути мод 4, ви можете замінити його ==3на>2
FlipTack
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.