Pyth, 83 82 byte
=eAQM.^GHQKf%=/H=2;1=gftgT/Q;1HJg~gGHh/H2WtG=*J=gT^2t-K=Kfq1gG^2T1=%*G=^T2Q;hS%_BJ
Suite uji
Program ini mengimplementasikan algoritma Tonelli-Shanks . Saya menulisnya dengan cermat mengikuti halaman Wikipedia. Dibutuhkan sebagai input (n, p).
Tidak adanya akar kuadrat dilaporkan oleh kesalahan berikut:
TypeError: pow() 3rd argument not allowed unless all arguments are integers
Ini adalah kode golf yang sangat rumit, ditulis dengan gaya imperatif, berbeda dengan gaya fungsional Pyth yang lebih umum.
Aspek halus Pyth yang saya gunakan adalah =, yang, jika tidak segera diikuti oleh variabel, mencari maju dalam program untuk variabel berikutnya, kemudian memberikan hasil dari ekspresi berikut untuk variabel itu, kemudian mengembalikan hasil itu. Saya akan merujuk seluruh penjelasan ke halaman wikipedia: Algoritma Tonelli-Shanks , karena itulah algoritma yang saya terapkan.
Penjelasan:
=eAQ
Amengambil 2-tuple sebagai input, dan memberikan nilai masing G- Hmasing, dan mengembalikan inputnya. Qadalah input awal. emengembalikan elemen terakhir dari suatu urutan. Setelah cuplikan ini, Gadalah n, dan Hdan Qsedang p.
M.^GHQ
Mmendefinisikan fungsi input 2 g, di mana input berada Gdan H. .^adalah fungsi eksponensial modular cepat Pyth. Cuplikan ini didefinisikan gsebagai mod eksponensial Q.
Kf%=/H=2;1
fmendefinisikan pengulangan sampai false loop, dan mengembalikan jumlah iterasi yang dijalankannya, diberikan 1sebagai inputnya. Selama setiap iterasi loop, kami membaginya Hdengan 2, set Hke nilai itu, dan memeriksa apakah hasilnya aneh. Setelah itu, kita berhenti. Kmenyimpan jumlah iterasi yang dibutuhkan.
Satu hal yang sangat sulit adalah =2;bagiannya. =mencari di depan untuk variabel berikutnya, yaitu T, jadi Tdiatur ke 2. Namun, Tdi dalam floop adalah penghitung iterasi, jadi kami gunakan ;untuk mendapatkan nilai dari Tlingkungan global. Ini dilakukan untuk menyimpan beberapa byte spasi putih yang jika tidak akan diperlukan untuk memisahkan angka.
Setelah potongan ini, Kadalah Sdari artikel wikipedia (wiki), dan Hadalah Qdari wiki, dan Tini 2.
=gftgT/Q;1H
Sekarang, kita perlu menemukan mod nonresid kuadratik p. Kami akan memaksa ini menggunakan kriteria Euler. /Q2adalah (p-1)/2, karena /adalah divisi lantai, sehingga ftgT/Q;1menemukan bilangan bulat pertama di Tmana T ^ ((p-1)/2) != 1, seperti yang diinginkan. Ingat itu ;lagi menarik Tdari lingkungan global, yang masih 2. Hasil ini zdari wiki.
Selanjutnya, untuk membuat cdari wiki, kita perlu z^Q, jadi kita bungkus di atas g ... Hdan tetapkan hasilnya T. Sekarang Tadalah cdari wiki.
Jg~gGHh/H2
Mari kita memisahkan ini: ~gGH. ~seperti =, tetapi mengembalikan nilai asli variabel, bukan nilai baru. Jadi, ia kembali G, yang ndari wiki.
Ini memberikan Jnilai n^((Q+1)/2), yaitu Rdari wiki.
Sekarang, yang berikut ini berlaku:
~gGH
Ini memberikan Gnilai n^Q, yang berasal tdari wiki.
Sekarang, kita telah mengatur variabel loop kami. M, c, t, Rdari wiki adalah K, T, G, J.
Tubuh loop rumit, jadi saya akan menyajikannya dengan spasi putih, cara saya menulisnya:
WtG
=*J
=
gT^2
t-
K
=Kfq1gG^2T1
=%*G=^T2Q;
Pertama, kita periksa apakah G1. Jika demikian, kita keluar dari loop.
Kode berikutnya yang berjalan adalah:
=Kfq1gG^2T1
Di sini, kami mencari nilai pertama isedemikian rupa G^(2^i) mod Q = 1, mulai dari 1. Hasilnya disimpan K.
=gT^2t-K=Kfq1gG^2T1
Di sini, kita mengambil nilai lama K, kurangi nilai baru K, kurangi 1, naikkan 2 ke daya itu, lalu naikkan Tke mod daya itu Q, lalu tetapkan hasilnya T. Ini Tsama dengan bdari wiki.
Ini juga merupakan garis yang mengakhiri loop dan gagal jika tidak ada solusi, karena dalam hal ini nilai baru Kakan sama dengan nilai lama K, 2 akan dinaikkan ke -1, dan eksponensial modular akan menimbulkan kesalahan.
=*J
Selanjutnya, kita kalikan Jdengan hasil di atas dan simpan kembali J, tetap Rperbarui.
=^T2
Lalu kami menyiku Tdan menyimpan hasilnya kembali T, mengatur Tkembali ke cdari wiki.
=%*G=^T2Q
Lalu kita kalikan Gdengan hasil itu, ambil modnya Qdan simpan hasilnya kembali G.
;
Dan kami mengakhiri loop.
Setelah loop selesai, Jadalah akar kuadrat dari nmod p. Untuk menemukan yang terkecil, kami menggunakan kode berikut:
hS%_BJ
_BJmembuat daftar Jdan negasinya, %secara implisit mengambil Qsebagai argumen kedua, dan menggunakan perilaku default Pyth untuk diterapkan % ... Qke setiap anggota urutan. Kemudian Smengurutkan daftar dan hmengambil anggota pertamanya, minimum.