这是普罗斯数吗?


37

一个普罗斯数,弗朗索瓦·普罗斯命名,是可以表示为一个数

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不满意。

您面临的挑战非常简单:给定正整数,您必须编写一个程序或函数,确定该程序或函数是否是Proth数字。您可以采用任何合理的格式输入,如果输出是Proth值,则应输出真实值,如果不是,则应输出错误值。如果您的语言具有“ Proth-number detection”功能,则可以使用它们。

测试IO

以下是前1000个Proth的前46个数字。(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,恰好也是Proth数!

Answers:


41

果冻,5 个字节

’&C²>

在线尝试!验证所有测试用例

背景

j为严格的正整数。J + 1间切换的所有尾随组比特Ĵ和相邻的未设置位。例如,10011 2 +1 = 10100 2

由于〜j =-(j + 1)= -j-1-j =〜j + 1,因此-n将以上内容应用于j的按位NOT (这会切换所有位),从而切换最后一位之前的所有位1

通过采取J&-j -按位和Ĵ-j -所有位之前和之后的最后一组位被无效(因为不平等Ĵ-j),由此产生的最高功率2划分Ĵ均匀。

对于输入ñ,我们要应用上面N - 1找到2 ñ,最高功率2划分N - 1。如果m = N-1-m =-(N-1)= 1-N,那么(N-1)和(1- N)得出2 n

剩下要测试的是2 n > k。如果K> 0,这是真实的,当且仅当(2 Ñ2 > K2 Ñ,这是真的本身当且仅当(2 Ñ2 ≥K2 Ñ + 1 = N

最后,如果(2 n2 = N = k2 n +1,则2 n必须为奇数(1),以便双方的奇偶校验可以匹配,这意味着k = 0N = 1。在这种情况下(N - 1)&(1 - N)= 0&0 = 0((N - 1)&(1 - N))2 = 0 <1 = N

因此,当且仅当N为Proth数时,(((N-1)&(1-N))2 > 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间切换的所有尾随组比特Ĵ和相邻的未设置位。例如,10011 2 +1 = 10100 2

由于〜j =-(j + 1)= -j-1-j =〜j + 1,因此-n将以上内容应用于j的按位NOT (这会切换所有位),从而切换最后一位之前的所有位1

通过采取J&-j -按位和Ĵ-j -所有位之前和之后的最后一组位被无效(因为不平等Ĵ-j),由此产生的最高功率2划分Ĵ均匀。

对于输入ñ,我们要应用上面N - 1找到2 ñ,最高功率2划分N - 1。如果m = N-1-m =-(N-1)= 1-N,那么(N-1)和(1- N)得出2 n

剩下要测试的是2 n > k。如果K> 0,这是真实的,当且仅当(2 Ñ2 > K2 Ñ,这是真的本身当且仅当(2 Ñ2 ≥K2 Ñ + 1 = N

最后,如果(2 n2 = N = k2 n +1,则2 n必须为奇数(1),以便双方的奇偶校验可以匹配,这意味着k = 0N = 1。在这种情况下(N - 1)&(1 - N)= 0&0 = 0((N - 1)&(1 - N))2 = 0 <1 = N

因此,当且仅当N为Proth数时,(((N-1)&(1-N))2 > 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}

编辑:实际上,如果我窃取了丹尼斯的按位AND想法,我可以将其缩减为23 22 20字节。

Mathematica,23 22 20字节(感谢Simmons

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

2
欢迎来到编程难题和Code Golf!:)
Adnan

1
无需开始g=,纯函数就可以了!
西蒙斯(Simmons)

哦太好了。立即修复。
Michael Lee

顺便说一句,您的测试可以大大简化为Select[Range@1000,f]
numbermaniac

8

05AB1E14 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

@Emigna那是天才!谢谢 :)。
阿德南

7

脑高射炮460 350 270 266个 264 188 176字节

在线尝试!

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

说明

该程序将使用2和4的幂,直到找到比N-1大的2的幂。找到后,它使用模取二的幂来检查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。Falsy是0或输出为空。(唯一产生空输出的输入是12;其余输入产生01)。

在线尝试!

说明

x表示输入。设y为2的最大幂,除以x -1,然后z =(x -1)/ y。请注意,z自动为奇数。那么,当且仅当y > z时x才是Proth数;或者当y 2 > x -1时,x是等值的。

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

Brachylog,28个字节

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

在线尝试!

一次验证所有测试用例。 (稍作修改。)

说明

Brachylog是Prolog的派生产品,擅长证明事物。

在这里,我们证明这些事情:

>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

编辑:感谢nimi,现在46个字节

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

4
欢迎来到编程难题和代码高尔夫球!
丹尼斯

谢啦!在这里潜伏了一段时间。顺便说一句,果冻超级酷。希望我可以学习,但是a,我不太了解
X88B88 '16

2
一般提示:如果您只对通过理解创建的列表的长度感兴趣,可以使用sum[1| ... ]。在这里,我们可以继续进行,将相等性测试移至的前面,|并检查其中的or任何一项是否正确:f x=or[k*2^n+1==x|k<-...,n<-...,2^n>k]
nimi

哇。很棒的提示。我一定会修改的。
X88B88'8

2
如果您有兴趣学习Jelly,请查看Wiki或加入Jelly室
丹尼斯

5

ECMAScript正则表达式,48 43 41字节

Neil和H.PWiz的正则表达式(兼有ECMAScript风格)本身就很漂亮。还有另一种方式做到这一点,这是美丽整洁的巧合是1个字节超过尼尔的,现在用H.PWiz建议的高尔夫(谢谢!),1个字节比H.PWiz的少。

警告:尽管此正则表达式尺寸很小,但它包含一个主要的扰流板。我强烈建议学习如何通过独立地找出初始数学见解来解决ECMAScript正则表达式中的一元数学问题。对于我而言,这是一次引人入胜的旅程,对于那些可能想要自己尝试的人,尤其是对数字理论感兴趣的人,我都不想破坏它。请参阅此较早的帖子,以获取一系列连续扰流器标记的建议问题的列表,以逐一解决。

因此,如果您不想破坏一些高级一元正则表达式魔术,请不要再继续阅读。如果您确实想自己弄清楚该魔术,我强烈建议您先解决ECMAScript regex中的一些问题,如上面链接的那部分所述。

因此,此正则表达式的工作原理非常简单:首先减去一个正则表达式。然后找到最大的奇数因子k。然后,我们除以k(使用除法运算符regex post的一个用剧透标记的段落中简要解释的除法算法)。我们偷偷地同时做一个断言,即所得商数大于k。如果相符,我们有一个Proth编号;如果没有,我们就不会。

我能够使用格里米(Grimy)发现的技巧从此正则表达式(43→41)中删除2个字节,该技巧可以在确保商数大于或等于除数的情况下进一步缩短除法时间。

^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
O_o哇,只有48个字节
ASCII

尼尔是不是丹尼斯更多类似地雷
H.PWiz

4

朱莉娅,16个字节

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

感谢@Dennis提供答案和一些高尔夫技巧!


那不行 在Julia中,&优先级与相同*
丹尼斯,

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(在此处Px)除以2找到2^n等式的一部分k=(N-1)/2^n,然后离开,然后使用以下事实计算是否k低于等式2^n2^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,如果它是Proth数字,则返回1,否则返回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。凉!
Conor O'Brien

2

视网膜0.8.2,47字节

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

k·2n+1(2k±1)·2n+1+1k=1

\d+
$*

转换为一元。

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

转换为二进制。

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

反复反向运行Proth生成公式。

^10*1$

匹配Proth生成公式的基本情况。

编辑:我认为实际上有可能使用单个正则表达式将Proth数字与一元数字直接匹配。当前,这需要我47个字节,比我当前的Retina代码多7个字节,用于检查一元数是否是Proth数:

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

2

ECMAScript Regex,42个字节

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

在线尝试!(使用视网膜)

我本质上减去1,除以最大可能的奇数k,然后检查至少k+1剩下。

事实证明,我的正则表达式与尼尔回答结束时给出的正则表达式非常相似。我用x(xx)*代替(x*)\2x。我用一种较短的方法来检查k < 2^n


哇,太棒了!做得非常好。请注意,您可以通过更改(\3\3)*)$(\3\3)*$)
Deadcode

那个视网膜代码很好。我不知道$=$.=。它可以得到更好的改进
Deadcode

2
@Deadcode如果您要nitpick页眉和页脚,请进行一些进一步的改进
尼尔

@Neil看起来不错,但是很不幸,它似乎有一个错误。尝试单数。他们不工作。
死码

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

爪哇1.7,49 43个字节

多亏@charlie,才有6个字节的灰尘。

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'的尝试都将导致编译错误,因为不支持按位运算符,即float或doubles :(


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.*通话。只是不知道怎么做!谢谢!
MH。





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^nk=1,3,5..n=1,2,3..

随着n=1我们有一个k可供测试。随着我们的增加,n我们需要进行更多k's测试,如下所示:

n = 1; k = 1

n = 2; k = 1 k = 3

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

...

通过这些可能性的迭代,如果对于给定nk=1数字大于N并且没有其他迭代是匹配的,则可以确保N不是Prouth数。

因此,我的代码基本上可以“蛮力”找到N。

在阅读了其他答案并意识到您可以将N-1乘以2来找到n条件之后k<2^n,我认为使用该方法可以使我的代码更小,更高效。

值得一试!

测试了给定的所有数字和一些“非实数”数字。如果数字是Prouth数字,则函数返回1,否则返回0。


0

Javascript ES7,16个字节

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

我的Julia答案的端口,这是@Dennis的Jelly答案的端口。

感谢@Charlie保存2个字节!


n=x=>x-1&1-x>x**.5; n(3)给我0(实际上无论输入如何,它都给我0)
相当于

什么浏览器?可能就是这样。
Mama Fun Roll'8

n=x=>x-1&1-x>Math.pow(x,0.5); n(3)
Chrome52。Firefox48

好的-这是运算符的优先级。它必须是(x-1&1-x)因为没有它的运算符优先级实际上是:(x-1)&((1-x)>x**.5)
eithed

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回答 -这不是要发布的同类文章中的第一个,但它是我所看到的同类文章中的第一个。

不打高尔夫球

= 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遵循x86系统的标准System V调用约定,在寄存器中接受输入参数(无符号整数),并且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)

在线尝试!

这是一个非常简单的解决方案,并且在概念上类似于MegaTom的C版本。实际上,您可以使用C编写如下代码:

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

但是即使将机器代码设置为针对大小进行优化,上述机器代码也比从C编译器中获得的更好。

唯一的“欺骗”在这里返回-1作为“真实”值,返回0作为“虚假”值。该技巧允许使用2字节SBB指令而不是3字节SETB指令。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.