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รับสมาชิกรายแรกเป็นจำนวนต่ำสุด