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
และมีการQ
p
M.^GHQ
M
กำหนดฟังก์ชั่น 2 การป้อนข้อมูลg
ที่ปัจจัยการผลิตที่มีและG
เป็นฟังก์ชั่นการยกกำลังเร็วแบบแยกส่วนของ Pyth ข้อมูลโค้ดนี้กำหนดที่จะ modH
.^
g
Q
Kf%=/H=2;1
f
กำหนดการทำซ้ำจนกว่าจะวนซ้ำเท็จและส่งกลับจำนวนการวนซ้ำที่มันทำงานเพื่อรับ1
เป็นอินพุต ในแต่ละรอบการวนซ้ำเราหารH
ด้วย 2 ตั้งค่าH
เป็นค่านั้นและตรวจสอบว่าผลลัพธ์เป็นเลขคี่หรือไม่ เมื่อมันเป็นเราหยุด K
เก็บจำนวนการวนซ้ำที่ใช้
สิ่งหนึ่งที่ยุ่งยากมากคือ=2;
บิต =
ค้นหาตัวแปรถัดไปล่วงหน้าซึ่งคือT
ดังนั้นT
ถูกตั้งค่าเป็น 2 อย่างไรก็ตามT
ภายในf
ลูปคือตัวนับการวนซ้ำดังนั้นเราจึงใช้;
เพื่อรับค่าT
จากสภาพแวดล้อมโกลบอล สิ่งนี้ทำเพื่อบันทึกช่องว่างสองสามไบต์ที่อาจจำเป็นต้องแยกตัวเลข
หลังจากข้อมูลโค้ดนี้K
เป็นS
บทความจากวิกิพีเดีย (วิกิพีเดีย) และH
เป็นQ
จากวิกิพีเดียและเป็นT
2
=gftgT/Q;1H
p
ตอนนี้เราต้องไปหาพอควรสม nonresidue เราจะดุร้ายโดยใช้เกณฑ์ออยเลอร์ /Q2
is คือ(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, R
K, 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
จะเท่ากับค่าเก่าของK
2 จะถูกยกไปที่-1
และการยกกำลังแบบแยกส่วนจะทำให้เกิดข้อผิดพลาด
=*J
ต่อไปเราจะทวีคูณJ
ด้วยผลลัพธ์ข้างต้นและเก็บไว้ในที่J
เดิมR
อัปเดตอยู่เสมอ
=^T2
จากนั้นเรายกกำลังสองT
และเก็บผลลัพธ์กลับมาT
ตั้งค่าT
กลับc
จากวิกิ
=%*G=^T2Q
จากนั้นเราก็คูณG
โดยผลที่จะเอามัน mod และเก็บกลับผลในQ
G
;
และเรายุติลูป
หลังจากกว่าวงที่J
เป็นรากที่สองของmodn
p
เพื่อหาสิ่งที่เล็กที่สุดเราใช้รหัสต่อไปนี้:
hS%_BJ
_BJ
สร้างรายการJ
และการปฏิเสธของมัน%
โดยปริยายใช้Q
เป็นอาร์กิวเมนต์ที่สองและใช้พฤติกรรมเริ่มต้นของ Pyth เพื่อใช้% ... Q
กับสมาชิกแต่ละลำดับ จากนั้นจึงS
เรียงลำดับรายการและh
รับสมาชิกรายแรกเป็นจำนวนต่ำสุด