En hızlı tweetable tam sayı çarpanlaştırıcı


17

Görev, bileşik bir sayının önemsiz olmayan bir faktörünü bulmaktır.

Kodunuzun 140 bayttan daha uzun olmamasına bağlı olarak, mümkün olduğunca çabuk bir kompozit sayı için önemsiz bir faktör bulan bir kod yazın. Çıktı sadece bulduğunuz faktör olmalıdır.

Kodunuz girdi alabilir ve çıktıyı, örneğin bir işleve bağımsız değişken olarak dahil olmak üzere uygun herhangi bir şekilde verebilir.

Tüm faktörleri listeleyen test senaryoları (sadece bir tane çıkarmanız gerekir)

187: 11 17
1679: 23 73
14369648346682547857: 1500450271 9576890767
34747575467581863011: 3628273133 9576890767
52634041113150420921061348357: 2860486313 5463458053 3367900313
82312263010898855308580978867: 264575131106459 311111111111113
205255454905325730631914319249: 2860486313 71755440315342536873 
1233457775854251160763811229216063007: 1110111110111 1000000000063 1111111999999
1751952685614616185916001760791655006749: 36413321723440003717 48112959837082048697

Yanıtınızı, test için ilgi çekici olabilecek aşağıdaki zor test durumunda puanlamayacağım:

513231721363284898797712130584280850383: 40206835204840513073 12764787846358441471

Puan

Puanınız, yukarıdaki tüm test durumlarını hesaba katmak için birleştirilmiş süredir ve başarısız olan her bir çarpanlara ayırma işlemi için 10 dakika ceza alır (tümü en yakın saniyeye yuvarlanır). Kodunuz diğer tamsayılar için de çalışmalıdır, yani sadece bu cevapları sabit kodlamamalıdır.

10 dakika sonra kodunuzu durduracağım.

İki kişi aynı puanı alırsa, ilk cevap kazanır.

Kısıtlamalar

Kodunuz, tamsayı çarpanlarına ayırma işlemi yapan herhangi bir yerleşik veya kitaplık işlevi kullanamaz. Girişin 256 bit'ten az sürdüğünü varsayabilirsiniz. Tüm giriş numaraları bileşik olacaktır.

Nasıl zaman ayıracağım?

time ./myprogZamanlamayı yapmak için tam anlamıyla Ubuntu sistemimde çalışacağım , bu yüzden lütfen tanımladığınız herhangi bir işlevi içeren çalışmam için eksiksiz bir program sağlayın.

Derlenmiş diller için bir not

Derleme süresi makinemde 1 dakikadan fazla sürmemelidir.

Aslında mümkün mü?

Boşluk kısıtlamalarını yoksayarsanız, her biri bilgisayarımda saf Python kodu + pypy kullanarak 2 saniyeden daha kısa sürede çarpanlarına ayrılabilir.

Önemsiz faktoring algoritması nedir?

Pollard'ın rho algoritması hızlı ve golf için uygundur. Tabii ki bir tamsayıyı da hesaba katmanın başka yolları da vardır.

Kuadratik elek daha da hızlıdır . 140 bayta sıkıştırmak ciddi bir zorluk gibi görünüyor.

Ana skorlar

  • SEJPM , son test vakası için 10 dakika ceza + Haskell'de 16 saniye

Yani, bize bir sayı verilebilir 2 ** 1024mi?
Conor O'Brien

@ ConorO'Brien Test durumlarından daha fazla basamağa sahip bir şey verilmeyecektir.

Yani, hassasiyet açısından, 256 bitten fazla bir şey yok.
Conor O'Brien

4 gibi bir giriş için çıkış 2veya 2, 2?
Bay Xcoder

1
@AndersKaseorg Önerinizi izleyerek soruyu güncelledim. Teşekkürler.

Yanıtlar:


9

Haskell, 100 97 91 89 87 72 67 Bayt

Çevrimiçi Deneyin!

