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

 
fxsaber #:

Эта функция указывает на наличие/отсутствие определенной оптимизации компилятора, а не на наличие/отсутствие одноименного флага GUI компилятора.

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

В прошлом она уже использовалась для этого. Возможно, это можно перенести в mql.
 
Artyom Trishkin #:
Пожалуйста, дайте ссылку на эту тему.

TimeUtilsверсии 1.10был опубликован в кодовой базе.

https://www.mql5.com/en/code/53970

High-Performance Time Functions (TimeUtils)
High-Performance Time Functions (TimeUtils)
  • www.mql5.com
High-performmance functions for dealing with time.
 

Рассмотрим этоткод старого образца для поиска значения в статическом массиве:

int DaysInMonth(const int year, const int month)
  {
   const int dim[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
   return ((month == 2 && IsLeapYear(year)) ? 29 : dim[month % 13]);
  }

Теперь статические массивы оцениваются во время выполнения, поэтому мы можем переопределить массив как:

int DaysInMonth(const int year, const int month)
  {
   const int dim[13] = {0, 31, (IsLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
   return dim[month % 13];
  }
и он скомпилируется без ошибок.
 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

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

Dominik Egert, 2024.11.28 15:37

Немного более оптимизированная версия:

bool TimeToStructMQLplus(datetime timestamp, MqlDateTime& dt_struct)
{
    static const int Months[] = { 0, 11512692, 11512196, 11511744, 11511248, 11510766, 11510272, 11509790, 11509296, 11508797, 11508318, 11507822, 11507342 };

    const uint t            = (uint)timestamp;
    const int  n            = (int)(t / 86400);
    const int  tn           = (n << 2) | 2;

    dt_struct.day_of_year   = (tn % 1461) >> 2;
    dt_struct.year          = (tn / 1461) + 1970;
    const int  isleap       = !(dt_struct.year & 3);

//    dt_struct.mon           = ((((dt_struct.day_of_year + ((dt_struct.day_of_year < (isleap + 59)) ? 0 : (2 - isleap))) * 12) + 373) / 367);
    dt_struct.mon           = ((((dt_struct.day_of_year + ((dt_struct.day_of_year < (isleap + 59)) ? 0 : (2 - isleap))) * 67) + 2075) >> 11);
    dt_struct.day           = n - (int)((dt_struct.year * 5844 - Months[dt_struct.mon]) >> 4);
    #ifndef WITHOUT_HOURS
        dt_struct.hour      = (int)(t / 3600) % 24;
        dt_struct.min       = (int)(t / 60) % 60;
        dt_struct.sec       = (int)(t % 60);

    #endif //#ifndef WITHOUT_HOURS
    dt_struct.day_of_week   = (n + 4) % 7;

   return (true);
}

Скорее всего, так быстрее будет.

 

А обратно ?

в смысле что TimeToStruct обычно применяется в паре с обратной функцией StructToTime

найти "первый понедельник предыдущего месяца" , "начало текущего квартала" etc. 

А просто разложить текущую дату на день-месяц-год (чтобы знать) бывает нужно раз в сутки и этот момент не критичен. Никто-же не вызывает TimeToStruct на каждом тике :-)

 
Maxim Kuznetsov функцией StructToTime.

Чтобы найти "первый понедельник предыдущего месяца", "начало текущего квартала" и т.д.

А просто разложить текущую дату на день-месяц-год (узнать) может понадобиться раз в день и этот момент не критичен. Никто же не вызывает TimeToStruct на каждом тике :-)

Мне приходилось вызывать dt.day_of_week 500k раз в цикле, который сканирует историю. Так и получилось.
 
amrali #:

Самая быстрая замена встроенной функции TimeToStruct(),

я предлагаю использовать эту функцию:

Ускорение примерно в 4-5 раз (для версии без кэша).

После применения оптимизаций из статьи "Евклидовы аффинные функции и их применение к алгоритмам календаря ":

bool TimeToStructFast2(datetime time, MqlDateTime& dt_struct)
  {
   static const int Months[13] = {0, -1, 30, 58, 89, 119, 150, 180, 211,242, 272, 303, 333};
   uint t       = (uint)time;
   int  n       = (int)(t / (24 * 3600));
   int  tn      = (n << 2) + 2;
   int  dow     = (n + 4) % 7;
 //int  year    = (tn / 1461) + 1970; // to 2100
 //int  doy     = (tn % 1461) / 4;

   // Example 3.12 of the paper https://arxiv.org/pdf/2102.06959
   ulong P_1    = 2939745 ULL * tn;
   int  year    = (int)(P_1 >> 32) + 1970; // to 2100
   int  doy     = (int)(((uint)P_1) / 2939745 / 4);

   int  isleap  = ((year & 3) == 0);
   int  leapadj = ((doy < (isleap + 59)) ? 0 : (2 - isleap));
 //int  mon     = ((((doy + leapadj) * 12) + 373) / 367);
   int  mon     = ((doy + leapadj) * 34284 + 1068518) >> 20;
   int  day     = doy - Months[mon] - (isleap && doy > 59);

 //int  HH      = (int)(t / 3600) % 24;
 //int  MM      = (int)(t / 60) % 60;
 //int  SS      = (int)(t % 60);

   // Example 3.14 of the paper https://arxiv.org/pdf/2102.06959
   ulong P_2    = 1193047 ULL * (t - n * 86400);
   ulong P_3    = 71582789 ULL * ((uint)P_2 / 1193047);

   int   HH     = (int)(P_2 >> 32);
   int   MM     = (int)(P_3 >> 32);
   int   SS     = (int)((uint)P_3 / 71582789);

   dt_struct.year           = year;
   dt_struct.mon            = mon;
   dt_struct.day            = day;
   dt_struct.hour           = HH;
   dt_struct.min            = MM;
   dt_struct.sec            = SS;
   dt_struct.day_of_week    = dow;
   dt_struct.day_of_year    = doy;

   return (true);
  }

Результаты:

/*
 Compiler Version: 4620, X64 Regular
 13th Gen Intel Core i3-1305U, AVX2 + FMA3
 1970.01.01 00:05:17 - 2099.11.29 23:56:35, random datetimes[]
  5.20 ns, checksum = 151984615301017   // TimeToStruct2100
  5.18 ns, checksum = 151984615301017   // TimeToStructFast
  4.52 ns, checksum = 151984615301017   // TimeToStructFast2
  4.87 ns, checksum = 151984615301017   // TimeToCalendar
  5.62 ns, checksum = 151984615301017   // TimeToJulian
 23.08 ns, checksum = 151984615301017  /// MQL's TimeToStruct()
*/
Файлы:
 
amrali #:

После применения оптимизаций из статьи "Евклидовы аффинные функции и их применение к алгоритмам календаря ":

Спасибо, очень интересное решение.


int  mon     = ((doy + leapadj) * 34284 + 1068518) >> 20;

Вы можете использовать меньшие числа в выражении.

dt_struct.mon           = ((((dt_struct.day_of_year + ((dt_struct.day_of_year < (isleap + 59)) ? 0 : (2 - isleap))) * 67) + 2075) >> 11);
 
amrali #:

После применения оптимизаций из этой статьи "Евклидовы аффинные функции и их применение к календарным алгоритмам":

Результаты:

Впечатляющий код.

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