Это прот номер?


37

Номер Proth , названный в честь Франсуа Прот, это число , которое может быть выражено как

N = k * 2^n + 1

Где kнечетное положительное целое число и nтакое положительное целое число, что 2^n > k. Давайте использовать более конкретный пример. Возьмите 3. 3 - число Proth, потому что оно может быть записано как

(1 * 2^1) + 1

и 2^1 > 1доволен. 5 Это также число Proth, потому что оно может быть записано как

(1 * 2^2) + 1

и 2^2 > 1доволен. Тем не менее, 7 не число Proth потому что единственный способ записать его в виде N = k * 2^n + 1является

(3 * 2^1) + 1

и 2^1 > 3не устраивает.

Ваша задача довольно проста: вы должны написать программу или функцию, которая, с учетом положительного целого числа, определяет, является ли это число Протона или нет. Вы можете принимать входные данные в любом приемлемом формате и должны выводить истинное значение, если это число Протса, и ложное значение, если это не так. Если на вашем языке есть какие-либо функции «обнаружения числа протеза», вы можете их использовать.

Тест IO

Вот первые 46 чисел Proth до 1000. ( A080075 )

3, 5, 9, 13, 17, 25, 33, 41, 49, 57, 65, 81, 97, 113, 129, 145, 161, 177, 193, 209, 225, 241, 257, 289, 321, 353, 385, 417, 449, 481, 513, 545, 577, 609, 641, 673, 705, 737, 769, 801, 833, 865, 897, 929, 961, 993

Любой другой действительный ввод должен давать ложное значение.

Как обычно, это код-гольф, поэтому применяются стандартные лазейки, и выигрывает самый короткий ответ в байтах!


Дополнительная информация о теории чисел:

Самое большое известное простое число, которое не является Mersenne Prime 19249 * 2^13018586 + 1, и это тоже случай с числом Протса!

Ответы:


41

Желе , 5 байт

’&C²>

Попробуйте онлайн! или проверьте все контрольные примеры .

Задний план

Пусть j строго положительное целое число. j + 1 переключает все завершающие установленные биты j и соседний неустановленный бит. Например, 10011 2 + 1 = 10100 2 .

Так как ~ j = - (j + 1) = -j - 1 , -j = ~ j + 1 , то -n применяет вышеприведенное к побитовому НЕ для j (который переключает все биты), таким образом переключая все биты перед последним 1 .

Принимая j & -j - побитовое И для j и -j - все биты до и после последнего установленного бита обнуляются (поскольку они неравны по j и -j ), что дает наибольшую степень 2, которая делит j равномерно.

Для входа N мы хотим применить вышеупомянутое к N - 1, чтобы найти 2 n , наибольшую степень 2, которая делит N - 1 . Если m = N - 1 , -m = - (N - 1) = 1 - N , то (N - 1) & (1 - N) дает 2 n .

Все, что осталось проверить, это если 2 n > k . Если к> 0 , это справедливо тогда и только тогда , когда (2 л ) 2 > к2 п , что верно само по себе , если и только если (2 л ) 2 ≥ к2 п + 1 = N .

Наконец, если (2 n ) 2 = N = k2 n + 1 , 2 n должно быть нечетным ( 1 ), чтобы соотношения сторон могли совпадать, подразумевая, что k = 0 и N = 1 . В этом случае (N - 1) & (1 - N) = 0 & 0 = 0 и ((N - 1) & (1 - N)) 2 = 0 <1 = N .

Следовательно, ((N - 1) & (1 - N)) 2 > N истинно тогда и только тогда, когда N является числом Прота.

Как это работает

’&C²>  Main link. Argument: N

’      Decrement; yield N - 1.
  C    Complement; yield 1 - N.
 &     Take the bitwise AND of both results.
   ²   Square the bitwise AND.
    >  Compare the square to N.

во. это невероятно
Дон Яркий

46

Python, 22 байта

lambda N:N-1&1-N>N**.5

Это порт моего желе ответа . Проверьте это на Ideone .

