Особенности языка mql5, тонкости и приёмы работы - страница 308

 
fxsaber #:
b5179, еще одно интересное поведение компилятора.

Если во время сложения выполнить дополнительную битовую операцию, то скорость выполнения увеличивается на 40 %.

Строка поиска: Ошибка 139.

Кстати, я случайно обнаружил, что ArrayInitialize(array, 0) гораздо быстрее, чем ZeroMemory(array) для массивов long[].
Это может иметь значение в конструкторе класса или методе reset().
 
fxsaber #:

Вторая функция обнуляет размер массива.

Неправильно!
ZeroMemory() обнуляет все элементы массива. (Размер при этом не изменяется).

См. пример в документации:
 
amrali #:
Неправильно!

Я пишу в русскоязычной ветке, которая автоматически переводится в англоязычную, что Вы читаете.

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

 
amrali #:
2. Более быстрое время доступа, которое было достигнуто здесь, никогда не связано с объектом или структурой, оно просто обусловлено оптимизацией компилятора для оператора "switch".

3. Оптимизация switch зависит от количества случаев + режима оптимизации. Большое количество или сложные переключатели не получат такой оптимизации таблицы переходов и останутся в виде нескольких if-else.

4. Таблица поиска с использованием массива всегда будет стандартным и самым надежным методом, не зависящим ни от количества случаев, ни от их сложности, ни от режима оптимизации компилятора.
int Lookup_Table(int x)
  {
   static int table[16] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150};
   return table[x];
  }

// При компиляции маленького или среднего переключателя с последовательными случаями (от 0 до n), при
// в режиме оптимизации компилятор преобразует серию этих нескольких if-else
// операторов O(n) в таблицу переходов, где массив указателей на блоки кода
// индексируется по номеру дела во время выполнения, обеспечивая O(1) прямой доступ, подобный
// в таблицу поиска с помощью массива.
int Switch(int x)
  {
   switch(x)
     {
      case 0: return 0;
      case 1: return 10;
      case 2: return 20;
      case 3: return 30;
      case 4: return 40;
      case 5: return 50;
      case 6: return 60;
      case 7: return 70;
      case 8: return 80;
      case 9: return 90;
      case 10: return 100;
      case 11: return 110;
      case 12: return 120;
      case 13: return 130;
      case 14: return 140;
      case 15: return 150;
     }
   return -1;
  }

void OnStart()
  {
   long sum1 = 0;
   long sum2 = 0;
   int slots = 16;
   int test_count = 1 e8;

   int seed = MathRand();

   ulong time1 = GetMicrosecondCount();
   for(int i = 0; i < test_count; i++)
      for(int x = 0; x < slots; x++) {
         //int j = (x * 7 + seed) % slots; // отмените две строки для проверки поиска в случайном порядке (алгоритм Miller Shuffle)
         //sum1 += Lookup_Table(j); //в реальной ситуации поиск не является последовательным
         sum1 += Lookup_Table(x);
      }
   time1 = GetMicrosecondCount() - time1;
   PrintFormat("%6ull microsec,  sum:%ull %s", time1, sum1, " // Lookup table");

   ulong time2 = GetMicrosecondCount();
   for(int i = 0; i < test_count; i++)
      for(int x = 0; x < slots; x++) {
         //int j = (x * 7 + seed) % slots;
         //sum2 += Switch(j);
         sum2 += Switch(x);
      }
   time2 = GetMicrosecondCount() - time2;
   PrintFormat("%6ull microsec,  sum:%ull %s", time2, sum2, " // Switch statement");
  }

Максимальная оптимизация:

// 43834ll микросекунд, сумма:4035883008ll // Таблица поиска
// 6179ll микросекунд, сумма:4035883008ll // Оператор переключения

Более быстрое время доступа обусловлено сгенерированной таблицей переходов в режиме полной оптимизации.

Без оптимизации:

// 2636121ll микросекунд, сумма:4035883008ll // Таблица поиска
// 4120042ll микросекунд, сумма:4035883008ll // Оператор переключения
 

Простой и надежный код для генерации полного 32-битного беззнакового случайного числа в диапазоне [0, UINT_MAX]:

MathRand()^_RandomSeed;

мы также можем использовать его в качестве функции

uint random32(void)
{ 
   return MathRand()^_RandomSeed;
}

ulong random64(void) 
{ 
   return ((ulong)random32 << 32) + random32();  // [0, ULONG_MAX]
} 
 

