Bình thường, 83 82 byte
=eAQM.^GHQKf%=/H=2;1=gftgT/Q;1HJg~gGHh/H2WtG=*J=gT^2t-K=Kfq1gG^2T1=%*G=^T2Q;hS%_BJ
Bộ kiểm tra
Chương trình này thực hiện thuật toán Tonelli-Shanks . Tôi đã viết nó bằng cách theo sát trang Wikipedia. Nó là đầu vào (n, p).
Sự vắng mặt của một căn bậc hai được báo cáo bởi lỗi sau:
TypeError: pow() 3rd argument not allowed unless all arguments are integers
Đây là mã golf rất phức tạp, được viết theo phong cách bắt buộc, trái ngược với phong cách chức năng phổ biến hơn của Pyth.
Một khía cạnh tinh tế của Pyth tôi đang sử dụng là =, nếu không ngay lập tức theo sau một biến, tìm kiếm chuyển tiếp trong chương trình cho biến tiếp theo, sau đó gán kết quả của biểu thức sau cho biến đó, sau đó trả về kết quả đó. Tôi sẽ tham khảo trong suốt phần giải thích cho trang wikipedia: Thuật toán Tonelli-Shanks , vì đó là thuật toán tôi đang thực hiện.
Giải trình:
=eAQ
Amất 2 tuple như đầu vào, và gán các giá trị để Gvà Htương ứng, và trả về đầu vào của nó. Qlà đầu vào ban đầu. etrả về phần tử cuối cùng của chuỗi Sau đoạn này, Glà n, và Hvà Qlà p.
M.^GHQ
Mđịnh nghĩa một hàm 2 đầu vào g, trong đó các đầu vào là Gvà H. .^là chức năng lũy thừa mô-đun nhanh của Pyth. Đoạn mã này định gnghĩa mod mod lũy thừa Q.
Kf%=/H=2;1
fđịnh nghĩa lặp lại cho đến khi vòng lặp sai và trả về số lần lặp mà nó chạy, được đưa ra 1làm đầu vào của nó. Trong mỗi lần lặp của vòng lặp, chúng tôi chia Hcho 2, đặt thành Hgiá trị đó và kiểm tra xem kết quả có phải là số lẻ hay không. Một khi nó được, chúng tôi dừng lại. Klưu trữ số lần lặp này mất.
Một điều rất khó khăn là =2;bit. =tìm kiếm trước cho biến tiếp theo, đó là T, do đó Tđược thiết lập để 2. Tuy nhiên, Tbên trong một fvòng lặp là lặp truy cập, vì vậy chúng tôi sử dụng ;để có được giá trị của Ttừ môi trường toàn cầu. Điều này được thực hiện để lưu một vài byte khoảng trắng cần thiết để tách các số.
Sau đoạn này, Klà Stừ bài viết wikipedia (wiki), và Hlà Qtừ wiki, và Tlà 2.
=gftgT/Q;1H
Bây giờ, chúng ta cần tìm một mod nonresidue bậc hai p. Chúng tôi sẽ vũ phu điều này bằng cách sử dụng tiêu chí Euler. /Q2là (p-1)/2, vì /là phân chia thả nổi, vì vậy ftgT/Q;1tìm số nguyên đầu tiên Tở đâu T ^ ((p-1)/2) != 1, như mong muốn. Nhớ lại rằng ;một lần nữa kéo Ttừ môi trường toàn cầu, vẫn là 2. Kết quả này là ztừ wiki.
Tiếp theo, để tạo ctừ wiki, chúng tôi cần z^Q, vì vậy chúng tôi gói phần trên g ... Hvà gán kết quả cho T. Bây giờ Tlà ctừ wiki.
Jg~gGHh/H2
Chúng ta hãy tách ra điều này : ~gGH. ~giống như =, nhưng trả về giá trị ban đầu của biến, không phải giá trị mới của nó. Vì vậy, nó trả về G, đó là ntừ wiki.
Điều này gán Jgiá trị của n^((Q+1)/2), là Rtừ wiki.
Bây giờ, những điều sau đây có hiệu lực:
~gGH
Điều này gán Ggiá trị n^Q, là ttừ wiki.
Bây giờ, chúng ta có các biến vòng lặp được thiết lập. M, c, t, Rtừ wiki là K, T, G, J.
Phần thân của vòng lặp rất phức tạp, vì vậy tôi sẽ trình bày nó với khoảng trắng, như cách tôi đã viết:
WtG
=*J
=
gT^2
t-
K
=Kfq1gG^2T1
=%*G=^T2Q;
Đầu tiên, chúng tôi kiểm tra xem có phải Glà 1. Nếu vậy, chúng tôi thoát khỏi vòng lặp.
Mã tiếp theo chạy là:
=Kfq1gG^2T1
Ở đây, chúng tôi tìm kiếm giá trị đầu tiên inhư vậy G^(2^i) mod Q = 1, bắt đầu từ 1. Kết quả được lưu vào K.
=gT^2t-K=Kfq1gG^2T1
Ở đây, chúng ta lấy giá trị cũ của K, trừ đi giá trị mới của K, trừ 1, tăng 2 lên lũy thừa đó, rồi nâng Tlên mod công suất đó Q, rồi gán kết quả cho T. Điều này làm cho Tbằng với bwiki.
Đây cũng là dòng kết thúc vòng lặp và thất bại nếu không có giải pháp, bởi vì trong trường hợp đó, giá trị mới Ksẽ bằng giá trị cũ của K, 2 sẽ được nâng lên -1và lũy thừa mô-đun sẽ gây ra lỗi.
=*J
Tiếp theo, chúng tôi nhân Jvới kết quả trên và lưu trữ lại J, tiếp tục Rcập nhật.
=^T2
Sau đó, chúng tôi vuông Tvà lưu trữ kết quả trở lại T, thiết lập Tlại ctừ wiki.
=%*G=^T2Q
Sau đó, chúng tôi nhân Gvới kết quả đó, lấy mod Qvà lưu lại kết quả G.
;
Và chúng tôi chấm dứt vòng lặp.
Sau khi vòng lặp kết thúc, Jlà một căn bậc hai của nmod p. Để tìm cái nhỏ nhất, chúng tôi sử dụng mã sau:
hS%_BJ
_BJtạo danh sách Jvà phủ định của nó, %mặc nhiên lấy Qlàm đối số thứ hai của nó và sử dụng hành vi mặc định của Pyth để áp dụng % ... Qcho từng thành viên của chuỗi. Sau đó Ssắp xếp danh sách và hlấy thành viên đầu tiên của nó, mức tối thiểu.