Как это работает

Пусть j строго положительное целое число. j + 1 переключает все завершающие установленные биты j и соседний неустановленный бит. Например, 10011 2 + 1 = 10100 2 .

Так как ~ j = - (j + 1) = -j - 1 , -j = ~ j + 1 , то -n применяет вышеприведенное к побитовому НЕ для j (который переключает все биты), таким образом переключая все биты перед последним 1 .

Принимая j & -j - побитовое И для j и -j - все биты до и после последнего установленного бита обнуляются (поскольку они неравны по j и -j ), что дает наибольшую степень 2, которая делит j равномерно.

Для входа N мы хотим применить вышеупомянутое к N - 1, чтобы найти 2 n , наибольшую степень 2, которая делит N - 1 . Если m = N - 1 , -m = - (N - 1) = 1 - N , то (N - 1) & (1 - N) дает 2 n .

Все, что осталось проверить, это если 2 n > k . Если к> 0 , это справедливо тогда и только тогда , когда (2 л ) 2 > к2 п , что верно само по себе , если и только если (2 л ) 2 ≥ к2 п + 1 = N .

Наконец, если (2 n ) 2 = N = k2 n + 1 , 2 n должно быть нечетным ( 1 ), чтобы соотношения сторон могли совпадать, подразумевая, что k = 0 и N = 1 . В этом случае (N - 1) & (1 - N) = 0 & 0 = 0 и ((N - 1) & (1 - N)) 2 = 0 <1 = N .

Следовательно, ((N - 1) & (1 - N)) 2 > N истинно тогда и только тогда, когда N является числом Прота.

Игнорирование неточностей с плавающей запятой, это эквивалентно коду N-1&1-N>N**.5в реализации.


23
Я часто бываю на Math.SE, и мои глаза действительно хотят красивого LaTeX на этом сайте, а не похожи на сайт 90-х годов ...
qwr

Это мой любимый.
Qix


9

Mathematica, 50 48 45 40 38 35 31 29 байт

Mathematica, как правило, отстой, когда дело доходит до кода гольфа, но иногда есть встроенный, который делает вещи выглядеть действительно красиво.

1<#<4^IntegerExponent[#-1,2]&

Тест:

Reap[Do[If[f[i],Sow[i]],{i,1,1000}]][[2,1]]

{3, 5, 9, 13, 17, 25, 33, 41, 49, 57, 65, 81, 97, 113, 129, 145, 161, 177, 193, 209, 225, 241, 257, 289, 321, 353, 385, 417, 449, 481, 513, 545, 577, 609, 641, 673, 705, 737, 769, 801, 833, 865, 897, 929, 961, 993}

Редактировать: На самом деле, если я украду битовую идею Денниса И, я могу уменьшить ее до 23 22 20 байтов.

Mathematica, 23 22 20 байтов (спасибо Симмонс )

BitAnd[#-1,1-#]^2>#&

2
Добро пожаловать в программирование головоломок и Code Golf! :)
Аднан

1
Не нужно начинать с g=, чистая функция в порядке!
Симмонс

О сладкий. Исправлено сейчас.
Майкл Ли

Кстати, ваш тест может быть значительно упрощен до Select[Range@1000,f].
Числовой маньяк

8

05AB1E , 14 10 байт

Спасибо Emigna за сохранение 4 байта!

Код:

<©Ó¬oD®s/›

Использует кодировку CP-1252 . Попробуйте онлайн! ,

Объяснение:

Для пояснения воспользуемся номером 241 . Сначала мы уменьшаем число на единицу с <. Это приводит к 240 . Теперь вычислим простые множители (с дубликатами), используя Ò. Основными факторами являются:

[2, 2, 2, 2, 3, 5]

Мы разделили их на две части. Используя 2Q·0K, мы получаем список из двух:

[2, 2, 2, 2]

С помощью ®2Kмы получаем список оставшихся номеров:

[3, 5]

Наконец, возьмите продукт обоих. [2, 2, 2, 2]результаты в 16 . Произведение [3, 5]результатов в 15 .