Старая ошибка снова возвращается.

Доказательств нет, но printf() в экспертном журнале снова усекает выводимые строки, причем произвольно.

Очевидно, что ограничение на печать строк, превышающих размер 16K, снова обрезается, как это было довольно много лет назад, и теперь вернулось. - Единственное возможное исправление - примерно такое:


            void mq5_fixed_printf(string p1)
            {
                string ml_out[];
                const int lines = StringSplit(p1, 0x0A, ml_out);

                for(int cnt = NULL; (cnt < lines); cnt++)
                { printf("%s", ml_out[cnt]); }
            }

Приведенный выше код на самом деле нуждается в более сложной обертке с шаблонизированными вызовами, такой, чтобы вы могли пройти через StringFormat() перед отправкой строки в вышеуказанную функцию.

Примеры этого бага уже приводились, пожалуйста, поищите на форуме, если сомневаетесь в моих выводах и отчетах.

 

Нужно было определить длительность интервала тестирования.


Не нашел на форуме, поэтому написал такую функцию.

// Возвращает разницу между датами.
string GetDiffTime( const datetime From, const datetime To )
{
  string Str = NULL;
  
  MqlDateTime sFrom;
  MqlDateTime sTo;
  
  if (TimeToStruct(From, sFrom) && TimeToStruct(To, sTo))
  {
    int Days = sTo.day - sFrom.day;
    int Months = (sTo.year - sFrom.year) * 12 + (sTo.mon - sFrom.mon) - (Days < 0);
    
    const int Years = Months / 12;    
    Months %= 12;
    
    if (Days < 0)
    {
      if (sFrom.mon++ == 12)
      {
        sFrom.mon = 1;
        sFrom.year++;        
      }
      
      sFrom.day = 1;
      
    #define DAY (24 * 3600)
      Days = (int)((StructToTime(sFrom) - From) / DAY) + sTo.day - 1;
    #undef DAY
    }
        
  #define TIMETOSTRING(A) Str += (A ? ((Str == NULL) ? NULL : " ") + (string)A + " " + #A : NULL);
    TIMETOSTRING(Years);
    TIMETOSTRING(Months);
    TIMETOSTRING(Days);
  #undef TIMETOSTRING      
  }
  
  return(Str);
}


void OnStart()
{
  Print(GetDiffTime(D'2022.02.24', D'2025.08.24')); // 3 Years 6 Months
  Print(GetDiffTime(D'2025.02.28', D'2025.03.01')); // 1 Days
  Print(GetDiffTime(D'2024.02.28', D'2025.03.01')); // 1 Years 2 Days
  Print(GetDiffTime(D'2024.02.29', D'2025.03.01')); // 1 Years 1 Days
}

Вроде, правильно показывает.

 
fxsaber #:
Не нашел на форуме, поэтому написал такую функцию.
Хорошо, но я, как минималист, писал бы Y3 M6 D2, или 03.06.02 12:43 (если добавлять время). Ну, это вкусовщина.
 
fxsaber #:

Нужно было определить длительность интервала тестирования.


Не нашел на форуме, поэтому написал такую функцию.


Вроде, правильно показывает.

К чему такие навороты?

/****************************GetDiffTime*****************************/
string GetDiffTime(const datetime From, const datetime To)
 {
  string Str = NULL;
  MqlDateTime delta;
  TimeToStruct((To-From), delta);
  string y1=delta.year-1970>0?string(delta.year-1970)+" Years ":NULL;
  string m1=delta.mon-1>0?string(delta.mon-1)+" Months ":NULL;
  string d1=delta.day-1>0?string(delta.day-1)+" Days":NULL;
  StringConcatenate(Str,y1,m1,d1);
  return(Str);
 }/******************************************************************/

Результат тот-же

2025.08.24 11:18:40.544 Test shablon (AUDCAD,M5)        3 Years 6 Months 
2025.08.24 11:18:40.544 Test shablon (AUDCAD,M5)        1 Days
2025.08.24 11:18:40.544 Test shablon (AUDCAD,M5)        1 Years 2 Days
2025.08.24 11:18:40.544 Test shablon (AUDCAD,M5)        1 Years 1 Days
 
Alexey Viktorov #:

К чему такие навороты?

Результат тот-же

Print(GetDiffTime(D'2024.02.28', D'2025.02.27')); // 1 Years