Хочу поделиться с программистами своей неожиданной, простой и полезной находкой.
Функции округления:
оказались весьма медлительными. Чтобы убыстрить процесс округления в 4-5 раз (по моим тестам на MQL5) можно заменить эти функции простой альтернативой:
Т.к. эти функции часто используются в больших и вложенных циклах выигрыш в производительности может быть весьма существенным.
Наверное просто факт вызoва функции весьма затратный по времени (сохранения в стек разных данных, адресов и т.д.). А в данном случае можно обойтись без функций.
Файл скрипта с тестом производительности прилагаю.
Только я с этой строкой
y=round(x); -> y=(int)(x+0.5);
не согласен. По правилам математики если дробная часть меньше 0.5 то округление делается в меньшую сторону. Но если к 45.27 ещё прибавить 0.5 то округлится до большего.
Только я с этой строкой
не согласен. По правилам математики если дробная часть меньше 0.5 то округление делается в меньшую сторону. Но если к 45.27 ещё прибавить 0.5 то округлится до большего.
#define MUL(x) ((x)+(0.5)) //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { ulong t0,t1,t2,t3; int y0[],y1[],y2[]; ArrayResize(y0,10000000); ArrayResize(y1,10000000); ArrayResize(y2,10000000); double x=1.45; for(int i=0;i<10000000;i++) { if ((int)(x+0.5)!=(int)round(x)) Print("ой...",x); x+=0.27; y0[i]+=0; y1[i]+=0; y2[i]+=0; } Print("y0[]: ",y0[9999999]," / y1[]: ",y1[9999999]," / y2[]: ",y2[9999999]); x=1.45; t0=GetMicrosecondCount(); for(int i=0;i<10000000;i++) { y0[i]=(int)MathRound(x); x+=0.27; } t1=GetMicrosecondCount()-t0; Print("y0[]: ",y0[9999999]); x=1.45; t0=GetMicrosecondCount(); for(int i=0;i<10000000;i++) { y1[i]=(int)(x+0.5); x+=0.27; } t2=GetMicrosecondCount()-t0; Print("y1[]: ",y1[9999999]); x=1.45; t0=GetMicrosecondCount(); for(int i=0;i<10000000;i++) { y2[i]=(int)MUL(x); x+=0.27; } t3=GetMicrosecondCount()-t0; Print("y2[]: ",y2[9999999]); Print("Цикл округления 10 000 000 раз: (round) = ",IntegerToString(t1)," альтернатива с (int) = ",IntegerToString(t2)," альтернатива с (#define) = ",IntegerToString(t3)," микросекунд"); } //+------------------------------------------------------------------+
Только я с этой строкой
не согласен. По правилам математики если дробная часть меньше 0.5 то округление делается в меньшую сторону. Но если к 45.27 ещё прибавить 0.5 то округлится до большего.
Что то вы путаете. Я в пример специально вставил проверочный код:
for(int i=0;i<10000000;i++) { if ((int)(x+0.5)!=(int)round(x)) Print("ой...",x); x+=0.27; }
если бы я был не прав, тогда бы выполнился бы оператор Print("ой...",x);
Попробуйте - все Ок.
Только я с этой строкой
не согласен. По правилам математики если дробная часть меньше 0.5 то округление делается в меньшую сторону. Но если к 45.27 ещё прибавить 0.5 то округлится до большего.
А если взять и проверить? ))) Каким образом int(45.27 + 0.5) даст 46? Те же 45 и останутся.
Я не о скорости говорил.
Что то вы путаете. Я в пример специально вставил проверочный код:
если бы я был не прав, тогда бы выполнился бы оператор Print("ой...",x);
Попробуйте - все Ок.
Но все равно интересно что скорость меняется если массив заранее не заполнять данными
#define _round(x) (int)((x)+(0.5)) //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { ulong t0,t1,t2; int y0[],y1[]; ArrayResize(y0,10000000); double x=1.45; for(int i=0;i<10000000;i++) { if ((int)(x+0.5)!=(int)round(x)) Print("ой...",x); x+=0.27; y0[i]+=0; // !!!!!!!!!!!!!! } x=1.45; t0=GetMicrosecondCount(); for(int i=0;i<10000000;i++) { y0[i]=(int)(x+0.5); x+=0.27; } t1=GetMicrosecondCount()-t0; x=1.45; t0=GetMicrosecondCount(); for(int i=0;i<10000000;i++) { y0[i]=_round(x); x+=0.27; } t2=GetMicrosecondCount()-t0; Print("Цикл округления 10 000 000 раз: с (int) = ",IntegerToString(t1)," с (#define) = ",IntegerToString(t2)," микросекунд"); } //+------------------------------------------------------------------+
и заполнять
#define _round(x) (int)((x)+(0.5)) //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { ulong t0,t1,t2; int y0[],y1[]; ArrayResize(y0,10000000); double x=1.45; for(int i=1;i<10000000;i++) { if ((int)(x+0.5)!=(int)round(x)) Print("ой...",x); x+=0.27; y0[i]+=1; // !!!!!!!!!!!!!! } x=1.45; t0=GetMicrosecondCount(); for(int i=0;i<10000000;i++) { y0[i]=(int)(x+0.5); x+=0.27; } t1=GetMicrosecondCount()-t0; x=1.45; t0=GetMicrosecondCount(); for(int i=0;i<10000000;i++) { y0[i]=_round(x); x+=0.27; } t2=GetMicrosecondCount()-t0; Print("Цикл округления 10 000 000 раз: с (int) = ",IntegerToString(t1)," с (#define) = ",IntegerToString(t2)," микросекунд"); } //+------------------------------------------------------------------+
А если взять и проверить? ))) Каким образом int(45.27 + 0.5) даст 46? Те же 45 и останутся.
Согласен, тормознул. Беру свои слова взад...
Но все равно интересно что скорость меняется если массив заранее не заполнять данными
и заполнять
y0[i]+=0; // !!!!!!!!!!!!!!
С "#define" на мой взгляд удобней
#define _floor(x) (int)((x)) #define _ceil(x) (int)((x)+(1)) #define _round(x) (int)((x)+(0.5))
А почему не к лонгу кастуете? Хотя и его можно переполнить, но переполнить инт много легче.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Хочу поделиться с программистами своей неожиданной, простой и полезной находкой.
Функции округления:
оказались весьма медлительными. Чтобы убыстрить процесс округления в 4-5 раз (по моим тестам на MQL5) можно заменить эти функции простой альтернативой:
Т.к. эти функции часто используются в больших и вложенных циклах выигрыш в производительности может быть весьма существенным.
Наверное просто факт вызoва функции весьма затратный по времени (сохранения в стек разных данных, адресов и т.д.). А в данном случае можно обойтись без функций.
Файл скрипта с тестом производительности прилагаю.