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
A
giriş olarak bir 2-tuple alır ve değerler atar G
ve H
sırasıyla ve giriş döndürür. Q
ilk girdi. e
dizinin son öğesini döndürür. Bu pasajı sonra G
ise n
, ve H
ve Q
vardır p
.
M.^GHQ
M
g
girişlerin G
ve 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
f
false döngüsüne kadar bir yineleme tanımlar 1
ve girdisi olarak verildiği yineleme sayısını döndürür . Döngünün her yinelemesi sırasında, H
2'ye böleriz , H
bu değere ayarlanır ve sonucun garip olup olmadığını kontrol ederiz. Bir kez, duruyoruz. K
gereken 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 T
olarak ayarlanır. Ancak, T
bir f
dö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 K
ise S
wikipedia makalesinde (wiki) den ve H
bir Q
vikiden ve T
olduğ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. /Q2
olduğu (p-1)/2
, çünkü /
katlı bölümü, yani ftgT/Q;1
ilk tamsayı bulur arzu edildiği gibi,. Yine küresel ortamdan çekildiğini hatırlayın , ki bu hala 2'dir. Bu sonuç wiki'den.T
T ^ ((p-1)/2) != 1
;
T
z
Daha c
sonra, wiki'den oluşturmak için ihtiyacımız var z^Q
, bu yüzden yukarıdakileri g ... H
sarıyoruz ve sonucu atarız T
. Şimdi T
ise c
vikiden.
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 G
olan geri döner n
.
Bu atar J
değerini n^((Q+1)/2)
olduğunu R
vikiden.
Şimdi, aşağıdakiler geçerli olur:
~gGH
Bu atar G
değeri n^Q
olduğunu t
vikiden.
Şimdi döngü değişkenlerimizi kurduk. M, c, t, R
wiki 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, G
1 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 i
böyle bir ilk değeri G^(2^i) mod Q = 1
ararı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 T
o güç moduna yükseltiriz Q
ve sonucu atarız T
. Bu, T
wikiden 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 K
2'ye eşit olacak -1
ve modüler üs alma bir hataya neden olacaktır.
=*J
Ardından, J
yukarıdaki sonuçla çarpıyoruz ve güncellenerek J
saklıyoruz R
.
=^T2
Sonra kare T
ve sonuç geri saklamak T
, ayarı T
için geri c
vikiden.
=%*G=^T2Q
Sonra G
bu sonuçla çarparız , mod alır Q
ve sonucu tekrar saklarız G
.
;
Ve döngüyü sonlandırıyoruz.
Döngü bittikten sonra, modun J
kare köküdür . En küçük olanı bulmak için aşağıdaki kodu kullanırız:n
p
hS%_BJ
_BJ
listesini J
ve negatifliğini oluşturur, %
dolaylı Q
olarak ikinci argümanı olarak alır % ... Q
ve dizinin her üyesine uygulamak için Pyth'in varsayılan davranışını kullanır . Sonra S
listeyi sıralar ve h
ilk üyesini, minimum üyeyi alır.