平方根の数


13

タスクは次のとおりです。正の整数xと素数を指定すると、などのn > x最小の正の整数を出力y(y * y) mod n = xます。この質問の重要な部分は、ブルートフォースソリューションを除外する、以下で指定される制限時間です。

そのような値がない場合y、コードは出力されますN

テストケース

(2, 5, N), 
(3, 5, N), 
(4, 5, 2),
(524291, 1048583, N),
(529533, 1048583, N),
(534775, 1048583, 436853),
(540017, 1048583, 73675),
(536870913, 1073741827, 375394238),
(542239622, 1073741827, 267746399),
(547608331, 1073741827, N),
(552977040, 1073741827, 104595351),
(1099511627676, 1099511627791, N),
(1099511627677, 1099511627791, 269691261521),
(1099511627678, 1099511627791, 413834069585),
(1267650600228229401496703204376, 1267650600228229401496703205653, 5312823546347991512233563776),
(1267650600228229401496703204476, 1267650600228229401496703205653, N)
(1267650600228229401496703204576, 1267650600228229401496703205653, N)
(1267650600228229401496703204676, 1267650600228229401496703205653, 79905476259539917812907012931)

入出力

入力を受け取り、便利な方法で出力を行うことができます。出力したくない場合はN、どのFalsey値でもかまいません。

制限事項

コードは、標準デスクトップで1分以内にすべてのテストケースに回答する必要があります。この制限時間はブルートフォースの回答を防ぐためだけのものであり、すぐに適切な回答が実行されることを期待しています。この問題を解決したり、数値が2次剰余であるかどうかをテストしたりするライブラリまたはビルトインを使用することはできません。


2
したがって、ビッグ整数データ型をサポートしない言語は除外されます。残念
ルイスメンドー

1
@LuisMendo 1267650600228229401496703205653自分用のサポートをコード化できる場合、または__int128gccのように128ビットのサポートがある場合ではありません。また、さまざまな言語用に256ビットのintライブラリが多数あります。最後に、多くの言語には任意精度のintライブラリがあります。

回答:


7

Pyth、83 82バイト

=eAQM.^GHQKf%=/H=2;1=gftgT/Q;1HJg~gGHh/H2WtG=*J=gT^2t-K=Kfq1gG^2T1=%*G=^T2Q;hS%_BJ

テストスイート

このプログラムは、Tonelli-Shanksアルゴリズムを実装しています。ウィキペディアのページを注意深く追って書いた。入力として受け取ります(n, p)

平方根がないことは、次のエラーによって報告されます。

TypeError: pow() 3rd argument not allowed unless all arguments are integers

これは、Pythのより一般的な機能スタイルとは対照的に、命令型スタイルで記述された非常に複雑なゴルフコードです。

私が使用しているPythの微妙な側面は=、変数が直後にない場合、プログラムで次の変数を前方に検索し、次の式の結果をその変数に割り当てて、その結果を返します。説明全体でウィキペディアのページを参照します:Tonelli-Shanks algorithmは、私が実装しているアルゴリズムです。

説明:

=eAQ

A入力として2組をとり、に値を代入Gし、Hそれぞれ、その入力を返します。Qは初期入力です。eシーケンスの最後の要素を返します。このスニペットの後、GnHおよびQですp

M.^GHQ

M2入力機能定義g入力があり、GそしてH.^Pythの高速モジュラーべき乗関数です。このスニペットはg、べき乗modを意味すると定義していQます。

Kf%=/H=2;1

f偽ループまでの繰り返しを定義1し、入力として指定された実行回数を返します。ループの各反復中にH、2で割っHてその値に設定し、結果が奇数かどうかを確認します。いったん終了すると、停止します。Kこれにかかった反復回数を保存します。

非常に難しいのは=2;ビットです。=検索先にある次の変数、についてはT、そうT、しかし2に設定されているT内部のf私たちが使用するので、ループが反復カウンタは、ある;の値を取得するためにT、地球環境からを。これは、数を区切るのに必要な空白を数バイト節約するために行われます。

このスニペットの後、KあるSWikipediaの記事(ウィキ)から、とHあるQウィキから、とTあります2

=gftgT/Q;1H

ここで、2次の非剰余modを見つける必要がありますp。オイラー基準を使用して、これをブルートフォースします。/Q2である(p-1)/2ので、/床の分割があるので、ftgT/Q;1最初の整数見つけ所望のように、。まだ2であるグローバル環境からプルすることを思い出してください。この結果はwikiからのものです。TT ^ ((p-1)/2) != 1;Tz

