Pyth, 83 82 bayt
=eAQM.^GHQKf%=/H=2;1=gftgT/Q;1HJg~gGHh/H2WtG=*J=gT^2t-K=Kfq1gG^2T1=%*G=^T2Q;hS%_BJ
Test odası
Bu program Tonelli-Shanks algoritmasını uygular . Wikipedia sayfasını yakından takip ederek yazdım. Girdi olarak alır (n, p).
Karekök olmaması aşağıdaki hata ile bildirilir:
TypeError: pow() 3rd argument not allowed unless all arguments are integers
Bu, Pyth'in daha yaygın fonksiyonel stilinin aksine, zorunlu bir tarzda yazılmış çok karmaşık bir golf kodudur.
Kullanmakta olduğum Pyth'in bir ince yönü, =hemen bir değişken tarafından takip edilmezse, programda bir sonraki değişken için ileriye doğru arama yapar, daha sonra bu ifadeye aşağıdaki ifadenin sonucunu atar ve ardından bu sonucu döndürür. Açıklama boyunca wikipedia sayfasına bakacağım : Tonelli-Shanks algoritması , uyguladığım algoritma bu.
Açıklama:
=eAQ
Agiriş olarak bir 2-tuple alır ve değerler atar Gve Hsırasıyla ve giriş döndürür. Qilk girdi. edizinin son öğesini döndürür. Bu pasajı sonra Gise n, ve Hve Qvardır p.
M.^GHQ
Mggirişlerin Gve olduğu 2 giriş fonksiyonunu tanımlar H. .^Pyth'in hızlı modüler üs alma fonksiyonudur. Bu pasaj, güs alma modu anlamına gelir Q.
Kf%=/H=2;1
ffalse döngüsüne kadar bir yineleme tanımlar 1ve girdisi olarak verildiği yineleme sayısını döndürür . Döngünün her yinelemesi sırasında, H2'ye böleriz , Hbu değere ayarlanır ve sonucun garip olup olmadığını kontrol ederiz. Bir kez, duruyoruz. Kgereken yineleme sayısını kaydeder.
Çok zor bir şey =2;biraz. =bir sonraki değişken için ileriye doğru arama yapar T, yani 2 Tolarak ayarlanır. Ancak, Tbir fdöngü içinde yineleme sayacıdır, bu nedenle küresel ortamdan ;değerini almak için kullanırız T. Bu, aksi takdirde sayıları ayırmak için gerekecek birkaç bayt boşluk kaydetmek için yapılır.
Bu pasajı sonra Kise Swikipedia makalesinde (wiki) den ve Hbir Qvikiden ve Tolduğunu 2.
=gftgT/Q;1H
Şimdi, ikinci dereceden bir karşılıksız mod bulmamız gerekiyor p. Euler ölçütünü kullanarak bunu zorlayacağız. /Q2olduğu (p-1)/2, çünkü /katlı bölümü, yani ftgT/Q;1ilk tamsayı bulur arzu edildiği gibi,. Yine küresel ortamdan çekildiğini hatırlayın , ki bu hala 2'dir. Bu sonuç wiki'den.TT ^ ((p-1)/2) != 1;Tz
Daha csonra, wiki'den oluşturmak için ihtiyacımız var z^Q, bu yüzden yukarıdakileri g ... Hsarıyoruz ve sonucu atarız T. Şimdi Tise cvikiden.
Jg~gGHh/H2
En bu ayırmak edelim: ~gGH. ~gibi =, ancak değişkenin orijinal değerini döndürür, yeni değerini döndürmez. Böylece, wiki'den Golan geri döner n.
Bu atar Jdeğerini n^((Q+1)/2)olduğunu Rvikiden.
Şimdi, aşağıdakiler geçerli olur:
~gGH
Bu atar Gdeğeri n^Qolduğunu tvikiden.
Şimdi döngü değişkenlerimizi kurduk. M, c, t, Rwiki vardır K, T, G, J.
Döngünün gövdesi karmaşıktır, bu yüzden onu yazdığım şekilde boşlukla sunacağım:
WtG
=*J
=
gT^2
t-
K
=Kfq1gG^2T1
=%*G=^T2Q;
İlk olarak, G1 olup olmadığını kontrol ederiz . Eğer öyleyse, döngüden çıkarız.
Çalışan bir sonraki kod:
=Kfq1gG^2T1
Burada, 1'den başlayarak iböyle bir ilk değeri G^(2^i) mod Q = 1ararız. Sonuç kaydedilir K.
=gT^2t-K=Kfq1gG^2T1
Burada, eski değerini alır K, yeni değerini Kçıkarırız, 1 çıkarırız, 2'yi bu güce yükseltiriz ve sonra To güç moduna yükseltiriz Qve sonucu atarız T. Bu, Twikiden eşittir b.
Bu aynı zamanda döngüyü sonlandıran ve çözüm yoksa başarısız olan çizgidir, çünkü bu durumda yeni değeri K, eski değerinin K2'ye eşit olacak -1ve modüler üs alma bir hataya neden olacaktır.
=*J
Ardından, Jyukarıdaki sonuçla çarpıyoruz ve güncellenerek Jsaklıyoruz R.
=^T2
Sonra kare Tve sonuç geri saklamak T, ayarı Tiçin geri cvikiden.
=%*G=^T2Q
Sonra Gbu sonuçla çarparız , mod alır Qve sonucu tekrar saklarız G.
;
Ve döngüyü sonlandırıyoruz.
Döngü bittikten sonra, modun Jkare köküdür . En küçük olanı bulmak için aşağıdaki kodu kullanırız:np
hS%_BJ
_BJlistesini Jve negatifliğini oluşturur, %dolaylı Qolarak ikinci argümanı olarak alır % ... Qve dizinin her üyesine uygulamak için Pyth'in varsayılan davranışını kullanır . Sonra Slisteyi sıralar ve hilk üyesini, minimum üyeyi alır.