-3 @flawr sayesinde bayt
-6 tekrar @flawr sayesinde bayt
-2 yine @flawr sayesinde bayt
-2 parametreleri optimize edilmiş bir dizi sayesinde bayt
-1 bayt @flawrs sayesinde bir kere daha
-14 ihtiyacına sayesinde bayt @AndersKaseorg sayesinde sadece bir faktörün
-5 bayt çıktısını almak

f n|let s x=mod(x*x+7)n;a#b|d<-gcd(b-a)n,d>1=d|c<-s b=s a#s c=5#s 5

Bu, ilk 5 test vakası için fark edilmeden çalışır.
Muhtemelen en büyük test senaryosunda zaman aşımı olacaktır.

Genel olarak bu genellikle en küçük faktörün karekökü ile orantılı olarak zaman içinde önemsiz olmayan bir faktörü döndürür.
Her girdide çalışmayacaktır çünkü polinomu değiştirmez ve istisnai durumun tespiti 140 baytta yapmak zordur.
Aynı zamanda tam çarpanlara ayırma değil, önemsiz olmayan bir çarpan ve girdinin bu çarpanla bölünmesi olacaktır.
Ayrıca faktörleri boyuta göre sıralamaz.

Kullanılan yöntem standart başlangıç ​​değeri 2 olan Pollard-Rho-Factoring'dir (standart ilex^2+11 tüm diğer değerlendirmeler için kez uygulanan polinom ) ve standart olmayan polinom sabit faktörü olan 7 (çünkü 1679 ile çalışmadı) .

Tam program (factor.hs ):

import System.Environment(getArgs)

f n|let s x=mod(x*x+7)n;a#b|d<-gcd(b-a)n,d>1=d|c<-s b=s a#s c=5#s 5

main= do
      args <- getArgs
      print$f (read $ head args :: Integer)

Farklı derleme $ ghc factor.hs(ihtiyaçlarghc kurulu ).
Farklı çalıştır $ ./factor <number>.

Örnek çalışma:

$ ./factor 187
11

Kod çözülmemiş kod:

f n=g 5 (s 5)
   where s x=mod(x*x+7)n
         g a b = if d>1 then d else g(s a)(s(s b))
               where d=gcd(b-a)n

gBaşlangıç ​​değerleriyle arayarak önemsiz olmayan faktörü hesaplar . Polinom burada 2'ye önceden uygulanır ve sonuç (5) üzerine tekrar uygulanır, böylece g(bir "burada" cümlesi içinde ) girdisi her zaman gcd testi için kolayca kullanılabilir. g(golfed sürümü infix kullanır #) daha sonra önemsiz olmayan bir faktörü d(golfe edilmemiş versiyondaki nerede, golfed'de satır içi) iki giriş arasındaki fark olarak ghesaplar. , yeniden dener. Burada sadece önemsiz bir faktör nvarsa a==bve bu şekilde geri dönerse , çıktı olarak üretilebilir , bunu ele almak için uygun yaklaşım ya bu olaydaki başlangıç ​​değerlerini değiştirmek ya da polinomu değiştirmek olacaktır.


|1<2=s a#(s$s b)|c<-s b=s a#s cbence ile değiştirilebilir :) (ayrıca: neden bir TIO bağlantısı yayınlamıyorsunuz ?)
flawr

Soruyu yorum önerilerini izleyerek güncelledim. Şimdi sadece bir faktörün çıktısını almanız gerekiyor ve sayıların bileşik olduğu garanti ediliyor.

3
Not: neden golf
oynuyoruz

4
Artık daha da karmaşık bir faktoring algoritması uygulamak için 53

1
Ayrıca çıkartabilirsiniz abs , çünkü bher zaman negatif değildir. (Belki de demek istediniz abs$b-a, ancak gcdolumsuz argümanları kabul ediyorsunuz ve her zaman olumsuz olmayan bir sonuç üretiyorsunuz.)
Anders Kaseorg

6

Pari / GP , 137 bayt, ~ 5 saniye

GP'nin yerleşik eliptik eğri işlemlerini (ve bazı el yapımı parametre ayarlamalarını) kullanarak :

