最速のツイート可能な整数因数分解器


17

タスクは、合成数の重要な要素を見つけることです。

コードの長さが140バイトを超えないことを条件に、複合数の重要な要素をできるだけ早く見つけるコードを記述します。出力は、あなたが見つけた要素である必要があります。

コードは、たとえば関数の引数としてなど、便利な方法で入力を取得し、出力を提供できます。

すべての要因をリストするテストケース(出力する必要があるのは1つだけです)

187: 11 17
1679: 23 73
14369648346682547857: 1500450271 9576890767
34747575467581863011: 3628273133 9576890767
52634041113150420921061348357: 2860486313 5463458053 3367900313
82312263010898855308580978867: 264575131106459 311111111111113
205255454905325730631914319249: 2860486313 71755440315342536873 
1233457775854251160763811229216063007: 1110111110111 1000000000063 1111111999999
1751952685614616185916001760791655006749: 36413321723440003717 48112959837082048697

テストに興味があるかもしれない次の難しいテストケースであなたの答えを採点しません:

513231721363284898797712130584280850383: 40206835204840513073 12764787846358441471

スコア

スコアは、上記のすべてのテストケースを因数分解するための合計時間であり、因数分解に失敗するたびに10分のペナルティがあります(すべて最も近い秒に丸められます)。コードは他の整数でも機能するはずです。つまり、これらの答えをハードコーディングするだけではいけません。

10分後にコードを停止します。

2人が同じスコアを獲得した場合、最初の答えが勝ちます。

制限事項

コードでは、整数分解を実行する組み込み関数またはライブラリ関数を使用できません。入力は256ビット未満であると想定できます。すべての入力番号は合成されます。

どうやって時間を計るの?

私はtime ./myprog、Ubuntuシステムで文字通りタイミングを実行するので、定義した機能を含む完全なプログラムも実行してください。

コンパイルされた言語に関する注意

私のマシンでは、コンパイル時間は1分以内でなければなりません。

実際に可能ですか?

スペースの制約を無視すると、純粋なPythonコード+ pypyを使用して、コンピューター上でそれぞれ2秒未満でファクタリングできます。

それでは、非自明な因数分解アルゴリズムとは何ですか?

Pollardのrhoアルゴリズムは高速で、ゴルフに適しています。もちろん、整数因数分解する方法は他にもたくさんあります。

二次ふるいはさらに高速です。それを140バイトに圧縮することは、深刻な課題のようです。

一流のスコア

  • SEJPM、最後のテストケースの10分ペナルティ+ Haskellの 16秒

したがって、次のような番号が与えられ2 ** 1024ます。
コナーオブライエン

@ ConorO'Brienテストケースよりも桁数の多いものは与えられません。

したがって、精度の点では、256ビットにすぎません。
コナーオブライエン

4のような入力の場合、出力は2or 2, 2ですか?
ミスターXcoder

1
@AndersKaseorgあなたの提案に従って質問を更新しました。ありがとう。

回答:


9

Haskell、100 97 91 89 87 72 67バイト

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

@flawrのおかげで-3バイト
再び@flawrのおかげで-6バイト再び
@flawrのおかげで-2バイト
-2パラメータの最適化されたセットのおかげバイト
@flawrsおかげさらに別の時間-1バイトを
-14要件のおかげでバイト@AndersKaseorgのおかげで、1つのファクター-5バイトを出力するだけで
済みます

f n|let s x=mod(x*x+7)n;a#b|d<-gcd(b-a)n,d>1=d|c<-s b=s a#s c=5#s 5

これは、気付かないうちに最初の5つのテストケースで機能します。
これはおそらく最大のテストケースでタイムアウトになります。

一般に、これは通常、最小の因子の平方根に比例する時間で1つの重要な因子を返します。
多項式を変更せず、例外的なケースの検出を140バイトで行うのは難しいため、すべての入力で機能するわけではありません。
また、完全な因数分解を出力するのではなく、重要な因子とこの因子による入力の除算を出力します。
また、サイズで因子をソートしません。

使用される方法は、標準評価値2(標準多項式を1回適用)と非標準多項式定数係数7(1679で機能しなかったため)をすべての評価で使用するPollard-Rho-Factoringです。x^2+11

完全なプログラム(factor.hs):

import System.Environment(getArgs)

f n|let s x=mod(x*x+7)n;a#b|d<-gcd(b-a)n,d>1=d|c<-s b=s a#s c=5#s 5

main= do
      args <- getArgs
      print$f (read $ head args :: Integer)

としてコンパイル $ ghc factor.hsghcインストールが必要)。
として実行し$ ./factor <number>ます。