Этот тест верен с 16 > 15 .


<©Ó¬oD®s/›или <DÓ0èoDŠ/›за 10.
Эминья

@ Emigna Это гений! Благодарность :).
Аднан

7

Brain-Flak , 460 350 270 266 264 188 176 байт

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

({}[()])(((<>()))){{}([(((({}<(({}){})>){}){})<>[({})(())])](<>)){({}())<>}{}<>{}{}<>(({})){{}{}<>(<(())>)}{}}(<{}{}>)<>{({}[()])<>(({}()[({})])){{}(<({}({}))>)}{}<>}{}<>({}<>)

объяснение

Программа проходит через степени двух и четырех, пока не найдет степень двух больше, чем N-1. Когда он находит его, он проверяет делимость N-1 на степень двух, используя модуль, и выводит результат

({}[()])      #Subtract one from input
(((<>())))    #Put three ones on the other stack
{
 {}           #Pop the crap off the top
 ([(
  ((({}<(({}){})>){}){}) #Multiply the top by four and the bottom by two
  <>[({})(())])](<>)){({}())<>}{}<>{}{}<>(({})){{}{}<>(<(())>)}{} #Check if the power of four is greater than N-1
}
(<{}{}>) #Remove the power of 4
<>{({}[()])<>(({}()[({})])){{}(<({}({}))>)}{}<>}{}<>({}<{}><>) #Modulo N-1 by the power of two

Эта программа не чистая в стеке. Если вы добавите дополнительные 4 байта, вы можете сделать его чистым:

({}[()])(((<>()))){{}([(((({}<(({}){})>){}){})<>[({})(())])](<>)){({}())<>}{}<>{}{}<>(({})){{}{}<>(<(())>)}{}}(<{}{}>)<>{({}[()])<>(({}()[({})])){{}(<({}({}))>)}{}<>}{}<>({}<{}><>)

5

MATL , 9 байт

qtYF1)EW<

Правдивый вывод есть 1. Ложь 0или пустой вывод. (Единственные входные данные, которые производят пустой вывод, являются 1и 2; остальные производят либо 0или 1).

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

объяснение

Пусть х обозначает вход. Пусть y будет наибольшей степенью 2, которая делит x − 1, и z = ( x − 1) / y . Обратите внимание, что z автоматически нечетно. Тогда x является числом Прота тогда и только тогда, когда y > z , или эквивалентно, если y 2 > x −1.

q    % Input x implicitly. Subtract 1
t    % Duplicate
YF   % Exponents of prime factorization of x-1
1)   % First entry: exponent of 2. Errors for x equal to 1 or 2
E    % Duplicate
W    % 2 raised to that. This is y squared
<    % Is x-1 less than y squared? Implicitly display

5

Брахилог , 28 байт

>N>0,2:N^P:K*+?,P>K:2%1,N:K=

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

Проверьте все тестовые случаи одновременно. (Слегка изменено.)

объяснение

Брахилог, будучи производным от Пролога, очень хорошо доказывает вещи.

Здесь мы докажем эти вещи:

>N>0,2:N^P:K*+?,P>K:2%1,N:K=

>N>0                           input > N > 0
     2:N^P                     2^N = P
         P:K*+?                P*K+1 = input
                P>K            P > K
                  K:2%1        K%2 = 1
                        N:K=   [N:K] has a solution

5

Haskell, 55 46 байтов

f x=length [x|k<-[1,3..x],n<-[1..x],k*2^n+1==x,2^n>k]>0

Редактировать: благодаря Ними, теперь 46 байтов

f x=or[k*2^n+1==x|k<-[1,3..x],n<-[1..x],2^n>k]

4
Добро пожаловать в Программирование Пазлов и Code Golf!
Деннис

Спасибо чувак! Некоторое время прятался здесь. Большой поклонник между прочим, желе очень круто. Хотелось бы мне учиться, но, увы, я не совсем понимаю
X88B88

