Объявление переменных за циклом или внутри цикла? - страница 2

 
Georgiy Merts:

Нет. Не шучу.

Безусловно, в данном случае нормальный компилятор объявление переменной внутри цикла должен выносить наружу.

Просто я считаю, что "на компилятор надейся, а сам не плошай". В стандарте компилятора принято, что локальная переменная создается в момент объявления, и удаляется при выходе из блока, в котором она была объявлена. А значит, на этот принцип и надо ориентироваться в первую очередь, а не ждать, что компилятор за тебя будет улучшать твой код.

Так вот я и говорю, если хотите "не плошать", то вперёд на ассемблер.  Раз вам нужно самому всё лично контролировать... Ведь описанный случай - это совершенный пустяк. Встречаются вещи на порядки сложнее.  ООП вам точно противопоказано. Вы ж не узнаете, выродил ли компилятор тот или иной виртуальный метод в обычный вызов, или вырезал ли излишнюю проверку указателя...  Что вообще можно делать на управляемом MQL с такой паранойей ? )

Да и подстраивать код под особенности компилятора (причём мнимые), в ущерб правильности и надёжности кода - это явно не то, чем должен заниматься хороший программист.  А здесь речь идёт именно о неправильности кода.  Переменная должна объявляться непосредственно в том блоке, в котором используется.

 
Vict:

Блин, ну это просто дикая дремучесть, чего тут комментировать, полное непонимание работы отладчика.

У вас - да.
 
Alexey Navoykov:
У вас - да.

Как в детском саду )) Объясняю для тех кто в танке: сначала компилируем g++ 1.cpp, там нет никаких точек останова, компилятор о них ничего не знает. Затем запускаем отладчик: gdb a.out, и только теперь ставим точку останова.

Понимаете, какую ерунду сказали?

 
Alexey Navoykov:

Обнаружить оптимизацию можно только по скомпилированному коду, ну либо замерив производительность.  Так вот это первое, что надо сделать. И успокоиться )

2019.08.18 10:28:12.826 SpeedTest (EURUSD,H1) 1. s1=rand(): loops=100000000 ms=7031

2019.08.18 10:28:19.885 SpeedTest (EURUSD,H1) 2. s2=rand(): loops=100000000 ms=7063

2019.08.18 10:28:27.037 SpeedTest (EURUSD,H1) 3. s3=rand(): loops=100000000 ms=7140

2019.08.18 10:28:34.045 SpeedTest (EURUSD,H1) 4. s4=rand(): loops=100000000 ms=7016

2019.08.18 10:28:41.135 SpeedTest (EURUSD,H1) 5. s5=rand(): loops=100000000 ms=7094

2019.08.18 10:28:47.896 SpeedTest (EURUSD,H1) 1. q=rand(): loops=100000000 ms=6750

2019.08.18 10:28:54.659 SpeedTest (EURUSD,H1) 2. q=rand(): loops=100000000 ms=6765

2019.08.18 10:29:01.447 SpeedTest (EURUSD,H1) 3. q=rand(): loops=100000000 ms=6797

2019.08.18 10:29:08.257 SpeedTest (EURUSD,H1) 4. q=rand(): loops=100000000 ms=6797

2019.08.18 10:29:15.102 SpeedTest (EURUSD,H1) 5. q=rand(): loops=100000000 ms=6844

//+------------------------------------------------------------------+
//|                                                    SpeedTest.mq5 |
//|                                                            IgorM |
//|                              https://www.mql5.com/ru/users/igorm |
//+------------------------------------------------------------------+
#property copyright "IgorM"
#property link      "https://www.mql5.com/ru/users/igorm"
#property version   "1.00"
#define N 8

#define   test(M,S,EX) {uint mss=GetTickCount();ulong nn=(ulong)pow(10,M);for(ulong tst=0;tst<nn&&!_StopFlag;tst++){EX;} \
                        printf("%s: loops=%i ms=%u",S,nn,GetTickCount()-mss);}
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   string s1; srand(GetTickCount()); test(N,"1. s1=rand()",s1=IntegerToString(rand()));
   string s2; srand(GetTickCount()); test(N,"2. s2=rand()",s2=IntegerToString(rand()));
   string s3; srand(GetTickCount()); test(N,"3. s3=rand()",s3=IntegerToString(rand()));
   string s4; srand(GetTickCount()); test(N,"4. s4=rand()",s4=IntegerToString(rand()));
   string s5; srand(GetTickCount()); test(N,"5. s5=rand()",s5=IntegerToString(rand()));

   srand(GetTickCount()); test(N,"1. q=rand()",string q=IntegerToString(rand()));
   srand(GetTickCount()); test(N,"2. q=rand()",string q=IntegerToString(rand()));
   srand(GetTickCount()); test(N,"3. q=rand()",string q=IntegerToString(rand()));
   srand(GetTickCount()); test(N,"4. q=rand()",string q=IntegerToString(rand()));
   srand(GetTickCount()); test(N,"5. q=rand()",string q=IntegerToString(rand()));
  }
//+------------------------------------------------------------------+
 
Покопал под отладчиком подобный код, но без пользовательского operator new, ну могли быть какие-нибудь сомнения - мол пользовательский оператор не оптимизируется. Отлавливал вызова malloc() из libc. Результат: стринг в цикле - вызов malloc перед каждым принтом, вне цикла - один вызов перед пачкой принтов. Тут уже никаких сомнений быть не может, лишь первый вариант лучше юзать. Конечно, возможно в мкл что-то иначе, но луче ориентироваться на взрослые языки.
 
