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

 
amrali #:

Вы упустили, что day_of_year - это индекс, основанный на нуле. Таким образом, doy=31 означает на самом деле 1 февраля.

Спасибо, понял это раньше Вашего сообщения, поэтому удалил.

 
amrali #:

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

В штатной TimeToStruct кеширование каждый час.
 

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

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

amrali, 2024.11.26 15:58

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

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

bool TimeToStructFast(datetime time, MqlDateTime& dt_struct)
  {
//   static const int Months[13] = {0, -1, 30, 58, 89, 119, 150, 180, 211,242, 272, 303, 333};  
   static const int Months[] = {0, 11512692, 11512196, 11511744, 11511248, 11510766, 11510272,
                                   11509790, 11509296, 11508797, 11508318, 11507822, 11507342};
   uint t       = (uint)time;
   int  n       = (int)(t / (24 * 3600));
   int  tn      = (n << 2) + 2;
   int  dow     = (n + 4) % 7;
   int  doy     = (tn % 1461) / 4;
   int  year    = (tn / 1461) + 1970; // to 2100
//   int  doy     = n - ((year * 5844 - 11512676) >> 4);

//   int  isleap  = ((year & 3) == 0);
//   int  leapadj = ((doy < (isleap + 59)) ? 0 : (2 - isleap));
//   int  mon     = ((((doy + leapadj) * 12) + 373) / 367);
//   int  day     = doy - Months[mon] - (isleap && doy > 59);
   int  mon     = (doy < 59) ? ((doy + 1) >> 5) + 1 : (((doy - !(year & 3)) * 67 + 2209 ) >> 11);   
   int  day     = n - (int)((year * 5844 - Months[mon]) >> 4); // https://www.mql5.com/ru/forum/170952/page254#comment_53104383
   int  HH      = (int)(t / 3600) % 24;
   int  MM      = (int)(t / 60) % 60;
   int  SS      = (int)(t % 60);

   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);
  }

В моем предыдущем варианте была ошибка, поэтому удалил.

Изменил Months[] и избавился от расчета isleap при любой дате. Теперь правильно и быстрее.

 
fxsaber #:

В моей предыдущей версии была ошибка, поэтому я ее удалил.

Изменил Months[] и избавился от вычисления isleap для любой даты. Теперь все работает корректно и быстрее.

Оно все еще там: doy - !(year & 3)
 
amrali #:
Оно все еще там: doy - !(year & 3)

Только при doy >= 59.

 
amrali #:

Спасибо, Ален, за ваш тест. Замена на встроенный TimeToStruct() работает всего в 4-5 раз быстрее, как я уже сообщал.

Однако замена TimeYear(), TimeDayOfWeek() как минимум в 10-20 раз быстрее, чем использование MQL's TimeToStruct()

Этот код выполняется медленно при использовании оберток встроенного StructToTime.

Использование оптимизированных функций здесь очень помогает.

Еще один момент: распаковка (TimeToStruct) всегда быстрее, чем сжатие (StructToTime). Встроенный StructToTime действительно медленнее, чем TimeToStruct().

Если ваш код создает много переменных 'datetime' из компонентов времени, вы обнаружите, что CreateDateTime() намного быстрее, чем MQL'овская StructToTime().

Я столкнулся с проблемой медленной работы StructToTime() при создании переменных времени суток для перехода на летнее время в библиотеке TimeZoneInfo. Заменив ее на эту пользовательскую CreateDateTime(), я значительно улучшил скорость работы.

Спасибо за советы. Я не использую "TimeHour", так как его тривиально получить, но я проверю другие варианты использования TimeToStruct().
 

fxsaber #:

Теперь правильно и быстрее.

Random.

Compiler Version: 4699 X64 Regular, optimization - true
Intel Core i7-2700K  @ 3.50GHz, AVX
With hours (dt.hour+ dt.min+ dt.sec - on), random datetimes[].
1970.01.01 00:00:04 - 2097.11.29 23:59:24
 9.97 ns, checksum = 1287384081405080   // TimeToStruct2100
 9.65 ns, checksum = 1287384081405080   // TimeToStructFast
 9.81 ns, checksum = 1287384081405080   // TimeToStructFast_fxsaber