2
Общий совет: если вы просто заинтересованы в длине списка, созданного пониманием, вы можете использовать sum[1| ... ]. Здесь мы можем пойти дальше и двигаться тест равенства в передней части |и проверить с , orесли любой из них правда: f x=or[k*2^n+1==x|k<-...,n<-...,2^n>k].
Ними,

Вау. Отличные советы. Я обязательно пересмотрю.
X88B88

2
Если вы заинтересованы в изучении желе, загляните в вики или присоединитесь к комнате желе .
Деннис

5

ECMAScript Regex, 48 43 41 байт

Регулярные выражения Нейла и Х.П.Виза (оба также и на ECMAScript) прекрасны сами по себе. Существует еще один способ сделать это, что по довольно аккуратным совпадение было 1 байт больше , чем Нила, и теперь предложил играть в гольф H.PWiz в (спасибо!), Составляет 1 байт больше , меньше H.PWiz годов.

Предупреждение: Несмотря на небольшой размер этого регулярного выражения, он содержит основной спойлер . Я настоятельно рекомендую научиться решать унарные математические задачи в регулярном выражении ECMAScript, самостоятельно выясняя исходные математические идеи. Для меня это было увлекательное путешествие, и я не хочу испортить его тем, кто потенциально может попробовать его сами, особенно тем, кто интересуется теорией чисел. См. Этот более ранний пост для списка последовательно рекомендованных спойлером рекомендованных проблем, чтобы решить одну за другой.

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

Таким образом, это регулярное выражение работает довольно просто: оно начинается с вычитания одного. Тогда он находит самый большой нечетный фактор, k . Затем мы делим на k (используя алгоритм деления, кратко объясненный в помеченном спойлером абзаце моего поста регулярных выражений факторных чисел ). Мы украдкой делаем одновременное утверждение, что результирующее отношение больше k . Если деление совпадает, у нас есть номер Proth; если нет, то нет.

Мне удалось отбросить 2 байта из этого регулярного выражения (43 → 41), используя уловку, найденную Гримми, которая может еще больше сократить деление в случае, когда коэффициент гарантированно будет больше или равен делителю.

^x(?=(x(xx)*)\1*$)((\1x*)(?=\1\4*$)x)\3*$

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


 # Match Proth numbers in the domain ^x*$
 ^
 x                         # tail = tail - 1
 (?=(x(xx)*)\1*$)          # \1 = largest odd factor of tail
 
 # Calculate tail / \1, but require that the quotient, \3, be > \1
 # (and the quotient is implicitly a power of 2, because the divisor
 # is the largest odd factor).
 (                         # \3 = tail / \1, asserting that \3 > \1
     (\1x*)                # \4 = \3-1
     (?=\1\4*$)            # We can skip the test for divisibility by \1-1
                           # (and avoid capturing it) because we've already
                           # asserted that the quotient is larger than the
                           # divisor.
     x
 )
 \3*$
 


1
О_о вау, только 48 байтов
только ASCII

Нил больше похож на мой, чем на Денниса
Х.П. Виз

4

Юлия, 16 байт

!x=~-x&-~-x>x^.5

Кредиты @Dennis для ответа и несколько советов по гольфу!


Это не работает У Юлии &такой же приоритет, как и у *.
Деннис

1
О верно. Исправлено: PI должен действительно проверить мой код.
Mama Fun Roll

2
Вы можете использовать -~-xвместо (1-x). Кроме того, есть √xвместо x^.5, но это не сохраняет байтов.
Деннис

4

R, 52 50 байт

x=scan()-1;n=0;while(!x%%2){x=x/2;n=n+1};2^(2*n)>x

Программа начинается с деления N-1(называемого здесь Pи x) 2как можно дольше для того, чтобы найти 2^nчасть уравнения, оставляя k=(N-1)/2^n, а затем вычисляя, не kуступает ли оно 2^n, используя тот факт, что2^n>x/2^n <=> (2^n)²>x <=> 2^2n>x


