我在下面有以下代码。我想就如何改进/重写最小化提出建议和建议;
1)所花费的时间 2)操作次数
假设代码中所有整数变量都非常大 - 例如每个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()
中的元组(a,b,c,d)。
**特别是,最慢的部分似乎是'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 :(得分:1)
如果不完全了解您的数据,也不知道它有多大,可以通过一次性获取VBA数组中所需的所有数据来优化它。
您的代码基本上从第1列和第2列中的单元格反复取出.Value
。每次越过这样的VBA / Excel边框时,您支付(小)开销成本,但支付该价格太多次加起来。
而是尝试仅在第1列和第2列中获取数据,而是从这些数组中进行操作。例如:
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)
。 (请注意,此处返回的数组是二维数组,其中第一个索引是行,第二个索引是列。)
答案 1 :(得分:1)
此外,您可以在代码开头使用此功能禁用计算和屏幕更新:
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
最后,回到正常状态:
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
小心宏崩溃。当崩溃发生时,请记住将它恢复正常。