Код (принимает случайным образом 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 минут, есть ли способ оптимизировать код, чтобы он работал быстрее?
8 минут для стольких записей не слишком долго. Имейте в виду, что копирование/вставка (или чтение из одной ячейки и запись значения в другое) в Excel занимает довольно много времени. – varocarbas
Я бы написал свою собственную функцию RandBetween, используя встроенную функцию Rnd VBA, вместо того, чтобы сделать запрос interprocess в Excel. Это должно немного ускорить работу, хотя, имея дело с такими многочисленными записями, требуется время для чтения с листа и записи. Вы можете попробовать сохранить все значения листа в массиве, хотя я никогда не пробовал его с такими большими данными, поэтому он может быть медленным и, возможно, даже невозможен. –
@JonFournier - реальное узкое место в CalcW (где я пытаюсь перейти через 2d-массив и вычислять средние значения и экспозиции), он занимает около 70% времени. Чтение и хранение данных с листа, похоже, отлично работает. не уверен, что его принятие так долго все время обрабатывается в ОЗУ – user2522749