1
Вы можете вытащить P=в начале, изменить конец 2^n>xи сохранить как 5 или 6 байтов
user5957401

4

Регулярное выражение (ECMAScript), 40 38 байт

-2 байта благодаря Deadcode

^x(?=((xx)+?)(\1\1)*$)(?!(\1x\2*)\4*$)

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

Комментируемая версия:

# Subtract 1 from the input N
^x

# Assert N is even.
# Capture \1 = biggest power of 2 that divides N.
# Capture \2 = 2.
(?=((xx)+?)(\1\1)*$)

# Assert no odd number > \1 divides N
(?!(\1x\2*)\4*$)

Вау, это очень круто. Так много разных способов решить эту проблему!
Deadcode

1
38 байт: ^x(?=((xx)+?)(\1\1)*$)(?!(\1x\2*)\4*$)( Попробуйте онлайн )
Deadcode

2

J, 10 байт

%:<<:AND-.

На основе побитового решения @Dennis .

Принимает входные данные nи возвращает 1, если это число Proth, иначе 0.

использование

   f =: %:<<:AND-.
   f 16
0
   f 17
1
   (#~f"0) >: i. 100  NB. Filter the numbers [1, 100]
3 5 9 13 17 25 33 41 49 57 65 81 97

объяснение

%:<<:AND-.  Input: n
        -.  Complement. Compute 1-n
   <:       Decrement. Compute n-1
     AND    Bitwise-and between 1-n and n-1
%:          Square root of n
  <         Compare sqrt(n) < ((1-n) & (n-1))

Да. Я не знал о AND. прохладный!
Конор О'Брайен

2

Сетчатка 0.8.2 , 47 байт

\d+
$*
+`(1+)\1
$+0
01
1
+`.10(0*1)$
1$1
^10*1$

К·2N+1(2К±1)·2N+1+1Кзнак равно1

\d+
$*

Преобразовать в одинарный.

+`(1+)\1
$+0
01
1

Преобразовать в двоичный файл

+`.10(0*1)$
1$1

Повторно запустить формулу поколения Proth в обратном порядке.

^10*1$

Соответствуйте базовому случаю формулы поколения Proth.

Редактировать: я думаю, что на самом деле можно сопоставить число Прота непосредственно с одинарным числом с одним регулярным выражением. В настоящее время это занимает 47 байтов, что на 7 байтов больше, чем мой текущий код Retina, для проверки, является ли унарное число протовым числом:

^.(?=(.+?)(\1\1)*$)(?=((.*)\4.)\3*$).*(?!\1)\3$

2

ECMAScript Regex, 42 байта

^x(?=(x(xx)*)\1*$)(?=(x+?)((\3\3)*$))\4\1x

Попробуйте онлайн! (С помощью Retina)

По сути, я вычитаю 1, делю на максимально возможное нечетное число k, затем проверяю, k+1осталось ли хотя бы меньше .

Оказывается, мое регулярное выражение очень похоже на то, которое Нил дает в конце своего ответа . Я использую x(xx)*вместо (x*)\2x. И я использую более короткий метод, чтобы проверитьk < 2^n


Вау, это круто! Очень красиво сделано. Обратите внимание, что вы можете сделать это немного быстрее, перейдя (\3\3)*)$на(\3\3)*$)
Deadcode

Хорошая работа с этим кодом Retina. Я не знал о $=и $.=. Это может быть улучшено даже лучше .
Deadcode

2
@Deadcode Если вы собираетесь придираться к верхнему и нижнему колонтитулам, внесите некоторые улучшения .
Нил

@Neil Это похоже на хороший гольф, но, к сожалению, похоже, есть ошибка. Попробуйте отдельные числа . Они не работают
Deadcode

1
@Deadcode Извините, я не понял, что отдельные числа были частью "спецификации".
Нил

2

Brain-Flak , 128 байт

({<{({}[()]<(([{}]())<>{})<>>)}{}>{{}(<>)}{}}<><(())>){([()]{}<(({}){})>)}{}([({}[{}(())])](<>)){({}())<>}{}{((<{}>))<>{}}{}<>{}

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

