ตัวนับจำนวนเต็มทวีตที่เร็วที่สุด


17

งานคือการหาปัจจัยที่ไม่สำคัญของจำนวนประกอบ

เขียนโค้ดที่ค้นหาปัจจัยที่ไม่สำคัญของหมายเลขคอมโพสิตโดยเร็วที่สุดเท่าที่เป็นไปได้ภายใต้รหัสของคุณซึ่งมีความยาวไม่เกิน 140 ไบต์ ผลลัพธ์ควรเป็นปัจจัยที่คุณพบ

รหัสของคุณสามารถรับอินพุตและให้เอาต์พุตในวิธีที่สะดวกรวมถึงตัวอย่างเช่นอาร์กิวเมนต์ของฟังก์ชัน

กรณีทดสอบที่แสดงรายการปัจจัยทั้งหมด (คุณจะต้องส่งออกหนึ่งรายการเท่านั้น)

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 นาที

ถ้าคนสองคนได้คะแนนเท่ากันคำตอบแรกจะชนะ

ข้อ จำกัด

รหัสของคุณไม่สามารถใช้ฟังก์ชัน builtin หรือ library ที่ดำเนินการแยกตัวเป็นจำนวนเต็มได้ คุณสามารถสมมติว่าอินพุตใช้เวลาน้อยกว่า 256 บิต หมายเลขอินพุตทั้งหมดจะถูกรวม

ฉันจะใช้เวลาอย่างไร

ฉันจะรันtime ./myprogบนระบบ Ubuntu เพื่อกำหนดเวลาดังนั้นโปรดจัดหาโปรแกรมที่สมบูรณ์เพื่อให้ฉันใช้งานซึ่งรวมถึงฟังก์ชั่นที่คุณกำหนดไว้

หมายเหตุสำหรับภาษาที่รวบรวม

เวลารวบรวมจะต้องใช้เวลาไม่เกิน 1 นาทีบนเครื่องของฉัน

เป็นไปได้จริงหรือ

หากคุณเพิกเฉยต่อข้อ จำกัด ของพื้นที่ว่างแต่ละอันสามารถแยกตัวประกอบในเวลาน้อยกว่า 2 วินาทีบนคอมพิวเตอร์ของฉันโดยใช้รหัส Python + pypy อย่างแท้จริง

ดังนั้นอัลกอริทึมแฟคตอริ่งที่ไม่สำคัญคืออะไร

อัลกอริทึม Rho ของ Pollardนั้นรวดเร็วและเหมาะสำหรับการเล่นกอล์ฟ แน่นอนว่ายังมีวิธีอื่นอีกมากในการแยกจำนวนเต็มเช่นกัน

ได้เร็วขึ้นเป็นตะแกรงกำลังสอง ดูเหมือนจะเป็นความท้าทายที่ร้ายแรงที่จะบีบให้มีขนาด 140 ไบต์

คะแนนชั้นนำ

  • SEJPMโทษ 10 นาทีสำหรับกรณีทดสอบสุดท้าย + 16 วินาทีในHaskell

ดังนั้นเราอาจได้รับหมายเลขเป็น2 ** 1024อย่างไร
Conor O'Brien

@ ConorO'Brien คุณจะไม่ได้รับอะไรมากกว่าตัวเลขในกรณีทดสอบ

ดังนั้นในความแม่นยำไม่มีอะไรเกิน 256 บิต
Conor O'Brien

สำหรับอินพุตเช่น 4 เอาต์พุตควรเป็น2หรือ2, 2?
Mr. Xcoder

1
@AndersKaseorg ฉันได้อัปเดตคำถามตามคำแนะนำของคุณ ขอบคุณ

คำตอบ:


9

Haskell, 100 97 91 89 87 72 67 ไบต์

ลองออนไลน์!

-3 ไบต์ต้องขอบคุณ @flawr
-6 ไบต์ต้องขอบคุณ @flawr อีกครั้ง
-2 ไบต์ต้องขอบคุณ @flawr อีกครั้ง
-2 ไบต์ต้องขอบคุณชุดพารามิเตอร์ที่ได้รับการเพิ่มประสิทธิภาพ
-1 ไบต์ขอบคุณ @flawrs และอีกครั้งที่
-14 ไบต์ขอบคุณความต้องการ เพื่อส่งออกเพียงปัจจัยเดียว
-5 ไบต์ด้วย @AndersKaseorg

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 กรณีทดสอบแรกในเวลาที่ไม่สามารถสังเกตเห็นได้
นี่อาจเป็นการหมดเวลาสำหรับกรณีทดสอบที่ใหญ่ที่สุด

โดยทั่วไปแล้วสิ่งนี้จะคืนปัจจัยที่ไม่สำคัญในเวลาให้ตรงกับสัดส่วนรากที่สองของปัจจัยที่เล็กที่สุด
มันจะไม่ทำงานในทุกอินพุตเพราะมันไม่ได้เปลี่ยนแปลงพหุนามและการตรวจจับกรณีพิเศษนั้นยากที่จะทำใน 140 ไบต์
มันจะไม่ส่งผลการแยกตัวประกอบแบบเต็ม แต่จะเป็นปัจจัยที่ไม่ใช่เรื่องไร้สาระและการหารอินพุตด้วยปัจจัยนี้
นอกจากนี้ยังจะไม่เรียงลำดับปัจจัยตามขนาด

