2016-10-11 28 views
5

Şu anda bir ProjectEuler problem çözülmeye çalışıyorum ve her şeyim var, hız hariç. Programın çok yavaş yürütmesinin sebebinin iç içe döngülerden kaynaklandığından neredeyse eminim. Bunu hızlandırmak için bazı tavsiyeleri çok isterim. Ben acemi bir programcıyım, bu yüzden daha gelişmiş yöntemler/konular ile aşina değilim.Bu programı nasıl hızlandırabilirim?

public class Problem12 { 

    public static void main(String[] args) { 
     int num; 

     for (int i = 1; i < 15000; i++) { 
      num = i * (i + 1)/2; 
      int counter = 0; 

      for (int x = 1; x <= num; x++) { 
       if (num % x == 0) { 
        counter++; 
       } 
      } 
      System.out.println("[" + i + "] - " + num + " is divisible by " + counter + " numbers."); 
     } 
    } 
} 

DÜZENLEME: Aşağıda katlanarak hızlıdır yeni kodudur. Daha fazla hızlandırmak için sabit çizgi baskısını da kaldırdı. bölenler bakarken kare kökü aşağıdaki her bölen üzerinde bir eşdeğer olduğundan

public class Problem12 { 

    public static void main(String[] args) { 
     int num; 

     outerloop: 
     for (int i = 1; i < 25000; i++) { 
      num = i * (i + 1)/2; 
      int counter = 0; 

      double root = Math.sqrt(num); 
      for (int x = 1; x < root; x++) { 
       if (num % x == 0) { 
        counter += 2; 
        if (counter >= 500) { 
         System.out.println("[" + i + "] - " + num + " is divisible by " + counter + " numbers."); 
         break outerloop; 
        } 
       } 
      } 
     } 
    } 
} 
+1

C gibi daha hızlı bir dil kullanmayı deneyin ve onlar Java –

+0

mevcut iseniz bu algoritma çalışması hiç mi, bitshifts yerine bölünme ve çarpma kullanmayı deneyin? Yani "i = 3" sonra "num = 6" ve sonra "counter = 4" yanlış – afsafzal

+4

@ShaheAnsar gibi C'nin bunun için Java'dan daha hızlı olduğunu nasıl tahmin edersiniz? bitshifts desteklenir? – njzk2

cevap

5

başlayanlar için, sen sayının kök kareden daha ileri gitmek gerekir asla.

n = a * b => a <= sqrt(n) or b <= sqrt(n) 

Sonra bölünme diğer tarafını saymak gerekir: sadece

if ((double) ((int) root) == root) { 
    counter += 1; 
} 
+0

Bu hile yaptı. Ancak, nasıl emin değilim. Bunun neden işe yaradığını biraz düşünür müsün? – jxshu

+1

her bölen bir çift olarak çalışıyor, bu yüzden her birini iki kere sayıyoruz. Her bir çift için, elemanlardan biri karekökün altında, diğeri ise yukarıda. Bunu görmek çok kolaydır: eğer her iki eleman da üzerindeyse, sonuç da üzerindedir. Her ikisi de altındaysa, sonuç da aşağıdadır. Örnek: '10 = 2 * 5 = 1 * 10'. 2 ve 1, 3.16, 5 ve 10'un altındadır. – njzk2

+0

althoug, Şimdi üçgenin _and_ kare sayısı olmadığından yanıldım – njzk2

0

Sen: Yalnızca bir kez tamsayı ise sayıldığı için

double root = Math.sqrt(num); 
for (int x = 1; x < root; x++) { 
    if (num % x == 0) { 
     counter += 2; 
    } 
} 

karekök özeldir sayıyı hesaplamak gerekiyor. p^a * q^b * r^c, (a+1)*(b+1)*(c+1) bölümlerine sahiptir. İşte bazı temel uygulama bu fikri kullanıyor:

static int Divisors(int num) { 
    if (num == 1) { 
     return 1; 
    } 

    int root = (int) Math.sqrt(num); 
    for (int x = 2; x <= root; x++) { 
     if (num % x == 0) { 
      int c = 0; 
      do { 
       ++c; 
       num /= x; 
      } while (num % x == 0); 
      return (c + 1) * Divisors(num); 
     } 
    } 

    return 2; 
} 

public static void test500() { 
    int i = 1, num = 1; 
    while (Divisors(num) <= 500) { 
     num += ++i; 
    } 

    System.out.println("\nFound: [" + i + "] - " + num); 
} 
İlgili konular