Тестовый стенд делать не буду, но результаты скажу
Итак, что я знаю на данный момент по тестам на 150 тыс элементов массива: • --Format$() шустрее WorksheetFunction.Round() ~ 1,5 раза (Format или Format$ — на скорость не повлияло) • Round() шустрее --Format$() ~ 2 раза • CCur() где-то на уровне --Format$(), но всегда 4 знака - не подходит Вопрос: кто какие ещё методы/способы округления знает? Протестирую на своих данных
Скрин (собственно, сам участок кода): • 47 тыс строк • 3 столбца с округлением до 6ти • 3 столбца с округлением до 4ёх • 12 столбцов с округлением до 2ух
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Jack Famous написал: Тестовый стенд делать не буду
А я сделаю (на 1000000 обращений):
Код
Option Explicit
#If VBA7 Then
Private Declare PtrSafe Function getFrequency Lib "kernel32" Alias _
"QueryPerformanceFrequency" (cyFrequency As Currency) As Long
Private Declare PtrSafe Function getTickCount Lib "kernel32" Alias _
"QueryPerformanceCounter" (cyTickCount As Currency) As Long
#Else
Private Declare Function getFrequency Lib "kernel32" Alias _
"QueryPerformanceFrequency" (cyFrequency As Currency) As Long
Private Declare Function getTickCount Lib "kernel32" Alias _
"QueryPerformanceCounter" (cyTickCount As Currency) As Long
#End If
Function MicroTimer() As Double
' Returns seconds.
Dim cyTicks1 As Currency
Static cyFrequency As Currency
'
MicroTimer = 0
' Get frequency.
If cyFrequency = 0 Then getFrequency cyFrequency
' Get ticks.
getTickCount cyTicks1
' Seconds
If cyFrequency Then MicroTimer = cyTicks1 / cyFrequency
End Function
Sub Test()
Dim t As Double, nMax As Long, i As Long, d As Double
nMax = 1000000
t = MicroTimer
With WorksheetFunction
For i = 1 To nMax
d = .Round(1 + i / nMax, 2)
Next i
End With
Debug.Print "WorksheetFunction.Round", FormatNumber(MicroTimer - t, 3)
t = MicroTimer
For i = 1 To nMax
d = Round(1 + i / nMax + 0.00000001, 2)
Next i
Debug.Print "VBA.Round" & Space(10), FormatNumber(MicroTimer - t, 3)
t = MicroTimer
For i = 1 To nMax
d = CDbl(Format(1 + i / nMax, "0.00"))
Next i
Debug.Print "VBA.Format" & Space(10), FormatNumber(MicroTimer - t, 3)
End Sub
У меня разница в скорости в 20 раз. Так что, если банковское округление не важно, то WorksheetFunction.Round (как и другие обращения к объектной модели Excel из VBA) сразу снимаем с пробега.
Функция (VBA.)Round специально написана для округления, нет оснований сомневаться в ее работоспособности и эффективности.
вот видите - у вас аж в 20 раз разница Тестовый стенд не делал, потому что реальный проект мс данными и тест — это бывает 2 разных результата, но для "спортивного интереса" ничего лучше нет - это правда))) 1. смущает, что у вас WorksheetFunction и в With сидит и просто так 2. вы сравнили 2 крайности, т.к. я в основном --Format$() использую, а он шустрее (у меня разница с функцией листа и форматом — 40 и 20 раз соответственно) 3.
Цитата
Jack Famous:Round использует "банковское округление"
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Если убрать With, то будет чуть-чуть медленнее. Format делает кучу лишней работы. Если известен диапазон чисел, с которыми Вы работаете, то положительные числа можно округлять в таком стиле:
Код
d = Round(1 + i / nMax + 0.00000001, 2)
Чаще всего, особой практической разницы между всеми указанными методами нет, так как на миллионе операций речь идет о различиях в доли секунды.
Fix пошустрее вроде, но все - для целочисленных операций, а приведение к целому для их использования "съест" весь возможный выигрыш в скорости (не тестил) За вариант спасибо - для целых точно быстрее будет
Цитата
sokol92: практической разницы нет, так как на миллионе операций речь идет о различиях в доли секунды
на моих данных прирост скорости с Format$() на Round сократил время в 2(!) раза — с 4 секунд до 2ух (только цикл со скрина) Или вы про ваш вариант округления положительных?
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Round быстрее Format'а с последующим обратным преобразованием в число раз в 10 на современных машинах (раньше разрыв был больше). Значит, в Вашем тесте собственно Format занимал примерно половину от общего времени. Дополнил тест обращением к Format.
Public Function MyRoundFix(X As Double, R As Long) As Double
Dim D As Double
Dim i As Long
D = 1
For i = 1 To R
D = D * 10#
Next i
MyRoundFix = (Fix(X * D + 0.5)) / D
End Function
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Можно еще чуть ускорить (своеобразный "дизельгейт"), если каждый раз не вычислять множитель:
Код
Public Function MyRoundFixStatic(X As Double, R As Long) As Double
Static OldR As Long
Static D As Double
Dim i As Long
If R <> OldR Then
D = 1
For i = 1 To R
D = D * 10#
Next i
OldR = R
End If
MyRoundFixStatic = Fix(X * D + 0.5) / D
End Function
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Кстати, давно хотел написать о точности измерений. Сейчас (в момент написания заметки) функция Timer выдает свыше 61000 (сек). Учитывая, что тип результата функции - Single, а это 7 (?) значащих цифр, долям секунды вполне доверять нельзя. Пора менять измерительный инструмент на более точный, рекомендованный разработчиком. Еще раз изменил #3 - теперь точности измерений времени можно доверять.
sokol92: Пора менять измерительный инструмент на более точный, рекомендованный разработчиком
себе занёс (спасибо за науку), но не знаю, где нужна такая точность - таймера пока вполне хватает
Цитата
Jack Famous: у вас получается округление Round, но до следующего знака и по-моему это не тоже самое , что банковское округление…ща потестирую
на скрине примеры несоответствия обычного округления и "банковского", а вычисление d - вообще ни в какие ворота (ни 0,00000001 ни 0,01
Тестовый стенд
Код
Sub t()
Dim x, a, b, c, d, i&
Const nMax& = 10000
x = 0
For i = 1 To nMax
a = WorksheetFunction.Round(x, 2)
b = --Format$(x, "0.00"): If b <> a Then Debug.Print i, "b:", a & "<>" & b
c = Round(x, 2): If c <> a Then Debug.Print i, "c:", a & " <> " & c
' d = Round(x+0.000000001, 2): If d <> a Then Debug.Print i, "d:", a & " <> " & d
x = x + 0.001
Next i
End Sub
Цитата
Alec Perle: Можно и WorksheetFunction.Round ускорить, правда на доли процента
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
БМВ: Это пагубно сказываются результаты самоизоляции
повторюсь, что задача именно практическая. Ускоряю свои таблицы. Вот успешно применил Round и в 2 раза сократил время (на бОльших объёмах ещё больше получится) Сюда написал в надежде, что хоть кто-то поделится своими "фишками" и получится ещё быстрее - помнится ZVI как-то успешно писал математические аналоги
Цитата
БМВ: прям скучаю, уж сколько времени не встречаемся по утрам
и не будем больше (к сожалению), т.к. я переехал в другую часть города - там снимал. Может теперь вы захотите посидеть где-нибудь?
Цитата
Alec Perle: А что с ним не так? Ведь закомментировано же))
привёл код - пробуйте. Убрал, чтобы не забивать окно Innediate
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
sokol92: У меня в тесте #3 все три прогона выдают одинаковые результаты
вы про скорость (вряд ли) или про результаты округлений (где там сравнение)?
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
БМВ, после пандемии вернёмся к обсуждению посиделок
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