11.40 ns, checksum = 1287384081405080   // TimeToCalendar
21.79 ns, checksum = 1287384081405080   // TimeToJulian
39.66 ns, checksum = 1287384081405080  /// MQL's TimeToStruct()

Compiler Version: 4699 AVX, optimization - true
Intel Core i7-2700K  @ 3.50GHz, AVX
With hours (dt.hour+ dt.min+ dt.sec - on), random datetimes[].
1970.01.01 00:00:09 - 2097.11.29 23:58:42
10.34 ns, checksum = 1258378892513111   // TimeToStruct2100
10.23 ns, checksum = 1258378892513111   // TimeToStructFast
10.17 ns, checksum = 1258378892513111   // TimeToStructFast_fxsaber
12.07 ns, checksum = 1258378892513111   // TimeToCalendar
22.58 ns, checksum = 1258378892513111   // TimeToJulian
38.64 ns, checksum = 1258378892513111  /// MQL's TimeToStruct()

Compiler Version: 4699 X64 Regular, optimization - true
Intel Core i7-2700K  @ 3.50GHz, AVX
Without hours (dt.hour+ dt.min+ dt.sec - off), random datetimes[].
1970.01.01 00:00:12 - 2097.11.29 23:59:10
 7.95 ns, checksum = 1236392076157598   // TimeToStruct2100
 7.62 ns, checksum = 1236392076157598   // TimeToStructFast
 7.59 ns, checksum = 1236392076157598   // TimeToStructFast_fxsaber
 8.45 ns, checksum = 1236392076157598   // TimeToCalendar
17.71 ns, checksum = 1236392076157598   // TimeToJulian
38.96 ns, checksum = 1236392076157598  /// MQL's TimeToStruct()

Compiler Version: 4699 AVX, optimization - true
Intel Core i7-2700K  @ 3.50GHz, AVX
Without hours (dt.hour+ dt.min+ dt.sec - off), random datetimes[].
1970.01.01 00:00:02 - 2097.11.29 23:59:39
 8.29 ns, checksum = 1256777674228719   // TimeToStruct2100
 7.83 ns, checksum = 1256777674228719   // TimeToStructFast
 7.99 ns, checksum = 1256777674228719   // TimeToStructFast_fxsaber
 9.19 ns, checksum = 1256777674228719   // TimeToCalendar
 6.85 ns, checksum = 1256777674228719   // TimeToJulian
38.48 ns, checksum = 1256777674228719  /// MQL's TimeToStruct()


Not random.

Compiler Version: 4699 X64 Regular, optimization - true
Intel Core i7-2700K  @ 3.50GHz, AVX
With hours (dt.hour+ dt.min+ dt.sec - on), not random datetimes[].
1970.01.01 00:00:00 - 2099.11.29 23:59:33
 9.38 ns, checksum = 706250935681392   // TimeToStruct2100
 9.65 ns, checksum = 706250935681392   // TimeToStructFast
 8.48 ns, checksum = 706250935681392   // TimeToStructFast_fxsaber
11.45 ns, checksum = 706250935681392   // TimeToCalendar
21.59 ns, checksum = 706250935681392   // TimeToJulian
 6.38 ns, checksum = 706250935681392  /// MQL's TimeToStruct()

Compiler Version: 4699 AVX, optimization - true
Intel Core i7-2700K  @ 3.50GHz, AVX
With hours (dt.hour+ dt.min+ dt.sec - on), not random datetimes[].
1970.01.01 00:00:00 - 2099.11.29 23:59:33
 9.75 ns, checksum = 706250935681392   // TimeToStruct2100
10.31 ns, checksum = 706250935681392   // TimeToStructFast
 8.93 ns, checksum = 706250935681392   // TimeToStructFast_fxsaber