実行例:

$ ./factor 187
11

未ゴルフコード:

f n=g 5 (s 5)
   where s x=mod(x*x+7)n
         g a b = if d>1 then d else g(s a)(s(s b))
               where d=gcd(b-a)n

g初期値で呼び出すことにより、自明でない要因を計算します。多項式はここで2に事前に適用され、結果(5)に再適用されるため、g「where」節内の)入力は常にgcd-testに簡単に使用できます。g(ゴルフバージョンはinfixを使用します#)その後、非ゴルフファクターd(非ゴルフバージョンのwhere句で、ゴルフバージョンのインライン)を2つの入力間の差として計算しようとしgます。 、それ以外の場合は再試行します。ここでは、些細な要因のみを返すn場合に出力として生成される可能性がa==bあり、これを処理する適切なアプローチは、このイベントで開始値を変更するか、多項式を変更することです。


|1<2=s a#(s$s b)に置き換えることができ|c<-s b=s a#s cます:)(また:TIOリンクを投稿してみませんか?)
flawr

コメントの提案に従って質問を更新しました。これで、1つのファクターを出力するだけで、数値が合成されることが保証されます。

3
PS:なぜ私たちはゴルフをしているのですか、これはコードゴルフで
-flawr

4
さらに高度なファクタリングアルゴリズムを実装する53バイトがあります。

1
またabs b常に負ではないので、を取り出すこともできます。(おそらくを意味しますがabs$b-agcd負の引数を受け入れ、常に非負の結果を生成します。)これにより、これはツイートの半分以下になります!
アンデルスカセオルグ

6

Pari / GP、137バイト、最大5秒

GPの組み込み楕円曲線演算を使用する (およびいくつかの手に負えないパラメーター調整)の使用

ecm(n)=iferr(if(n%2==0,2,n%3==0,3,for(a=1,n,ellmul(ellinit(Mod([a,a^2-a-1],n)),[1,a],lcm([1..ceil(4^a^0.5)])))),e,gcd(n,lift(Vec(e)[3])))

ecmファクターを返す(はずの)関数です。オンラインでお試しください!

テスト:

ecm(n)=iferr(if(n%2==0,2,n%3==0,3,for(a=1,n,ellmul(ellinit(Mod([a,a^2-a-1],n)),[1,a],lcm([1..ceil(4^a^0.5)])))),e,gcd(n,lift(Vec(e)[3])))

{
ns = [
  187,
  1679,
  14369648346682547857,
  34747575467581863011,
  52634041113150420921061348357,
  82312263010898855308580978867,
  205255454905325730631914319249,
  1233457775854251160763811229216063007,
  1751952685614616185916001760791655006749
  ]
}

test(n) = {
    d = ecm(n);
    if (!(1<d && d<n && n%d==0), error(d));
    print(n, ": ", d)
}

apply(test, ns)

quit

ゴルフをしていない:

ecm(n) = {
  iferr(if(n%2 == 0, 2,
           n%3 == 0, 3,
           for(a = 1, n,
               /* x^3 + A*x + B = y^2 */
               E = ellinit(Mod([a, a^2-a-1], n)); /* [A, B] */
               x0 = [1, a]; /* [x, y] */
               B = ceil(4^a^0.5); /* ~ exp(sqrt(log(p))), p ~= exp(a) */
               print("a=", a, ", B=", B);
               ellmul(E, x0, lcm([1..B]))
              )
          ),
         ERR, gcd(n, lift(Vec(ERR)[3] /* = Mod(d, n) */)),
         errname(ERR)=="e_INV")
}

悲しいことに、要因2と3を処理するには多くのバイトを使用します。ステージ2の追加に使用できた可能性のあるバイト:

ecm(n)=iferr(for(a=1,n,Y=X=ellmul(E=ellinit(Mod([a,1],n)),[0,1],(B=ceil(4^a^0.5))!);for(z=0,9*B,Y=elladd(E,Y,X))),e,gcd(n,lift(Vec(e)[3])))

1

公理、137バイト9分

p(n:PI):PI==(j:=1;a:=3;s:=n^.2;repeat(b:=j:=nextPrime(j);repeat(b<s=>(b:=b*j);break);a:=powmod(a,b,n);d:=gcd(a-1,n);d>1 or j>n=>break);d)

p()関数のテスト用にファイルにコピーするものを以下に因数分解するためにp-1アルゴを実装する関数p()の上

-- one has to copy this below text in a file name for example file.input
-- in one window where there is Axiom one could write 
-- )read C:\absolutepathwherethereisthatfile\file
-- and call the function test()
-- test()
-- the first character of all function and array must be afther a new line "\n"
)cl all
)time on
vA:=[187,1679,14369648346682547857,34747575467581863011,52634041113150420921061348357,82312263010898855308580978867,205255454905325730631914319249,1233457775854251160763811229216063007, 1751952685614616185916001760791655006749]

