รากที่สองจำนวน


13

งานจะเป็นดังนี้: ให้เป็นจำนวนเต็มบวกxและนายกn > xเอาท์พุทจำนวนเต็มบวกที่เล็กที่สุดเช่นว่าy (y * y) mod n = xส่วนที่สำคัญของคำถามนี้คือการ จำกัด เวลาที่ระบุด้านล่างซึ่งไม่รวมการแก้ปัญหากำลังดุร้าย

ถ้าไม่มีค่าดังกล่าวแล้วรหัสของคุณควรเอาท์พุทyN

กรณีทดสอบ

(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
ดังนั้นภาษาที่ไม่สนับสนุนประเภทข้อมูลจำนวนเต็มขนาดใหญ่จะถูกตัดออก สงสาร
หลุยส์เมนโด

1
@LuisMendo ไม่ใช่ถ้าคุณสามารถเขียนรหัสการสนับสนุนสำหรับ1267650600228229401496703205653ตัวคุณเองหรือถ้าคุณมีการรองรับ 128 บิตเช่น__int128ใน gcc นอกจากนี้ยังมีไลบรารี int จำนวน 256 บิตสำหรับภาษาต่าง ๆ สุดท้ายภาษาจำนวนมากมีไลบรารี 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-พระสาทิสลักษณ์อัลกอริทึม ฉันเขียนโดยติดตามหน้า Wikipedia อย่างใกล้ชิด มันต้องใช้เวลาเป็น (n, p)input

การไม่มีรากที่สองจะถูกรายงานโดยข้อผิดพลาดต่อไปนี้:

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

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

แง่มุมที่ละเอียดอ่อนอย่างหนึ่งของ Pyth ที่ฉันใช้คือ=ซึ่งหากไม่ได้ตามด้วยตัวแปรทันทีค้นหาไปข้างหน้าในโปรแกรมสำหรับตัวแปรถัดไปจากนั้นกำหนดผลลัพธ์ของนิพจน์ต่อไปนี้ให้กับตัวแปรนั้นจากนั้นส่งคืนผลลัพธ์นั้น ฉันจะอ้างถึงคำอธิบายทั้งหมดในหน้าวิกิพีเดีย: อัลกอริทึม Tonelli-Shanksเนื่องจากเป็นอัลกอริทึมที่ฉันใช้

คำอธิบาย:

=eAQ

Aใช้ 2-tuple เป็นอินพุตและกำหนดค่าให้กับGและHตามลำดับและส่งคืนอินพุต Qเป็นอินพุตเริ่มต้น eส่งคืนองค์ประกอบสุดท้ายของลำดับ หลังจากข้อมูลโค้ดนี้Gเป็นnและHและมีการQp

M.^GHQ

Mกำหนดฟังก์ชั่น 2 การป้อนข้อมูลgที่ปัจจัยการผลิตที่มีและG เป็นฟังก์ชั่นการยกกำลังเร็วแบบแยกส่วนของ Pyth ข้อมูลโค้ดนี้กำหนดที่จะ modH.^gQ

Kf%=/H=2;1

fกำหนดการทำซ้ำจนกว่าจะวนซ้ำเท็จและส่งกลับจำนวนการวนซ้ำที่มันทำงานเพื่อรับ1เป็นอินพุต ในแต่ละรอบการวนซ้ำเราหารHด้วย 2 ตั้งค่าHเป็นค่านั้นและตรวจสอบว่าผลลัพธ์เป็นเลขคี่หรือไม่ เมื่อมันเป็นเราหยุด Kเก็บจำนวนการวนซ้ำที่ใช้

สิ่งหนึ่งที่ยุ่งยากมากคือ=2;บิต =ค้นหาตัวแปรถัดไปล่วงหน้าซึ่งคือTดังนั้นTถูกตั้งค่าเป็น 2 อย่างไรก็ตามTภายในfลูปคือตัวนับการวนซ้ำดังนั้นเราจึงใช้;เพื่อรับค่าTจากสภาพแวดล้อมโกลบอล สิ่งนี้ทำเพื่อบันทึกช่องว่างสองสามไบต์ที่อาจจำเป็นต้องแยกตัวเลข

หลังจากข้อมูลโค้ดนี้Kเป็นSบทความจากวิกิพีเดีย (วิกิพีเดีย) และHเป็นQจากวิกิพีเดียและเป็นT2

=gftgT/Q;1H

pตอนนี้เราต้องไปหาพอควรสม nonresidue เราจะดุร้ายโดยใช้เกณฑ์ออยเลอร์ /Q2is คือ(p-1)/2เนื่องจาก/เป็นส่วนที่แบ่งชั้นดังนั้นftgT/Q;1จะพบจำนวนเต็มแรกTที่T ^ ((p-1)/2) != 1ตามที่ต้องการ จำได้ว่า;ดึงอีกครั้งTจากสภาพแวดล้อมทั่วโลกซึ่งยังคงเป็น 2 ผลลัพธ์นี้มาzจากวิกิ

ถัดไปในการสร้างcจากวิกิพีเดียที่เราต้องz^Qดังนั้นเราจึงห่อดังกล่าวข้างต้นและกำหนดผลให้g ... H Tตอนนี้Tเป็นcจากวิกิพีเดีย

Jg~gGHh/H2

~gGHลองแยกออกจากนี้: ~เป็นเหมือน=แต่ส่งกลับค่าดั้งเดิมของตัวแปรไม่ใช่ค่าใหม่ ดังนั้นมันกลับGมาซึ่งnมาจากวิกิ

สิ่งนี้กำหนดJค่าของn^((Q+1)/2)ซึ่งRมาจาก wiki

ตอนนี้สิ่งต่อไปนี้จะมีผล:

~gGH

สิ่งนี้กำหนดGค่าn^Qซึ่งtมาจากวิกิ

ตอนนี้เราได้ตั้งค่าตัวแปรลูปของเราแล้ว จากวิกิพีเดียที่มีM, c, t, RK, T, G, J

ร่างกายของลูปนั้นซับซ้อนดังนั้นฉันจะนำเสนอด้วยช่องว่างตามที่ฉันเขียนไว้:

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

ก่อนอื่นเราตรวจสอบว่าGเป็น 1 หรือไม่ถ้าใช่เราออกจากลูป

รหัสถัดไปที่ทำงานคือ:

=Kfq1gG^2T1

ที่นี่เราค้นหาค่าแรกของiดังกล่าวว่าG^(2^i) mod Q = 1เริ่มต้นที่ 1. Kผลที่ได้จะถูกบันทึกไว้ใน

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

ที่นี่เราใช้ค่าเดิมของKลบค่าใหม่ของKลบ 1 ยก 2 ถึงอำนาจที่แล้วเพิ่มTไปพอควรอำนาจและจากนั้นกำหนดผลให้Q Tสิ่งนี้ทำให้Tเท่ากับbจากวิกิ

นี่เป็นบรรทัดที่ยุติลูปและล้มเหลวหากไม่มีวิธีแก้ปัญหาเนื่องจากในกรณีนั้นค่าใหม่ของKจะเท่ากับค่าเก่าของK2 จะถูกยกไปที่-1และการยกกำลังแบบแยกส่วนจะทำให้เกิดข้อผิดพลาด

=*J

ต่อไปเราจะทวีคูณJด้วยผลลัพธ์ข้างต้นและเก็บไว้ในที่JเดิมRอัปเดตอยู่เสมอ

=^T2

จากนั้นเรายกกำลังสองTและเก็บผลลัพธ์กลับมาTตั้งค่าTกลับcจากวิกิ

=%*G=^T2Q

จากนั้นเราก็คูณGโดยผลที่จะเอามัน mod และเก็บกลับผลในQG

;

และเรายุติลูป

หลังจากกว่าวงที่Jเป็นรากที่สองของmodn pเพื่อหาสิ่งที่เล็กที่สุดเราใช้รหัสต่อไปนี้:

hS%_BJ

_BJสร้างรายการJและการปฏิเสธของมัน%โดยปริยายใช้Qเป็นอาร์กิวเมนต์ที่สองและใช้พฤติกรรมเริ่มต้นของ 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? กลุ่มงูหลามโคดเดอร์?
วิศวกรที่กลับรายการ

@DaveBoltman Programming Puzzles & Code Golf
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 Johansen

@ ØrjanJohansenขอบคุณมาก! testCasesผมปรับคำตอบของฉันด้วยรหัสของคุณและแทนที่
2560

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