Я использовал совсем другой алгоритм, чем старое решение Brain-Flak .

По сути, я делю на 2 (округляя вверх), пока не достигну четного числа. Затем я просто сравниваю результат последнего деления с двумя с степенью числа раз, которое я разделил.

Объяснение:

({
  # (n+1)/2 to the other stack, n mod 2 to this stack
  <{({}[()]<(([{}]())<>{})<>>)}{}>
  # if 1 (n was odd) jump to the other stack and count the one
  {{}(<>)}{}
#end and push the sum -1, with a one under it
}<>[(())])
#use the one to get a power of two
{([()]{}<(({}){})>)}{}
#compare the power of two with the remainder after all the divisions
([({}[{}(())])](<>)){({}())<>}{}{((<{}>))<>{}}{}<>{}

1

Клен, 100 байт (включая пробелы)

IsProth:=proc(X)local n:=0;local x:=X-1;while x mod 2<>1 do x:=x/2;n:=n+1;end do;is(2^n>x);end proc:

Хорошо разнесены для удобства чтения:

IsProth := proc( X )
    local n := 0;
    local x := X - 1;
    while x mod 2 <> 1 do
        x := x / 2;
        n := n + 1;
    end do;
    is( 2^n > x );
end proc:

Та же идея, что и у нескольких других; делите X на 2 до тех пор, пока X не перестанет делиться равномерно на 2, затем проверьте критерии 2 ^ n> x.


1

Java 1.7, 49 43 байта

Еще 6 байт пыли благодаря @charlie.

boolean g(int p){return p--<(p&-p)*(p&-p);}

Попытайся! (ideone)

Два пути, одинаково длинные. Как и с большинством ответов здесь, кредиты идут на @Dennis, конечно, для выражения.

Взяв корень правой части выражения:

boolean f(int p){return(p-1&(1-p))>Math.sqrt(p);}

Применяя степень два к левой части выражения:

boolean g(int p){return Math.pow(p-1&(1-p),2)>p;}

Может сбрить один байт, если положительному числовому значению разрешено представлять «истину», а отрицательному значению «ложь»:

double g(int p){return Math.pow(p-1&(1-p),2)-p;}

К сожалению, из-за «сужения примитивного преобразования» нельзя просто написать это на Java и получить правильные результаты:

((p - 1 & (1 - p))^2) > p;