12.11 ns, checksum = 706250935681392   // TimeToCalendar
22.81 ns, checksum = 706250935681392   // TimeToJulian
 6.51 ns, checksum = 706250935681392  /// MQL's TimeToStruct()

Compiler Version: 4699 X64 Regular, optimization - true
Intel Core i7-2700K  @ 3.50GHz, AVX
Without hours (dt.hour+ dt.min+ dt.sec - off), not random datetimes[].
1970.01.01 00:00:00 - 2099.11.29 23:59:33
 7.07 ns, checksum = 706253275674880   // TimeToStruct2100
 7.55 ns, checksum = 706253275674880   // TimeToStructFast
 6.47 ns, checksum = 706253275674880   // TimeToStructFast_fxsaber
 8.46 ns, checksum = 706253275674880   // TimeToCalendar
17.92 ns, checksum = 706253275674880   // TimeToJulian
 5.93 ns, checksum = 706253275674880  /// MQL's TimeToStruct()

Compiler Version: 4699 AVX, optimization - true
Intel Core i7-2700K  @ 3.50GHz, AVX
Without hours (dt.hour+ dt.min+ dt.sec - off), not random datetimes[].
1970.01.01 00:00:00 - 2099.11.29 23:59:33
 7.57 ns, checksum = 706253275674880   // TimeToStruct2100
 7.86 ns, checksum = 706253275674880   // TimeToStructFast
 6.75 ns, checksum = 706253275674880   // TimeToStructFast_fxsaber
 9.16 ns, checksum = 706253275674880   // TimeToCalendar
 6.83 ns, checksum = 706253275674880   // TimeToJulian
 5.94 ns, checksum = 706253275674880  /// MQL's TimeToStruct()


Волшебство.

Убираем в исходнике (см. вложение) эту строку.

   Print((string)t[ArrayMinimum(t)] + " - " + (string)t[ArrayMaximum(t)]);


Compiler Version: 4699 AVX, optimization - true
Intel Core i7-2700K  @ 3.50GHz, AVX
Without hours (dt.hour+ dt.min+ dt.sec - off), random datetimes[].
TimeToCalendar's magic
 7.91 ns, checksum = 1238992342013450   // TimeToStruct2100
 7.62 ns, checksum = 1238992342013450   // TimeToStructFast
 7.79 ns, checksum = 1238992342013450   // TimeToStructFast_fxsaber
 4.02 ns, checksum = 1238992342013450   // TimeToCalendar
 6.87 ns, checksum = 1238992342013450   // TimeToJulian
38.02 ns, checksum = 1238992342013450  /// MQL's TimeToStruct()

Compiler Version: 4699 AVX, optimization - true
Intel Core i7-2700K  @ 3.50GHz, AVX
Without hours (dt.hour+ dt.min+ dt.sec - off), not random datetimes[].
TimeToCalendar's magic
 7.29 ns, checksum = 706253275674880   // TimeToStruct2100
 7.60 ns, checksum = 706253275674880   // TimeToStructFast
 6.59 ns, checksum = 706253275674880   // TimeToStructFast_fxsaber
 4.00 ns, checksum = 706253275674880   // TimeToCalendar
 6.80 ns, checksum = 706253275674880   // TimeToJulian
 5.69 ns, checksum = 706253275674880  /// MQL's TimeToStruct()


TimeToCalendar в AVX-компиляторе очень сильно опережает любые другие реализации.

Файлы:
 
fxsaber #:

Случайность.


Не случайно.


Магия.

Мы удаляем эту строку в исходнике (см. вложение).



TimeToCalendar в AVX-компиляторе очень сильно опережает любую другую реализацию.

AVX2 работает медленнее?

 
Alain Verleyen #:

AVX2 работает медленнее?

У меня нет такого процессора, чтобы проверить.

Исходник рабочий, можете попробовать.
 
fxsaber #:

У меня нет такого процессора, чтобы протестировать.

Исходник работает, можете попробовать.
Хорошо, я сделаю это.