ecm(n)=iferr(if(n%2==0,2,n%3==0,3,for(a=1,n,ellmul(ellinit(Mod([a,a^2-a-1],n)),[1,a],lcm([1..ceil(4^a^0.5)])))),e,gcd(n,lift(Vec(e)[3])))

ecmbir faktör döndürmesi gereken bir işlevdir. Çevrimiçi deneyin!

Ölçek:

ecm(n)=iferr(if(n%2==0,2,n%3==0,3,for(a=1,n,ellmul(ellinit(Mod([a,a^2-a-1],n)),[1,a],lcm([1..ceil(4^a^0.5)])))),e,gcd(n,lift(Vec(e)[3])))

{
ns = [
  187,
  1679,
  14369648346682547857,
  34747575467581863011,
  52634041113150420921061348357,
  82312263010898855308580978867,
  205255454905325730631914319249,
  1233457775854251160763811229216063007,
  1751952685614616185916001760791655006749
  ]
}

test(n) = {
    d = ecm(n);
    if (!(1<d && d<n && n%d==0), error(d));
    print(n, ": ", d)
}

apply(test, ns)

quit

Ungolfed:

ecm(n) = {
  iferr(if(n%2 == 0, 2,
           n%3 == 0, 3,
           for(a = 1, n,
               /* x^3 + A*x + B = y^2 */
               E = ellinit(Mod([a, a^2-a-1], n)); /* [A, B] */
               x0 = [1, a]; /* [x, y] */
               B = ceil(4^a^0.5); /* ~ exp(sqrt(log(p))), p ~= exp(a) */
               print("a=", a, ", B=", B);
               ellmul(E, x0, lcm([1..B]))
              )
          ),
         ERR, gcd(n, lift(Vec(ERR)[3] /* = Mod(d, n) */)),
         errname(ERR)=="e_INV")
}

Ne yazık ki, 2 ve 3 faktörlerini işlemek birçok bayt kullanır. 2. aşama eklemek için kullanılabilecek bayt sayısı:

ecm(n)=iferr(for(a=1,n,Y=X=ellmul(E=ellinit(Mod([a,1],n)),[0,1],(B=ceil(4^a^0.5))!);for(z=0,9*B,Y=elladd(E,Y,X))),e,gcd(n,lift(Vec(e)[3])))

1

Aksiyom, 137 bayt 9 dakika

p(n:PI):PI==(j:=1;a:=3;s:=n^.2;repeat(b:=j:=nextPrime(j);repeat(b<s=>(b:=b*j);break);a:=powmod(a,b,n);d:=gcd(a-1,n);d>1 or j>n=>break);d)

p (1) fonksiyonunda test için bir dosyaya kopyalanacak şeyin altında faktoring için p-1 algo uygulayacak olan p () fonksiyonunun üstünde

-- one has to copy this below text in a file name for example file.input
-- in one window where there is Axiom one could write 
-- )read C:\absolutepathwherethereisthatfile\file
-- and call the function test()
-- test()
-- the first character of all function and array must be afther a new line "\n"
)cl all
)time on
vA:=[187,1679,14369648346682547857,34747575467581863011,52634041113150420921061348357,82312263010898855308580978867,205255454905325730631914319249,1233457775854251160763811229216063007, 1751952685614616185916001760791655006749]

p(n:PI):PI==(j:=1;a:=3;s:=n^.2;repeat(b:=j:=nextPrime(j);repeat(b<s=>(b:=b*j);break);a:=powmod(a,b,n);d:=gcd(a-1,n);d>1 or j>n=>break);d)

-- this would try to factor n with p-1 Pollard method
pm1(n:PI):PI==
   j:=1;a:=3;s:=n^.2
   repeat
      b:=j:=nextPrime(j)
      repeat(b<s=>(b:=b*j);break)
      a:=powmod(a,b,n)
      d:=gcd(a-1,n);d>1 or j>n=>break
   d

