2017-01-25 12 views
0

以下のコードがあります。どのように改良したり、書き直して最小化するかについて、アドバイスや提案をお願いしたいと思います。 2を取らExcel VBAコードをより効率的にして時間を短縮する方法

1)時間操作

推定全コードの整数であるが非常に大きくなる可能性変数の)番号 - 例えば各dim as Long、及びコードの> 0

目的は、カウントします変数iに格納されている数学問題(https://math.stackexchange.com/questions/2093497/finding-number-of-coprime-tuples-from-1-to-n/2094773)の解のタプル(a、b、c、d)の数をそれぞれArray_abcd()に格納します。

**特に、最も遅い部分は'Calculate tuples for F(i,j)=1 stored in Array_u_Fij()の下にあるコードのようです - 私はBig-O n^5の時間の複雑さを計算します。** - これが今ヘルプをリクエストしています。

機能モデューロ:

Function Modulo(x as long, y as long, p as long) as Long 

Modulo = x * y mod p 

End Function 

メインサブ:正確にあなたのデータを知らず

Sub Number_tuples() 

'This is limited by the number of rows and column an 
'.xlsm file can have. 
Application.screenupdating=false 
Application.displayalerts=false 
Application.calculation=xlcalculationmanual 

Prime1=599 
Prime2=601 
p=Prime1 * Prime2 

'Set up sheet 1 
... 
'Set up sheet 2 
... 

'Declare Array_Ints() 
Redim Array_ints(4) 

'Store list of integers to be given in question 
'This can be any list of integers 
Array_ints(0)=1 
Array_ints(1)=10 
Array_ints(2)=100 
Array_ints(3)=1000 

'Calculate N 
N=Ubound(Array_ints) 

'Declare array Array_nu_Fij() 
Redim Array_nu_Fij(N,N,2) 

'Calculate all non-unique Fij and store results in Array_nu_Fij(), and put matrix of nu_Fij values in sheet 1 
... 
Array_nu_Fij(i,j,0) = Modulo(a,b,p) 
Array_nu_Fij(i,j,1) = Cstr(a) & "," & Cstr(b) 
sht1.cells(i+2, j+1).value=Array_nu_Fij(i,j,0) 
... 

'Declare Array_u_Fij() 
ReDim Array_Fij(N*N,3) 

'Calculate all unique Fij 
'Store uFij value in Array_u_Fij(o,0), and a_b in Array(o,1) 
'Put a_b value in worksheet 2 
... 

'Put freq from worksheet 2 in Array_u_Fij() 
... 


'Calculate size of 1st col of Array_u_Fij() 
lastrow_new_sht2= sht2.Cells(sht2.Rows.Count, "A"). End(xlUp).Row 
startrow_sht2 = 3 
size_u_Fij_1col = lastrow_new_sht2 - startrow_sht2 + 1 

'Declare Array_abcd() 
ReDim Array_abcd(N*N) 

'Calculate tuples for F(i,j)=1 stored in Array_u_Fij() 
i=0 
For m = 0 to size_u_Fij_1col - 1 
    'Store current u_Fij and freq being considered 
    u_fij_1= Array_u_Fij(m,0) 
    Freq = Array_u_Fij(m,1) 
    a_b = Array_u_Fij(m,2) 
    c_d = "" 
     While freq > 1 
      'First compare u_Fij_1 with current u_Fij_1 
      For freq_gt_1 = 2 to freq 
       'Check if u_Fij_1 = 1 
       If u_fij_1 = 1 then 
        dblGCD = 1 
        i = i +1 
        Array_abcd(m)= Array_abcd(m) & "||" & a_b 
       Else 
        'GCD of u_Fij_1 with other u_Fij_1 
        dblGCD = u_Fij_1 
        If dblGCD = 1 then 
         i = i + 1 
         Array_abcd(m)= Array_abcd(m) & "||" & a_b 
        Else 
        End if 
       End if 
      Next freq_gt_1 

      '2nd compare u_Fij_1 with u_Fij_2<>u_Fij_1 
      For q = 1 to lastrow_sht2 
       If m+q >= size_u_Fij_1col then 
        'Array_u_Fij(m+q) doesn't exist 
        'Hence no need to check 
       Else 
        u_Fij_2 = Array_u_Fij(m+q+1,0) 
        freq_other = Array_u_Fij(m+q+1,1) 
        c_d = Array_u_Fij(m+q+1,2) 
        'Only consider freq_other > 0 
        While freq_other > 0 
         if u_Fij_1 =1 then 
          'GCD is 1 
          dblGCD = 1 
          Array_abcd(m)= Array_abcd(m) & "||" & a_b & "," & c_d 
          i = i + 1 
         Elseif u_Fij_1 = u_Fij_2 then 
          dblGCD = u_Fij_1 
          If dblGCD = 1 then 
           i = i + 1 
           Array_abcd(m)= Array_abcd(m) & "||" & a_b & "," & c_d         
          Else 
          End if 
         Elseif u_fij_2 = 1 then 
          dblGCD = 1 
          i = i +1 
          Array_abcd(m)= Array_abcd(m) & "||" & a_b & "," & c_d 
         Else 
          dblGCD = Application.WorksheetFunction.GCD(u_Fij_1,u_Fij_2) 
          If dblGCD = 1 then 
           i = i + 1 
           Array_abcd(m)= Array_abcd(m) & "||" & a_b & "," & c_d         
          Else 
          End if 
        Else 
        End if 
        Freq_other = freq_other - 1 
       Wend 
      End if 
     Next q 
     Freq=freq - 1 
    Wend 

    While freq=1 
     'Compare a=u_Fij_1 with b=u_Fij_2<>1 
     For q = 0 To size_uFij_1col 
      'Check if m+q is equal to or larger than size of 
      'array 
      If m+q >= size_uFij_1col then 
       'Do nothing 
      Else 
       If u_fij_1 = 1 then 
        dblGCD = 1 
        Array_abcd(m)=Array_abcd(m) & "||" & a_b & "," & c_d 
        i= i+1 
       Else 
        'u_Fij_1 <>1. Now need to consider freq of other u_Fij_2=b<>a 
        u_Fij_2 = Array_u_Fij(m+q+1,0) 
        freq_other=Array_uFij(m+q+1,1) 
        c_d=Array_uFij(m+q+1,2) 
        'Only consider freq_other > 0 
        While freq_other > 0 
         'Check if u_Fij_2 =1 
         If u_Fij_2 = 1 then 
          'GCD is 1 
          Array_abcd(m)=Array_abcd(m) & "||" & a_b & "," & c_d 
          i = i + 1 
         Else 
          'Need to determine GCD 
          dblGCD = Application.WorksheetFunction.GCD(u_Fij_1,u_Fij_2) 
          If dblGCD = 1 then 
           I = I+ 1 
           Array_abcd(m)=Array_abcd(m) & "||" & a_b & "," & c_d 
          Else 
          End if    
         End if 
         Freq_other = Freq_other - 1 
        Wend 
        End if 
      End if 
     Next q 
     Freq=freq - 1 
    Wend 
Next m 

Application.screenupdating=true 
Application.displayalerts=true 
Application.calculation=xlcalculationautomatic 

End Sub 
+0

誰かがコードを改善できるかどうかは、正確に*何をする/しなければならないのかほとんど疑いがありません。 –

+0

あなたは、少なくとも各セクションが達成するためのものであることをコードにコメントする必要があります...あるいは、コード全体が何を達成しようとしているのかを説明し、誰かがそれを行うより速い方法を持っているかもしれません! – Wolfie

+0

完了。更新された質問 –

答えて

1

、またどのように大きなそれはすることができ、それは一つに必要なすべてのデータをフェッチすることにより最適化される可能性がありますに行きますVBA配列。

あなたのコードは基本的に1列目と2列目のセルから.Valueを繰り返しフェッチします。このようにVBA/Excelの境界線を越えるたびに、(オーバーヘッドの)コストはかかりますが、加算されます。

代わりに列1と2のデータを1回だけフェッチし、代わりにこれらの配列から処理してください。例えば同様に:

Dim col1Values As Variant 
col1Values = sht2.Range(sht2.Cells(1, 1), sht2.Cells(lastrow_sht2, 1)).Value 
Dim col2Values As Variant 
col2Values = sht2.Range(sht2.Cells(1, 2), sht2.Cells(lastrow_sht2, 2)).Value 

ともうsht2.Cells(m, 1).Valueを使用しないではなく、その後col1Values(m, 1)から。 (ここでExcelが返す配列は2次元配列で、最初のインデックスが行、2番目の列です)

+0

Ok完了。質問が更新されました。レビューしてください。 –

1

また、演算中に計算中にこれを無効にすることができます。コード:

Application.ScreenUpdating = False 
Application.Calculation = xlCalculationManual 

と終了時に、通常の状態に戻す:

Application.ScreenUpdating = True 
Application.Calculation = xlCalculationAutomatic 

は、マクロクラッシュに注意してください。クラッシュが発生したときにそれらの変数を通常の状態に戻すことを忘れないでください。

+0

OKです。質問が更新されました。レビューしてください。 –

+1

'.ScreenUpdating'と'。「計算」は、細胞の内容を変更する場合にのみ有益です。この場合、セルは読み込みのみ、書き込まれません。 –

+0

そして、 '.Calculation'プロパティを使用する良い方法は、RAIIをそれに適用することです(https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization)。 'Class_Initialize'で' .Calculation'を無効にし、 'Class_Terminate'の初期値にリセットするクラスモジュールを作ります。あなたのサブの一番上にあるこれらのうちの1つだけを 'New'とし、それが範囲外になると(エラーも)、自動的に.Calculationがリセットされます。計算を途中で有効にする必要がある場合は、その場でNothingに設定します。 –

関連する問題