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
A
mất 2 tuple như đầu vào, và gán các giá trị để G
và H
tương ứng, và trả về đầu vào của nó. Q
là đầu vào ban đầu. e
trả về phần tử cuối cùng của chuỗi Sau đoạn này, G
là n
, và H
và Q
là p
.
M.^GHQ
M
định nghĩa một hàm 2 đầu vào g
, trong đó các đầu vào là G
và H
. .^
là chức năng lũy thừa mô-đun nhanh của Pyth. Đoạn mã này định g
nghĩ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 1
là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 H
cho 2, đặt thành H
giá 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. K
lư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, T
bên trong một f
vò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 T
từ 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, K
là S
từ bài viết wikipedia (wiki), và H
là Q
từ wiki, và T
là 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. /Q2
là (p-1)/2
, vì /
là phân chia thả nổi, vì vậy ftgT/Q;1
tì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 T
từ môi trường toàn cầu, vẫn là 2. Kết quả này là z
từ wiki.
Tiếp theo, để tạo c
từ wiki, chúng tôi cần z^Q
, vì vậy chúng tôi gói phần trên g ... H
và gán kết quả cho T
. Bây giờ T
là c
từ 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à n
từ wiki.
Điều này gán J
giá trị của n^((Q+1)/2)
, là R
từ wiki.
Bây giờ, những điều sau đây có hiệu lực:
~gGH
Điều này gán G
giá trị n^Q
, là t
từ wiki.
Bây giờ, chúng ta có các biến vòng lặp được thiết lập. M, c, t, R
từ 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 G
là 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 i
như 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 T
lên mod công suất đó Q
, rồi gán kết quả cho T
. Điều này làm cho T
bằng với b
wiki.
Đâ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 K
sẽ bằng giá trị cũ của K
, 2 sẽ được nâng lên -1
và lũy thừa mô-đun sẽ gây ra lỗi.
=*J
Tiếp theo, chúng tôi nhân J
với kết quả trên và lưu trữ lại J
, tiếp tục R
cập nhật.
=^T2
Sau đó, chúng tôi vuông T
và lưu trữ kết quả trở lại T
, thiết lập T
lại c
từ wiki.
=%*G=^T2Q
Sau đó, chúng tôi nhân G
với kết quả đó, lấy mod Q
và 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, J
là một căn bậc hai của n
mod p
. Để tìm cái nhỏ nhất, chúng tôi sử dụng mã sau:
hS%_BJ
_BJ
tạo danh sách J
và phủ định của nó, %
mặc nhiên lấy Q
làm đối số thứ hai của nó và sử dụng hành vi mặc định của Pyth để áp dụng % ... Q
cho từng thành viên của chuỗi. Sau đó S
sắp xếp danh sách và h
lấy thành viên đầu tiên của nó, mức tối thiểu.