И любая попытка расширить 'p' приведет к ошибке компиляции, потому что побитовые операторы не поддерживаются, то есть с плавающей запятой или с двойными числами :(


1
f = 47:boolean f(int p){return Math.sqrt(p--)<(p&-p);}
Чарли

1
g = 43:boolean g(int p){return p--<(p&-p)*(p&-p);}
Чарли

Хороший! Я знал, что должен быть способ избавиться от Math.*звонков; просто не мог понять как! Благодарность!
МХ.





0

C (137 байт)

int P(int N){int x=1,n=0,k=1,e=1,P=0;for(;e;n++){for(x=1,k=1;x&&x<N;k+=2){x=2<<n;x=x>k?x*k+1:0;if(x>N&&k==1)e=0;}if(x==N)P=1;}return P;}

Только пришел, чтобы прочитать ответы после того, как я попробовал.

Учитывая N=k*2^n+1с условием k<2^n(k=1,3,5.. иn=1,2,3..

У n=1нас есть один kдоступный для тестирования. По мере увеличения nмы получим еще несколько k'sтестов следующим образом:

n = 1; к = 1

n = 2; k = 1 k = 3

n = 3; k = 1 k = 3 k = 5 k = 7

...

Перебор этих возможностей мы можем быть уверены , что N не является числом Prouth если для данного полученное число больше , чем N , и никакая другая итерация не был матч.nk=1

Таким образом, мой код в основном "грубой силы", чтобы найти N.

После прочтения других ответов и понимания того, что вы можете вычислить N-1 с помощью 2, чтобы найти, nа затем сделать условие k<2^n, я думаю, мой код мог бы быть меньше и эффективнее при использовании этого метода.

Это стоило попробовать!

Проверены все приведенные числа и несколько «нерутовых» чисел. Функция возвращает 1, если число является числом Прута, и 0, если это не так.


0

Javascript ES7, 16 байт

x=>x--<(-x&x)**2

Порт моего ответа Джулии, который является портом ответа Jelly @ Dennis's.

Спасибо @Charlie за 2 сохраненных байта!


n=x=>x-1&1-x>x**.5; n(3)дает мне 0(на самом деле это дает мне 0 независимо от ввода)
Eited

Какой браузер? Это может быть просто так.
Mama Fun Roll

Chrome 52. Firefox 48 дает тот же ответn=x=>x-1&1-x>Math.pow(x,0.5); n(3)
eithed

Хорошо - это приоритет оператора. Должно быть так, (x-1&1-x)как без него приоритет оператора на самом деле:(x-1)&((1-x)>x**.5)
вышло

1
-1 байт: x=>x--**.5<(x&-x)илиx=>x**.5<(--x&-x)
Чарли


0

чернила , 60 байт

=p(n)
~n-=n>1
~temp x=1
-(k){n%2:{n<x}->->}
~x+=x
~n=n/2
->k

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

На основе ответу @ DSkoog на Maple, он был не первым в своем роде, но и первым в своем роде, который я увидел.

Ungolfed

= is_proth(number) =

/* It's easy to check if a number is one less than a Proth number.
   We take the number and divide it by 2 until we can't.
   Once we can't, we've found the smallest possible "k".
   If we also keep track of how many times we divided, we have our corresponding "2^n"
   All we have to do then is compare those
*/

~ number -= (number > 1)            // So, we first subtract one. Except this implementation won't ever halt for 0, so we don't subtract if the input is 1 (this is fine since the desired outputs for inputs 1 and 2 are the same)
~ temp power_of_two = 1             // We declare a variable to store our "2^n"
- (check)
  {
  - number % 2:                     // Once we can't divide by 2 anymore, we've found the smallest possible "k"
    {number < power_of_two}         // At that point, we print whether it's smaller than the "2^n" we found
    ->->                            // And then we return to where we were called from
  }

  ~ number = number / 2             // We keep dividing by 2 until we can't.
  ~ power_of_two += power_of_two    // and update our "2^n" as we go
-> check

0

Машинный код x86, 15 байт

4F 89 F8 F7 D8 21 F8 0F AF C0 39 C7 19 C0 C3

Эти байты определяют функцию, которая принимает входной аргумент (целое число без знака) в EDIрегистре, следуя стандартному соглашению о вызовах System V для систем x86, и возвращает результат в EAXрегистр, как все соглашения о вызовах x86.

В мнемонике ассемблера:

4F          dec   edi            ; input -= 1
89 F8       mov   eax, edi       ; \ temp
F7 D8       neg   eax            ; |      =
21 F8       and   eax, edi       ; /        (input & -input)
0F AF C0    imul  eax, eax       ; temp *= temp
39 C7       cmp   edi, eax       ; set CF if (input < temp)
19 C0       sbb   eax, eax       ; EAX = -CF
C3          ret                  ; return with result in EAX
                                 ;  (-1 for Proth number; 0 otherwise)

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

Это довольно простое решение - концептуально похожее на C-версию MegaTom . На самом деле, вы можете написать это в C как что-то вроде следующего:

unsigned IsProthNumber(unsigned input)
{
    --input;
    unsigned temp  = (input & -input);
    temp          *= temp;
    return (input < temp) ? -1 : 0;
}

но машинный код выше лучше, чем тот, который вы получите от компилятора Си, даже если он настроен на оптимизацию по размеру.

Единственный «чит» здесь возвращает -1 как «истинное» значение и 0 как «ложное» значение. Этот прием позволяет использовать 2-байтовую SBBинструкцию, а не 3-байтовую SETBинструкцию.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.