2010-12-21 12 views
5
ben aşağıdaki collatz sanısı algoritması dönüştürmek çalışıyorum

:Parallel.For C#

public class CollatzConjexture 
    { 
     public static int Calculate(int StartIndex, int MaxSequence) 
     { 
      int ChainLength = 0; 
      int key = 0; 
      bool ContinuteCalulating = true; 
      int LongestChain = 0; 
      Int64 Remainder = 0; 

      for (int i = StartIndex; i <= MaxSequence; i++) 
      { 
       ChainLength = 1; 
       Remainder = i; 
       ContinuteCalulating = true; 

       while (ContinuteCalulating) 
       { 
        Remainder = CalculateCollatzConjecture(Remainder); 
        if (Remainder == 1) 
         ContinuteCalulating = false; 

        ChainLength += 1; 
       } 

       if (ChainLength > LongestChain) 
       { 
        LongestChain = ChainLength; 
        key = i; 
       } 
      } 

      return key; 
     } 

     private static Int64 CalculateCollatzConjecture(Int64 Number) 
     { 
      if (Number % 2 == 0) 
       return Number/2; 
      else 
       return (3 * Number) + 1; 
     } 
    } 

yerine .NET 4.0 Parallel.For kullanmak için: Ben Ben bir his var

int ChainLength = 0; 
      int key = 0; 
      bool ContinuteCalulating = true; 
      int LongestChain = 0; 
      Int64 Remainder = 0; 

      int[] nums = Enumerable.Range(1, 1500000).ToArray(); 
      long total = 0; 

      // Use type parameter to make subtotal a long, not an int 
      Parallel.For<int>(1, nums.Length,() => 1, (j, loop, subtotal) => 
      { 
       Remainder = j; 

       while (ContinuteCalulating) 
       { 
        Remainder = CalculateCollatzConjecture(Remainder); 
        if (Remainder == 1) 
         ContinuteCalulating = false; 

        ChainLength += 1; 
       } 

       if (ChainLength > LongestChain) 
       { 
        LongestChain = ChainLength; 
        key = j; 
       } 
       return key; 


      }, 
       (x) => Interlocked.Add(ref key, x) 
      ); 

ondan çok uzak değil, ünlü son sözler.

Şimdiden teşekkürler.

cevap

9

Sorununuz, bu örnekte, Parallel.ForEach numaralı çağıran yineleme için bir dizi (nums) bulunduğunuz için bu örnekte Parallel.For kullanmak istemediğinizdir. yaklaşık iki kat daha hızlı üzerinde olduğunu

public static class CollatzConjexture2 
{ 
    public static int Calculate(int StartIndex, int MaxSequence) 
    { 
     var nums = Enumerable.Range(StartIndex, MaxSequence); 
     return nums.AsParallel() 
        // compute length of chain for each number 
        .Select(n => new { key = n, len = CollatzChainLength(n) }) 
        // find longest chain 
        .Aggregate((max, cur) => cur.len > max.len || 
        // make sure we have lowest key for longest chain 
         max.len == cur.len && cur.key < max.key ? cur : max) 
        // get number that produced longest chain 
        .key; 
    } 

    private static int CollatzChainLength(Int64 Number) 
    { 
     int chainLength; 
     for (chainLength = 1; Number != 1; chainLength++) 
      Number = (Number & 1) == 0 ? Number >> 1 : Number * 3 + 1; 
     return chainLength; 
    } 
} 

Bu yöntem: Ancak, dizi Enumerable.Range oluşturulur ve aslında herhangi bir şey için kullanmak yok, bu yüzden en iyi yolu AsParallel ve LINQ (PLINQ) ile yapmanın bilgisayarım seri uygulama olarak. Ayrıca, ana döngüyü en iyi duruma getirdiğimden, bir işlevi çağırmak yerine hesaplamayı satır içi yapar ve çarpma ve bölme yerine bitsel matematik kullanır. Bu tekrar iki kat daha hızlı yaptı. X86 yerine x64 için derlemek aynı zamanda iki kat daha hızlı yaptı.

+0

Bunu çalıştırdığımda, en uzun Collatz zincirini (yani 1 - 1500000, seri yöntemi 1117065 ve LINQ yöntemi 1126015 döndüren en küçük dizini almam gerekir. Her ikisi de 528 zincir uzunluğundadır.). Sadece LINQ öğrenirken, bunu düzeltmek için '.Aggregate' çağrısını değiştirmenin basit bir yolu var mı? – chezy525

+0

Her iki yanıtı da, her nasılsa, hata ayıkladığımda (1117065, 1126015) ayrı durumlar için alıyorum. İdeal olarak, minimum endeksi istiyorum. Şimdiden teşekkürler. – Seany84

+1

Bunun için biraz uğraştıktan sonra, ".Aggregate" deki koşul deyimini değiştirmeniz gerektiğini düşünüyorum. "max.len cur.key) ' – chezy525