2013-06-28 3 views
0

Код (принимает случайным образом 2d массив (R, C)) и перерывы приводит вниз в 2 массивы для каждого месяца (21 дней) (1 для среднего, 1 для облучения)Оптимизация медленного VBA Code

Public R As Double 
Public C As Integer 
Public Strike,Spot,Ton As Double 
Public Ton As Double 
Public AVG(), EXP(), w() As Variant 
'''''''''''''' 
Sub Start() 
sss = SetParmeters() 
MonteCarlo (Copy2Array()) 
i = calcW() 
cpSheet (True) 
End Sub 
''''''''''''''' 
    Function SetParmeters() As Boolean 
Dim w As Worksheet 
Set w = Worksheets("Copper daily moves") 
R = w.Range("cc") 
C = w.Range("row") 
Strike = w.Range("strike") 
Spot = w.Range("spot") 
Ton = w.Range("ton") 
End Function      
''''''''''''''''''' 
Function Copy2Array() As Variant 
    Dim w As Worksheet 
    Set w = Worksheets("Copper daily moves") 
    Copy2Array = w.Range("price") 
End Function 
'''''''''''''''''''' 
Function MonteCarlo(p As Variant) 
ReDim w(R, C) 
For i = 0 To R 
s = Spot 
For j = 0 To C 
w(i, j) = s * (1 + p(Application.WorksheetFunction.RandBetween(1, 1275), 1)) 
s = w(i, j) 
Next j 
Next i 
End Function 
'''''''''''''''' 
Function calcW() As Boolean 
ReDim AVG(R, (C/21) - 1) 
ReDim EXP(R, (C/21) - 1) 
Count21 = 0 
countW = 0 
For i = 0 To R 
Sum = 0 
countW = 0 
Count21 = 21 
For j = 0 To C 
Sum = Sum + w(i, j) 
If Count21 = j Then 
AVG(i, countW) = Sum/21 
If Strike > AVG(i, countW) Then 
EXP(i, countW) = (Strike - AVG(i, countW)) * ((C/21) - countW) * Ton 
Else 
EXP(i, countW) = 0 
End If 
countW = countW + 1 
Count21 = Count21 + 21 
Sum = 0 
End If 
Next j 
Next i 
End Function 
'''''''''''''' 
Sub cpSheet(flag) 
Addr = "$A$1" 
Addr = Addr & ":" & Range(Addr).Cells(UBound(AVG), _ 
UBound(AVG, 2) + 1).Address 
Worksheets("AVG").Range(Addr).Value = AVG 
Worksheets("EXP").Range(Addr).Value = EXP 
End Sub 

Основная проблема заключается в том, что для обработки данных требуется много времени (особенно при работе в симуляциях (строках) и т.п.), и, следовательно, может быть быстрее сделать это с помощью Excel-листов, а не VBA !!.

Я тестировал его с (R = 100k, c = 252), и это занимает около 8 минут, есть ли способ оптимизировать код, чтобы он работал быстрее?

+0

8 минут для стольких записей не слишком долго. Имейте в виду, что копирование/вставка (или чтение из одной ячейки и запись значения в другое) в Excel занимает довольно много времени. – varocarbas

+0

Я бы написал свою собственную функцию RandBetween, используя встроенную функцию Rnd VBA, вместо того, чтобы сделать запрос interprocess в Excel. Это должно немного ускорить работу, хотя, имея дело с такими многочисленными записями, требуется время для чтения с листа и записи. Вы можете попробовать сохранить все значения листа в массиве, хотя я никогда не пробовал его с такими большими данными, поэтому он может быть медленным и, возможно, даже невозможен. –

+0

@JonFournier - реальное узкое место в CalcW (где я пытаюсь перейти через 2d-массив и вычислять средние значения и экспозиции), он занимает около 70% времени. Чтение и хранение данных с листа, похоже, отлично работает. не уверен, что его принятие так долго все время обрабатывается в ОЗУ – user2522749

ответ

1

Попробуйте не использовать типы Variant, а также использовать

Application.ScreenUpdating = False 

рано в коде и

Application.ScreenUpdating = True 

... в конце кода.

Другим советом является замена «/» деления (возвращает одно значение) на «\» деление (возвращает целочисленное значение). Это, особенно внутри цикла, может немного улучшить его производительность.

 Смежные вопросы

  • Нет связанных вопросов^_^