フェルマーの因数分解ヘルパー


19

半素数を因数分解したい。この課題の目標は、u v NをFermatの方法で簡単に因数分解できるように2つの小さな整数uvを見つけ、Nの因子を簡単に差し引くことです。NuvuvNN

タスク

素数と正の整数kが与えられた場合、xyを次のように定義します。Nkバツy

Y=X2-KN

バツ=kN
y=バツ2kN

ステップ#1- kを見つけるk

まず、y平方数別名完全平方)になるように、最小値を見つける必要があります。ky

これにより、フェルマーの因数分解法の 1回の反復でを因数分解できます。より具体的には、これはすぐにつながります:kN

kN=バツ+y×バツy

(更新:このシーケンスは現在A316780として公開されています

ステップ#2- kの因数分解k

次に、次のような2つの正の整数およびvを見つける必要があります。あなたはv

c u = x +

あなたはv=k
dはV=X-
cあなたは=バツ+y
dv=バツy

ここで、dNの素因数です。cdN

概要

あなたの仕事は、入力としてを取り、uvを任意の順序と妥当な形式で印刷または出力するプログラムまたは関数を書くことです。Nあなたはv

N = 199163を考えてみましょうN=199163

ステップ1

可能な最小値は40で、次のようになります。k40

y=2823240×199163=79693297966520=2809=532kN=2823+53×282353kN=2876

バツ=40×199163=2823
y=2823240×199163=79693297966520=2809=532
kN=(2823+53)×(282353)
kN=2876×2770

ステップ2

の正しい因数分解は、k = 4 ×です。kです。k=4×10

kN=2876×2770
kN=(719×4)×(277×10)
N=719×277

[4,10][10,4]

ルール

  • 上記の2つの手順を厳密に適用する必要はありません。正しい値を見つける限り、他の方法を自由に使用できます。uv
  • uvN
  • 入力はセミプライムであることが保証されています。
  • これはコードゴルフなので、バイト単位の最短回答が勝ちです。
  • 標準的な抜け穴は禁止されています。

テストケース

N          | k    | Output
-----------+------+------------
143        | 1    | [   1,  1 ]
2519       | 19   | [   1, 19 ]
199163     | 40   | [   4, 10 ]
660713     | 1    | [   1,  1 ]
4690243    | 45   | [   9,  5 ]
11755703   | 80   | [  40,  2 ]
35021027   | 287  | [   7, 41 ]
75450611   | 429  | [ 143,  3 ]
806373439  | 176  | [   8, 22 ]
1355814601 | 561  | [  17, 33 ]
3626291857 | 77   | [   7, 11 ]
6149223463 | 255  | [  17, 15 ]
6330897721 | 3256 | [  74, 44 ]

実装例

fNuv

gNuvNO(1


入力Nが実際にセミプライムになることが保証されていますか?
グレッグマーティン

@GregMartinはい、そうです。
アーナルド

回答:


8

Mathematica、 81 79バイト

2バイトを節約してくれたMartin Enderに感謝します!

(c=Ceiling;For[j=0;z=E,c@z>z,p=(x=c@Sqrt[j+=#])+{z=Sqrt[x^2-j],-z}];p/#~GCD~p)&

入力としてセミプライムを取り、正の整数の順序付きペアを返す純粋な関数。For正確な手順は、(使用して質問に記載のループ器具#の代わりに入力するためにn用いて、)x我々は保存するが、そこに定義した通りj = k*nの代わりにk、それ自体z=Sqrt[y]の代わりにy、それ自体。またp={x+z,x-z}Forループ内で計算し、最終的に1バイトを節約します(7回目の試行のように)。次に、2つの所望の因子である(x+z)/GCD[#,x+z](x-z)/GCD[#,x-z]簡潔な発現がどの、p/#~GCD~p順序付けられたペアとして直接計算します。

好奇心:zが整数になるまでループしたい。しかしCeiling、コードですでに使用するので、!IntegerQ@z定義するために2バイトを節約しc=Ceiling(Mathematicaゴルファーが知っているように4バイトのコストがかかります)、それからをテストしc@z>zます。zループを開始できるように、何かに初期化する必要があり、その何かは整数ではない方が良いでしょう。幸いEなことに、簡潔な選択です。


4

JavaScript(ES7)、86 81バイト

n=>(g=k=>(y=(n*k)**.5+1|0,y+=(y*y-n*k)**.5)%1?g(k+1):n*u++%y?g(k):[--u,k/u])(u=1)

編集:@Arnauldのおかげで4バイトを保存しました。


4

Python 2、127 121 117 111 107 104 101 99バイト

Neilのおかげで-1バイト、ovsのおかげで-3バイト

N=input()
k=u=1;p=m=.5
while p%1:p=1+(k*N)**m//1;p+=(p*p-k*N)**m;k+=1
while N*u%p:u+=1
print~-k/u,u

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

好奇心:

p.5、ループ条件が最初の反復で真になるように初期化されます。保存する方が短いことに注意してくださいpx + sqrt(y)がそれぞれを格納するよりも)xy別々 。


x*x代わりにx**2
ニール

@Neilはい、もちろんです。ありがとう
数学中毒

1

公理、 131 115バイト

v(x)==floor(x^.5)::INT;r(n)==(k:=0;repeat(k:=k+1;x:=1+v(k*n);y:=v(x*x-k*n);x^2-y^2=k*n=>break);[w:=gcd(k,x+y),k/w])

問題を解決する関数は上記のr(n)です。ウンゴルフとテスト

vv(x)==floor(x^.5)::INT    

--(x-y)*(x+y)=k*n
rr(n)==
  k:=0
  repeat
     k:=k+1
     x:=1+vv(k*n)
     y:=vv(x*x-k*n)
     x^2-y^2=k*n=>break
  [w:=gcd(k,x+y),k/w]


(4) -> [[i,r(i)] for i in [143,2519,199163,660713,4690243,11755703]]
   (4)
   [[143,[1,1]], [2519,[1,19]], [199163,[4,10]], [660713,[1,1]],
    [4690243,[9,5]], [11755703,[40,2]]]
                                                      Type: List List Any
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.