is_gaussian_prime (г)?


23

задача

Напишите функцию, которая принимает два целых числа, a,bкоторые представляют гауссово целое число z = a+ib(комплексное число). Программа должна возвращать true или false в зависимости от того, 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
Я добавил в статью определение гауссовых простых чисел. Если вам не нравится, как я это сделал, не стесняйтесь откатить его назад, но я определенно рекомендую включить определение где-нибудь.
подземный

Это хорошо, я изначально просто не хотел прямо указывать, как определить первичность для того, чтобы люди
проявили

1 1073741857 не кажется мне простым гауссовым штрихом, потому что 1 ^ 2 + 1073741857 ^ 2 - это одно четное число ...
RosLuP

Ответы:


4

Haskell - 77/108 107 символов

Использование: в обоих решениях ввод% b вернет, является ли a + 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).

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

обратите внимание, что все это дается свободно ленивой природой языка Haskell, ничего из этого не видно из самого кода.

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


По моим подсчетам, ваше первое решение на самом деле состоит из 77 символов: D
killmous

я считал новые строки, не так ли?
гордый haskeller

Я считаю 74 обычных персонажа и 3 символа новой строки
killmous

Вы правы, кажется, что по какой-то причине notepad ++ добавляет символы перед символами новой строки. Благодарность!
гордый 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;}

Это единственная функция:

  • грамм ( 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 ( а , b ) возвращает 1 (true), если a + bi - простое гауссово, или 0 (false) в противном случае.

Пример вывода (увеличен на 200%) для | |, | б | ≤ 128:

Sample128


2
+1 за изображение! Не могли бы вы также сделать один примерно такого же размера только в первом квадранте (потому что симметрия), он действительно выглядит великолепно здесь =)
flawr

Вы можете сохранить пару символов, заменив d = 2; for (; n / d / d && n% d; d ++); с for (d = 2; n / d / d && n% d ++;);
Алхимик

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

Слишком верно. Опасности смотреть на это вдали от среды программирования и недостаточно внимательно. Инкремент должен оставаться там, где он есть, и инициализация только помогает вашему первоначальному решению. Есть очевидная экономия, если вы объявляете n & d вне функции, не указывая int, и инициализируете их в цикле for, но я предполагаю, что вы делаете функцию автономной, что является строгой интерпретацией требований.
Алхимик

1
Цикл первичного тестирования - это захватывающая игра в гольф! Однако можно добиться еще большей экономии, удалив спецификаторы типа int для возвращаемого типа и аргументов, используя переменную для | a | + | b | и оптимизация оператора return: 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 благодаря нахождению совершенно другого способа записи условия if-else как полноценного поезда.

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


-1 символ и исправление от @PeterTaylor


Рад, что смог помочь :)
killmous

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

@PeterTaylor Спасибо, что указали на ошибку ...
Hlt

Колл f(0,15)дает TypeError: unsupported operand type(s) for &: 'bool' and 'generator'с моим переводчиком. :(
Фалько

f(0,15)дает Falseдля меня, как на 2.7.6 и 3.4.1 (на OS 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)}

Ungolfed:

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. Функция возвращаемое значение по умолчанию является значением его последней строки, и эти условия возвращают некоторое истинное значение, если все условия были выполнены.


Я не могу заставить его работать для отрицательных параметров.
killmous

1
@killmous ты прав, только что исправил
Тал

Можете ли вы объяснить алгоритм?
гордый haskeller

1
Ницца! Кстати, я думаю, что вы могли бы сбрить пару символов, написав $a%4>2вместо $a%4==3.
Тодд Леман

2

Golflua 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, если нет.

Версия Lua без роли,

-- 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: переводы строк не учитывались, я просто добавил их для ясности (без боковой прокрутки). Я скоро обновлю чтение в g, когда приступлю к работе. Благодарность!
Кайл Канос

Ну, это все еще работает в разумные сроки для больших количеств? Я прежде всего думал о брутфорсе путем проверки всех гауссовых целых чисел, aгде, |a| <= |z|если a | z(если aделит z).
flawr

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

@flawr: протестировано с a = 4600 & b = 5603 (a ^ 2 + b ^ 2 = 2147393609 - простое число & <2 ^ 32-1), и для возврата 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 байт (без общей экономии).


1

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

Код не использует никаких стандартных функций простых чисел mathematica, вместо этого он подсчитывает количество целых чисел в списке {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.