test()==(for i in 1..#vA repeat output [vA.i, p(vA.i)])

burada sonuçlar:

(5) -> test()
   [187,11]
   [1679,73]
   [14369648346682547857,9576890767]
   [34747575467581863011,9576890767]
   [52634041113150420921061348357,2860486313]
   [82312263010898855308580978867,311111111111113]
   [205255454905325730631914319249,2860486313]
   [1233457775854251160763811229216063007,1111111999999]
   [1751952685614616185916001760791655006749,36413321723440003717]
                                                               Type: Void
                              Time: 496.78 (EV) + 53.05 (GC) = 549.83 sec

Ubuntu'daki komut satırından bu kodu tam olarak nasıl çalıştırabileceğinizi lütfen söyleyebilir misiniz? Ben aksiyom yükledim ve içinde golf olmayan kod ile foo.ax adlı bir dosya yaptım.

@Lembik 1) foo.input içinde fop.ax'ı yeniden adlandırın 2) Axiom'u bir terminalde veya xterm'de çalıştırın 3) Axiom terminalinde şu komutu yazın ") C'yi okuyun: absolutepath \ foo" 4) Axiom'un terminaline çağrı yazın test () işlevine. Windows'ta bu nasıl yapılır, bana bir aksiyom oturumu açmak ve ") read" komutuyla dosyayı yüklemek gibi görünen ipucu
RosLuP

@Lembik dosyaları ile ilgili sorun varsa ben de iyi olacağını düşünüyorum: 1) Axiom çalıştırmak 2) yazma) Axiom programında <return> zaman 3) kopya yapıştır ve Axiom programında her "kopya yapıştır" geri dönüş: dizi vA, Axiom program yazma testindeki () p () ve test () 4) fonksiyonu <return>
RosLuP

@Lembik yani ne zaman alır?
RosLuP

1

Aksiyom, 10 dakika + 31 saniye

A(a)==>a:=(a*a+7)rem n;z(n)==(p:=a:=b:=101;for i in 1..repeat(A(a);A(b);A(b);p:=mulmod(p,a-b,n);i rem 999<9=>(p:=gcd(p,n);p>1=>break));p)

z () işlevi rho, bir 137 bayt işlevidir; ungolfed z () ve rho () olarak adlandırın. Gcd (0, n) = n olduğu için döngü durur ve başarısız n için geri döner.

)time on    
rho(n)==
  p:=a:=b:=101
  for i in 1..repeat
          A(a);A(b);A(b)
          p:=mulmod(p,a-b,n)
          i rem 999<9=>(p:=gcd(p,n);p>1=>break)
  p

va1:=[187,1679,14369648346682547857,34747575467581863011,52634041113150420921061348357,82312263010898855308580978867,205255454905325730631914319249,1233457775854251160763811229216063007, 1751952685614616185916001760791655006749]
p1()==(for i in 1..#va1-1 repeat output [va1.i,z(va1.i)]) 

sonuçlar (z () herkese uygun değil ancak son sayı 1751952685614616185916001760791655006749 faktörsüz kalmıyor (10 dakika))

(6) -> p1()
   [187,17]
   [1679,23]
   [14369648346682547857,1500450271]
   [34747575467581863011,3628273133]
   [52634041113150420921061348357,2860486313]
   [82312263010898855308580978867,264575131106459]
   [205255454905325730631914319249,2860486313]
   [1233457775854251160763811229216063007,1111111999999]
                                                               Type: Void
                                 Time: 30.38 (EV) + 1.38 (GC) = 31.77 sec

(8) -> z(1679)
   (8)  23
                                                    Type: PositiveInteger
                                                              Time: 0 sec

0

Python 3 , 100 99 bayt, 45 40 39 saniye + 10 dakika ceza

import math
def f(n):
 x=y=2;d=1
 while d<2:y=y*y+1;x,y=1+x*x%n,y*y%n+1;d=math.gcd(x-y,n)
 return d

Çevrimiçi deneyin!

Başlangıç ​​değeri 2 ve polinom x ^ 2 + 1 olan Pollard-Rho kullanır.


Sen kullanabilirsiniz powsenin yürütme hızını artırmak için (3rd bağımsız değişkenle).
mbomb007
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.