次に、cwiki から作成するにはが必要なz^Qので、上記をラップしg ... Hて結果をに割り当てTます。今Tcウィキからです。

Jg~gGHh/H2

これを分けましょう:~gGH~はに似て=いますが、新しい値ではなく、変数の元の値を返します。したがって、それは返しGである、nウィキから。

これJによりn^((Q+1)/2)RWikiからのの値が割り当てられます。

現在、以下が有効になります。

~gGH

これは、割り当てられGた値n^Qである、tウィキからを。

これで、ループ変数が設定されました。M, c, t, RウィキからはK, T, G, J

ループの本体は複雑であるため、記述したとおりに、空白を表示します。

WtG
  =*J
    =
      gT^2
        t-
          K
          =Kfq1gG^2T1
  =%*G=^T2Q;

まず、G1 かどうかを確認します。1の場合、ループを終了します。

次に実行されるコードは次のとおりです。

=Kfq1gG^2T1

ここでは、iなどのの最初の値を1から検索G^(2^i) mod Q = 1します。結果はに保存されKます。

=gT^2t-K=Kfq1gG^2T1

ここで、古い値を取得しK、新しい値をK減算し、1を減算し、2をそのべき乗し、次にTそのべき乗modしQ、結果をに割り当てTます。これは、WikiからのものTと同等にbなります。

これは、ループを終了し、解決策がない場合に失敗する行でもあります。その場合、新しい値のK古い値はK2に等しく-1なり、モジュラーべき乗はエラーを発生するためです。

=*J

次に、J上記の結果を乗算してJに保存し、R更新されたままにします。

=^T2

その後、我々は、正方形T内の結果背中や保存Tの設定、Tバックにcウィキからを。

=%*G=^T2Q

次にG、その結果を乗算し、それをmodにQして、結果をに戻しGます。

;

そして、ループを終了します。

ループが終了するJと、nmodの平方根になりpます。最小のものを見つけるには、次のコードを使用します。

hS%_BJ

_BJのリストJとその否定を作成し、%暗黙的にQ2番目の引数として受け取り、Pythのデフォルトの動作を使用し% ... Qてシーケンスの各メンバーに適用します。次にS、リストをソートし、h最初のメンバーである最小値を取得します。


11

Python 2、166バイト

def Q(x,n,a=0):
 e=n/2
 while pow(a*a-x,e,n)<2:a+=1
 w=a*a-x;b=r=a;c=s=1
 while e:
    if e%2:r,s=(r*b+s*c*w)%n,r*c+s*b
    b,c=(b*b+c*c*w)%n,2*b*c;e/=2
 return min(r,-r%n)

%timeit Q(1267650600228229401496703204676,1267650600228229401496703205653) 100 loops, best of 3: 2.83 ms per loop :)

3
なんて素晴らしい答えでしょう!あなたはPPCGに対する私の信仰を回復しました。

5
初心者の質問は失礼ですが、PPCGはどうですか?ポーランドのPython Coders Group?
リバースエンジニア

@DaveBoltmanプログラミングパズルとコードゴルフ。
orlp


3

Haskell、326バイト

通常、ブルートフォースの回答が好きです。これは制限時間によって強く推奨されないため、ここで最も効率的な方法を知っています。

r p=((\r->min(mod(-r)p)r)$).f p
f p x|p==2=x|q x=f 0 0|mod p 4==3=x&div(p+1)4|let(r,s)=foldl i(p-1,0)[1..t 1o]=m$x&(d$r+1)*(b&d s)where q a=1/=a&o;m=(`mod`p);a&0=1;a&e|even e=m$a&d e^2|0<1=m$(a&(e-1))*a;b=[n|n<-[2..],q n]!!0;i(a,b)_|m(x&d a*b&d b)==p-1=(d a,d b+o)|0<1=(d a,d b);o=d p;t y x|even x=t(y+1)(d x)|0<1=y;d=(`div`2)

オンラインでお試しください!

私はこれがさらに下にゴルフすることができると確信しています、しかし、これは今のところするべきです。


TIOコードを変更して、回答を出力として提供できますか?現時点では「真」になっています。


@Lembik testCasesオリジナルのTIOのものに置き換える必要があります。それらがなくてもコメントにはほとんど適合しません。
Ørjanヨハンセン

@ØrjanJohansenどうもありがとう!私はあなたのコードで私の答えを調整し、置き換えました testCases
ბიმო

ええと、そのTIOリンクに奇妙なバグがあります-クリックするとコードが表示されますが、メニューオプションからURLを実行したり取得したりすることはできません- しかし、アドレスバーからURLをコピーして別のタブ、それが動作します。
Ørjanヨハンセン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.