2015-08-16 13 views
5

BigInteger öğesinin öncelikli olup olmadığını algılayan bir yöntem yazıyorum. Verilen bir sayının öncelikli olup olmadığını kontrol etmek için aşağıdaki kodu/algoritmayı kullandım. Ancak bu çok yavaştır ve bir sayı 10 rakam uzunluğundaysa uzun zaman alır.Bir BigInteger asal sayı olup olmadığını bulmak için en hızlı algoritma?

public boolean returnPrime(BigInteger testNumber){ 
     int divisorCounter=1; 
     BigInteger index,i ; 


     for (index= new BigInteger("2"); index.compareTo(testNumber) !=1; index=index.add(new BigInteger("1"))){ 


      System.out.println(index); 
      for(i= new BigInteger("2"); i.compareTo(index) != 1; i=i.add(new BigInteger("1"))){ 
      if((testNumber.mod(i).equals(BigInteger.ZERO))){ 
      divisorCounter++; 

      } 

      if(divisorCounter>2){ 
      return false; 
      } 

      }  

     } 
    return true; 

    } 

BigInteger asal sayı ile çalışmak için daha iyi algoritmalar var mı? Stackoverflow'ta bununla ilgili bir soru bulamadım. Böyle bir soruyla karşılaşırsanız lütfen bize bildirin ya da nasıl çözeceğiniz konusunda bir fikriniz varsa, fikirleriniz çok takdir edilir.

+1

2 sonra, sadece tek sayılar kontrol etmeniz gerekir. Ayrıca sqrt (n) 'ye ulaştıktan sonra durabilirsiniz. –

+0

, ikinci döngüden önce, sayının öncelikli olup olmadığını ve ikinci döngüye mi geçtiğini kontrol etmeden önce? Bu yükü azaltmak için kulağa hoş geliyor, çünkü tüm çift sayıları ortadan kaldırırdım. – Ram

+1

Ayrıca ve 'sqrt (n)' n ' –

cevap

6

Burada sadece (n) sqrt kadar testini kullanarak ve (Joni en cevabın gibi) Miller-Rabin testi kullanılarak optimize edilmiş sürümü:

public boolean returnPrime(BigInteger number) { 
    //check via BigInteger.isProbablePrime(certainty) 
    if (!number.isProbablePrime(5)) 
     return false; 

    //check if even 
    BigInteger two = new BigInteger("2"); 
    if (!two.equals(number) && BigInteger.ZERO.equals(number.mod(two))) 
     return false; 

    //find divisor if any from 3 to 'number' 
    for (BigInteger i = new BigInteger("3"); i.multiply(i).compareTo(number) < 1; i = i.add(two)) { //start from 3, 5, etc. the odd number, and look for a divisor if any 
     if (BigInteger.ZERO.equals(number.mod(i))) //check if 'i' is divisor of 'number' 
      return false; 
    } 
    return true; 
} 
+0

Kodunuzu test ettim ve temiz ve çok daha basit olduğunu söylemeliyim! Teşekkür ederim! – Ram

+0

Merhaba @Juan Lopes, sadece tek bir adım yerine "i" ile "i" nin artırılmasının sebebi nedir? – sunsin1985

+0

@ sunsin1985 Bölünebilirlik için iki tane daha önce test ettiğimizden, böylelikle bölünebilirliği bile faktörlerle test etmek zorunda değiliz. En iyi duruma getirilmiş bir versiyonda, sadece temel faktörleri test ederiz. Ancak bu, bellekte sqrt (n) primlerine kadar bilgi işlem ve depolama gerektirecektir. Bununla birlikte, sayının daha da erken test edilmesi, bölümlerin sayısını yarıya indirmemize izin verir, bu yüzden optimizasyona değerdir. –

2

Tamsayı bir "olası birincil" olup olmadığını kontrol edin. Eğer bunu bilmiyorsanız, bunun kompozit olduğundan emin olun ve yavaş faktorizasyondan kaçının.

if (!testNumber.isProbablePrime(5)) return false; 

Ayrıca yalnızca testNumber kare köküne kadar deneme bölünmeleri yapmanız gerekir. Eğer K kompozit ise, en küçük asal çarpanının en fazla sqrt (K) olması gerektiğini bilirsiniz.

+0

'dan çok daha küçüktür. Ayrıca, belirli bir aralıktaki sayılarla ilgili Miller-Rabin testinin deterministik varyantları da vardır (https://en.wikipedia.org/wiki/Miller% E2% 80% 93Rabin_primality_test # Deterministic_variants_of_the_test) –

0

Diğer bazı basit geliştirmeler, olası sayı kümenizi, dış döngüdeki yalnızca iki ve tek sayılarla sınırlamak ve yalnızca "dizin" in kareköküne kadar çoğaltmaktır (veya çok zorsa dizin/2 ise) iç döngünüzde hesaplayın.

İlgili konular