p(n:PI):PI==(j:=1;a:=3;s:=n^.2;repeat(b:=j:=nextPrime(j);repeat(b<s=>(b:=b*j);break);a:=powmod(a,b,n);d:=gcd(a-1,n);d>1 or j>n=>break);d)

-- this would try to factor n with p-1 Pollard method
pm1(n:PI):PI==
   j:=1;a:=3;s:=n^.2
   repeat
      b:=j:=nextPrime(j)
      repeat(b<s=>(b:=b*j);break)
      a:=powmod(a,b,n)
      d:=gcd(a-1,n);d>1 or j>n=>break
   d

test()==(for i in 1..#vA repeat output [vA.i, p(vA.i)])

ここの結果:

(5) -> test()
   [187,11]
   [1679,73]
   [14369648346682547857,9576890767]
   [34747575467581863011,9576890767]
   [52634041113150420921061348357,2860486313]
   [82312263010898855308580978867,311111111111113]
   [205255454905325730631914319249,2860486313]
   [1233457775854251160763811229216063007,1111111999999]
   [1751952685614616185916001760791655006749,36413321723440003717]
                                                               Type: Void
                              Time: 496.78 (EV) + 53.05 (GC) = 549.83 sec

ubuntuのコマンドラインからこのコードを実行する方法を正確に説明してもらえますか?axiomをインストールし、ゴルフ以外のコードを含むfoo.axというファイルを作成しました。

@Lembik 1)foo.inputでfop.axの名前を変更します2)1つのターミナルまたはxtermでAxiomを実行します3)そのAxiomターミナルにフォローコマンド「)read C:absolutepath \ foo」を書き込みますtest()を機能させます。これはWindowsで行う方法です。1つのAxiomセッションを開き、「)read」コマンドでファイルをロードするように思える手がかり
RosLuP

1)Axiomを実行する2)Axiomプログラムで<return>に時間を書き込む3)Axiomプログラムの各「コピーペースト」でコピーペーストとリターンを押す:@Lembik配列vA、関数p()およびtest()4)Axiomプログラムのtest()<return>に書き込む
RosLuP

@Lembikだから何時間かかりますか?
RosLuP

1

公理、10分+ 31秒

A(a)==>a:=(a*a+7)rem n;z(n)==(p:=a:=b:=101;for i in 1..repeat(A(a);A(b);A(b);p:=mulmod(p,a-b,n);i rem 999<9=>(p:=gcd(p,n);p>1=>break));p)

z()は関数rho、1つの137バイト関数です。ungolfed z()およびrho()として呼び出します。gcd(0、n)= nであるため、ループは停止し、フェイルnに戻ります。

)time on    
rho(n)==
  p:=a:=b:=101
  for i in 1..repeat
          A(a);A(b);A(b)
          p:=mulmod(p,a-b,n)
          i rem 999<9=>(p:=gcd(p,n);p>1=>break)
  p

va1:=[187,1679,14369648346682547857,34747575467581863011,52634041113150420921061348357,82312263010898855308580978867,205255454905325730631914319249,1233457775854251160763811229216063007, 1751952685614616185916001760791655006749]
p1()==(for i in 1..#va1-1 repeat output [va1.i,z(va1.i)]) 

結果(z()は、最後の数値1751952685614616185916001760791655006749以外はすべて問題ありません(10分))

(6) -> p1()
   [187,17]
   [1679,23]
   [14369648346682547857,1500450271]
   [34747575467581863011,3628273133]
   [52634041113150420921061348357,2860486313]
   [82312263010898855308580978867,264575131106459]
   [205255454905325730631914319249,2860486313]
   [1233457775854251160763811229216063007,1111111999999]
                                                               Type: Void
                                 Time: 30.38 (EV) + 1.38 (GC) = 31.77 sec

(8) -> z(1679)
   (8)  23
                                                    Type: PositiveInteger
                                                              Time: 0 sec

0

Pythonの3100 99バイト、45 40 39秒間+ 10分のペナルティ

import math
def f(n):
 x=y=2;d=1
 while d<2:y=y*y+1;x,y=1+x*x%n,y*y%n+1;d=math.gcd(x-y,n)
 return d

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

初期値2および多項式x ^ 2 + 1のPollard-Rhoを使用します。


pow(3番目の引数とともに)を使用して、実行速度を向上させることができます。
mbomb007
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.