วิธีที่ใช้คือPollard-Rho-Factoringโดยมีค่าเริ่มต้นมาตรฐานเป็น 2 (โดยx^2+1ใช้พหุนามมาตรฐานครั้งเดียว) และค่าคงที่พหุนามที่ไม่ได้มาตรฐานเท่ากับ 7 (เพราะ1ไม่ได้ใช้กับ 1679) สำหรับการประเมินเพิ่มเติมทั้งหมด

โปรแกรมเต็มรูปแบบ ( 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.hs(ต้องghcติดตั้ง) ทำงานเป็น
$ ./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(ในประโยค "ที่" ประโยค " ) ได้เสมอเพื่อใช้ในการทดสอบ gcd g(รุ่น golfed ใช้มัด#) จากนั้นพยายามที่จะคำนวณปัจจัยที่ไม่ใช่เรื่องไร้สาระd(ในกรณีที่ประโยคในรุ่น un-golfed, in-line ใน Golfed หนึ่ง) เป็นความแตกต่างระหว่างทั้งสองอินพุตไปgถ้ามันประสบความสำเร็จกลับมาพูดว่าปัจจัย ลองอีกครั้ง ที่นี่มันอาจสร้างnเป็นผลลัพธ์หากa==bและดังนั้นจะส่งกลับเพียงปัจจัยเล็ก ๆ น้อย ๆ วิธีการที่เหมาะสมในการจัดการนี้จะแตกต่างกันค่าเริ่มต้นกับเหตุการณ์นี้หรือเปลี่ยนพหุนาม


|1<2=s a#(s$s b)จะถูกแทนที่ด้วย|c<-s b=s a#s cผมคิดว่า :) (ยังทำไมคุณไม่แสดงความTIOเชื่อมโยง?)
flawr

ฉันอัปเดตคำถามตามคำแนะนำความคิดเห็น ตอนนี้คุณเพียงแค่ส่งออกปัจจัยเดียวและรับประกันว่าตัวเลขจะประกอบกัน

3
PS: ทำไมเราถึงเล่นกอล์ฟนี่ไม่ใช่แม้แต่โค้ดกอล์ฟ
ข้อผิดพลาด

4
ตอนนี้คุณมี 53 ไบต์ที่จะใช้อัลกอริทึมแฟคตอริ่งที่ซับซ้อนยิ่งขึ้น :)

1
นอกจากนี้คุณสามารถนำออกabs ได้เนื่องจากbไม่ใช่ค่าลบเสมอ (บางทีคุณอาจหมายถึงabs$b-aแต่gcdยอมรับข้อโต้แย้งเชิงลบและสร้างผลลัพธ์ที่ไม่เป็นลบเสมอ) ซึ่งจะทำให้ทวีตทวีตน้อยกว่าครึ่ง!
Anders Kaseorg

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

Ungolfed:

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 algo สำหรับแฟคตอริ่งด้านล่างสิ่งที่จะคัดลอกในไฟล์สำหรับทดสอบบน 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 ได้ไหม? ฉันได้ติดตั้งสัจพจน์และสร้างไฟล์ชื่อ foo.ax พร้อมรหัสที่ไม่ใช่ของคุณ

@ Lembik 1) เปลี่ยนชื่อ fop.ax ใน foo.input 2) เรียกใช้ Axiom ในหนึ่งเทอร์มินัลหรือ xterm 3) เขียนใน Axiom terminal ว่าคำสั่ง follow ") อ่าน C: absolutepath \ foo" 4) เขียนใน terminal ของ Axiom เพื่อทดสอบการทำงาน () นี่คือวิธีการทำใน Windows ดูเหมือนว่าฉันจะเปิดหนึ่งเซสชัน Axiom และโหลดไฟล์ด้วยคำสั่ง ") read"
RosLuP

@ Lembik หากมีปัญหากับไฟล์ฉันคิดว่ามันก็โอเคเช่นกัน: 1) เรียกใช้ Axiom 2) เขียน) เวลาบน <return> ในโปรแกรม Axiom 3) คัดลอกวางและกดกลับในแต่ละ "copy paste" ในโปรแกรม Axiom: อาเรย์ vA, ฟังก์ชั่น p () และทดสอบ () 4) ในการทดสอบการเขียนโปรแกรม Axiom () <ย้อนกลับ>
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 หนึ่ง 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 3 , 100 99 bytes, 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

ลองออนไลน์!

ใช้ Pollard-Rho ด้วยค่าเริ่มต้น 2 และพหุนาม x ^ 2 + 1


คุณสามารถใช้pow(พร้อมอาร์กิวเมนต์ที่ 3) เพื่อปรับปรุงความเร็วในการดำเนินการของคุณ
mbomb007
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.