#define N 9

2019.08.18 10:37:59.620 SpeedTest (EURUSD,H1) 1. s1=rand(): loops=1000000000 ms=70672

2019.08.18 10:39:10.352 SpeedTest (EURUSD,H1) 2. s2=rand(): loops=1000000000 ms=70719

2019.08.18 10:40:21.908 SpeedTest (EURUSD,H1) 3. s3=rand(): loops=1000000000 ms=71562

2019.08.18 10:41:32.315 SpeedTest (EURUSD,H1) 4. s4=rand(): loops=1000000000 ms=70407

2019.08.18 10:42:42.996 SpeedTest (EURUSD,H1) 5. s5=rand(): loops=1000000000 ms=70687

2019.08.18 10:43:50.964 SpeedTest (EURUSD,H1) 1. q=rand(): loops=1000000000 ms=67969

2019.08.18 10:44:58.887 SpeedTest (EURUSD,H1) 2. q=rand(): loops=1000000000 ms=67922

2019.08.18 10:46:06.829 SpeedTest (EURUSD,H1) 3. q=rand(): loops=1000000000 ms=67937

2019.08.18 10:47:14.602 SpeedTest (EURUSD,H1) 4. q=rand(): loops=1000000000 ms=67766

2019.08.18 10:48:22.428 SpeedTest (EURUSD,H1) 5. q=rand(): loops=1000000000 ms=67828

 

Igor Makanu:

#define   test(M,S,EX) {uint mss=GetTickCount();ulong nn=(ulong)pow(10,M);for(ulong tst=0;tst<nn&&!_StopFlag;tst++){EX;} \

Блин, у вас клавиша "пробел" не работает чтоль? )  Уже не первый раз замечаю.  Или экономите байты на жёстком диске? )

 
Alexey Navoykov:

Вы не шутите?  Это настолько тривиальная ситуация для компилятора, что тут даже говорить нечего.  А с такой паранойей можно надо чисто на ассемблере кодировать )  Хотя даже это уже становится бессмысленным по нынешним временам.  Чтобы переплюнуть оптимизации современных компиляторов - это надо очень сильно постараться.

p.s. Возможно я немного погорячился насчёт тривиальности в данном случае, т.к. речь идёт о буфере строки. Но он гарантированно сохраняется в MQL.  Причём не только внутри цикла, но даже между вызовами функции. Тут не раз обсуждалась эта тема

У меня есть подозрение, что автор сего высказывания вообще не в курсе, как работает процессор, память и компилятор... Готов поспорить, что любой ваш код можно ускорить минимум в десятки раз, а то и в сотни.  Из-за таких говнокодеров большинство продуктов сейчас безбожно тормозят на мощнейших компьютерах с десятками ядер, а надо-то всего лишь немножко подумать... Но некоторые считают - "Зачем думать? Надо кодить..."

К Вашему сведению, на данный момент ни один компилятор еще не научился понимать то, что в результате хотел получить программист. Он может развернуть некоторые циклы, оптимизировать некоторые обращения к памяти, чтоб данные находились в кэше процессора, но если код изначально не оптимизирован и написан через одно место, то ни один компилятор Вам не поможет...

P.S. Почитайте на досуге занимательную книжечку Крис Касперски "Техника оптимизации программ. Эффективное использование памяти"

 
Alexey Volchanskiy:

Жорж прав, это не гарантированно.

И получаем варнинг implicit conversion from 'number' to 'string'


И   А вот так точно избавляемся от неопределенности и варнинга

for (int i = 0; i < 1000; i++)
   {
      static string st = IntegerToString(i);
      ...
   }

А я так делал всегда 

string st = (string)i;

Да и зачем static? присвоение только один раз сработает в первой итерации


Решил замерить скорость выполнения

   CStopWatch sw; // Секундомер, для замера времени
   
   sw.Start();
   for (int i = 0; i < 10000000; i++)
   {
      string st = (string)i;
   }
   pr("Test1, время выполнения: " + sw.Stop());

   sw.Start();
   string st = "";
   for (int i = 0; i < 10000000; i++)
   {
      st = (string)i;
   }
   pr("Test2, Время выполнения: " + sw.Stop());

Результат:

Test1, время выполнения: 0.548275 сек.
Test2, Время выполнения: 0.313978 сек.

Запускал много раз, результат стабилен, код с объявлением переменной за циклом, работает быстрее

 
Alexey Navoykov:

Блин, у вас клавиша "пробел" не работает чтоль? )  Уже не первый раз замечаю.  Или экономите байты на жёстком диске? )

неее, этот код не мой, причесал немного - я код себе скопировал из топика про "поиск кол-ва знаков после запятой" и юзаю по спорным вопросам, править как то лень, 

в общем пробелы у меня есть и лень есть ))))

ЗЫ: дайте образцовый код, скопирую себе, будет так как Вы пожелаете в дальнейшем, меня, в принципе, не напрягает это  

ЗЫ: вотЪ :

#define   test(M,S,EX) {                                 \
uint mss=GetTickCount();                                 \
ulong nn=(ulong)pow(10,M);                               \
for(ulong tst=0;tst<nn && !_StopFlag;tst++) \
{ EX; }                                                  \
printf("%s: loops=%i ms=%u",S,nn,GetTickCount()-mss);}