Bir sayının karekökü


13

Görev şu şekildedir: Pozitif bir tam sayı xve asal olarak n > x, en küçük pozitif tamsayıyı ybu şekilde verin (y * y) mod n = x. Bu sorunun önemli bir kısmı, kaba kuvvet çözümlerini hariç tutan, aşağıda belirtilen zaman sınırıdır.

Böyle bir değer yoksa, ykodunuzun çıktısı alınmalıdır N.

Test senaryoları

(2, 5, N), 
(3, 5, N), 
(4, 5, 2),
(524291, 1048583, N),
(529533, 1048583, N),
(534775, 1048583, 436853),
(540017, 1048583, 73675),
(536870913, 1073741827, 375394238),
(542239622, 1073741827, 267746399),
(547608331, 1073741827, N),
(552977040, 1073741827, 104595351),
(1099511627676, 1099511627791, N),
(1099511627677, 1099511627791, 269691261521),
(1099511627678, 1099511627791, 413834069585),
(1267650600228229401496703204376, 1267650600228229401496703205653, 5312823546347991512233563776),
(1267650600228229401496703204476, 1267650600228229401496703205653, N)
(1267650600228229401496703204576, 1267650600228229401496703205653, N)
(1267650600228229401496703204676, 1267650600228229401496703205653, 79905476259539917812907012931)

Giriş ve çıkış

Giriş alabilir ve çıktıyı uygun olan herhangi bir şekilde verebilirsiniz. Çıktı almak istemiyorsanız, Nherhangi bir Falseydeğer olacaktır.

Kısıtlamalar

Kodunuz tüm test senaryolarını standart bir masaüstünde 1 dakikadan kısa sürede yanıtlamalıdır. Bu zaman sınırı sadece kaba kuvvet cevaplarını önlemek içindir ve iyi cevapların neredeyse anında çalışmasını beklerim. Bu sorunu çözen veya bir sayının kuadratik kalıntı olup olmadığını sınayan herhangi bir kütüphane veya yerleşik yapı kullanamazsınız.


2
Bu nedenle, büyük tamsayı veri türünü desteklemeyen diller göz ardı edilir. Yazık
Luis Mendo

1
@LuisMendo Desteği 1267650600228229401496703205653kendiniz kodlayabiliyorsanız veya __int128gcc gibi 128 bit desteğiniz varsa değil . Ayrıca, çeşitli diller için bir dizi 256 bit int kütüphanesi vardır. Son olarak, birçok dilde keyfi bir hassas int kütüphanesi vardır.

Yanıtlar:


7

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.


11

Python 2, 166 bayt

def Q(x,n,a=0):
 e=n/2
 while pow(a*a-x,e,n)<2:a+=1
 w=a*a-x;b=r=a;c=s=1
 while e:
    if e%2:r,s=(r*b+s*c*w)%n,r*c+s*b
    b,c=(b*b+c*c*w)%n,2*b*c;e/=2
 return min(r,-r%n)

%timeit Q(1267650600228229401496703204676,1267650600228229401496703205653) 100 loops, best of 3: 2.83 ms per loop :)

3
Ne harika bir cevap! PPCG'ye olan inancımı geri kazandınız.

5
Acemi soruyu özür dilerim, ama PPCG nedir? Polonya Python Kodlayıcıları Grubu?
Ters Mühendis

@DaveBoltman Programlama Bulmacalar ve Kod Golf.
orlp


3

Haskell , 326 bayt

Genellikle kaba kuvvet cevaplarını severim. Bu zaman sınırı nedeniyle kesinlikle cesaret kırıldığı için, bildiğim en etkili yol:

r p=((\r->min(mod(-r)p)r)$).f p
f p x|p==2=x|q x=f 0 0|mod p 4==3=x&div(p+1)4|let(r,s)=foldl i(p-1,0)[1..t 1o]=m$x&(d$r+1)*(b&d s)where q a=1/=a&o;m=(`mod`p);a&0=1;a&e|even e=m$a&d e^2|0<1=m$(a&(e-1))*a;b=[n|n<-[2..],q n]!!0;i(a,b)_|m(x&d a*b&d b)==p-1=(d a,d b+o)|0<1=(d a,d b);o=d p;t y x|even x=t(y+1)(d x)|0<1=y;d=(`div`2)

Çevrimiçi deneyin!

Eminim bu daha fazla golf olabilir, ama bu şimdilik yapmalı.


Cevapları çıktı olarak vermek için TIO kodunu değiştirebilir misiniz? Şu an sadece "Doğru" oluyor.


@Lembik Orijinal TIO'ndakilerle değiştirmeniz gerekiyor testCases, onlarsız bile bir yoruma sığmıyor.
Ørjan Johansen

@ ØrjanJohansen Çok teşekkürler! Yanıtımı kodunuzla değiştirdim ve değiştirdim testCases.
ბიმო

Huh, bu TIO bağlantısıyla garip bir hata görüyorum - tıklarsam koda sahiptir, ancak menü seçeneklerinden ne çalışıyor ne de URL'yi alır - ancak URL'yi adres çubuğundan kopyalayıp bir yapıştırıcıya yapıştırırsam farklı sekme, o zaman çalışır.
Ørjan Johansen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.