Features of the mql5 language, subtleties and tricks - page 236

 
Nikolai Semko #:
A faster implementation of the standard PeriodSeconds() function:

Looked at the format.

template <typename T>
bool IsCorrect( const int Index )
{
  ResetLastError();
  
  return((EnumToString((T)Index) != NULL) && !_LastError);
}

template <typename T>
string ToBits( const T Value )
{
  string Str = NULL;
  
  for(uint i = sizeof(T) << 3; (bool)i--;)
    Str += (string)(int)(!!(Value & (1 << i)));
    
  return(Str);
}

void OnStart()
{
  for (int i = 0; i < 1 e7; i++)
    if (IsCorrect<ENUM_TIMEFRAMES>(i))
      Print(ToBits(i) + " - " + EnumToString((ENUM_TIMEFRAMES)i) + ", " + (string)i);
}
00000000000000000000000000000000 - PERIOD_CURRENT, 0
00000000000000000000000000000001 - PERIOD_M1, 1
00000000000000000000000000000010 - PERIOD_M2, 2
00000000000000000000000000000011 - PERIOD_M3, 3
00000000000000000000000000000100 - PERIOD_M4, 4
00000000000000000000000000000101 - PERIOD_M5, 5
00000000000000000000000000000110 - PERIOD_M6, 6
00000000000000000000000000001010 - PERIOD_M10, 10
00000000000000000000000000001100 - PERIOD_M12, 12
00000000000000000000000000001111 - PERIOD_M15, 15
00000000000000000000000000010100 - PERIOD_M20, 20
00000000000000000000000000011110 - PERIOD_M30, 30
00000000000000000100000000000001 - PERIOD_H1, 16385
00000000000000000100000000000010 - PERIOD_H2, 16386
00000000000000000100000000000011 - PERIOD_H3, 16387
00000000000000000100000000000100 - PERIOD_H4, 16388
00000000000000000100000000000110 - PERIOD_H6, 16390
00000000000000000100000000001000 - PERIOD_H8, 16392
00000000000000000100000000001100 - PERIOD_H12, 16396
00000000000000000100000000011000 - PERIOD_D1, 16408
00000000000000001000000000000001 - PERIOD_W1, 32769
00000000000000001100000000000001 - PERIOD_MN1, 49153

Probably not faster. I have heard, though, about the marvellous speed of switch.

int PeriodSecondsFast( const ENUM_TIMEFRAMES tf )
{
  switch (tf)
  {
    case PERIOD_CURRENT: return(PeriodSecondsFast(_Period));      
    case PERIOD_M1:      return(60);
    case PERIOD_M2:      return(120);
    case PERIOD_M3:      return(180);
    case PERIOD_M4:      return(240);
    case PERIOD_M5:      return(300);
    case PERIOD_M6:      return(360);
    case PERIOD_M10:     return(600);
    case PERIOD_M12:     return(720);
    case PERIOD_M15:     return(900);
    case PERIOD_M20:     return(1200);
    case PERIOD_M30:     return(1800);
    case PERIOD_H1:      return(3600);
    case PERIOD_H2:      return(7200);
    case PERIOD_H3:      return(10800);
    case PERIOD_H4:      return(14400);
    case PERIOD_H6:      return(21600);
    case PERIOD_H8:      return(28800);
    case PERIOD_H12:     return(43200);
    case PERIOD_D1:      return(86400);
    case PERIOD_W1:      return(604800);
    case PERIOD_MN1:     return(2592000);
  }
  
  return(0);
}
 
fxsaber #:

Looked at the format.

Probably won't speed it up. Heard about the miraculous speed of the switch, though.

It looks longer, but I didn't notice any difference in performance.

int PeriodSecondsFast2(ENUM_TIMEFRAMES tf) {
   ushort i_tf= ushort(tf);
   uchar _i =uchar(i_tf>>14);
   int n = i_tf & 0x0FFF;
   switch(_i) {
   case 0: // минуты
      return n*60;
   case 1: // часы
      return n*60*60;
   case 2: // недели
      return 60*60*24*7;
   case 3: // месяцы
      return 2592000;
   }
   return -1;
}

so I think a one-line version is still preferable.

int PeriodSecondsFast(ENUM_TIMEFRAMES tf) {
   return (tf>>14==0)?(tf&0x0FFF)*60:(tf>>14==1)?(tf&0x0FFF)*60*60:(tf>>14==2)?60*60*24*7:60*60*24*30;
}
 
Nikolai Semko #:

looks longer

int PeriodSecondsFast( const ENUM_TIMEFRAMES tf )
{
  static const int Mult[] = {60, 60 * 60, 60 * 60 * 24 * 7, 60 * 60 * 24 * 30};
  
  return((tf & 0xFF) * Mult[tf >> 14]);
}
 

and now to convert all this into matrices and ONX :-)

 
fxsaber #:

Yeah. You could do that. More readable.
performance on my laptop is the same.

 

fxsaber #:

int PeriodSecondsFast( const ENUM_TIMEFRAMES tf )
{
  static const int Mult[] = {60, 60 * 60, 60 * 60 * 24 * 7, 60 * 60 * 24 * 30};
  
  return((tf & 0xFF) * Mult[tf >> 14]);
}

By the way, I was wrong in my previous posts. For some reason I thought there were 28 days in a month, not 30. I don't understand where I got that.
I can't fix my posts that are more than 1 hour old anymore.

So my correct version is this:

int PeriodSecondsFast(ENUM_TIMEFRAMES tf) {
   return (tf>>14==0)?(tf&0xFF)*60:(tf>>14==1)?(tf&0xFF)*60*60:(tf>>14==2)?60*60*24*7:60*60*24*30;
}

No one needs seconds of the month, though, since months are different in length

 
Nikolai Semko # :

By the way, I was wrong in my previous posts. For some reason I thought there were 28 days in a month, not 30. I don't understand where I got it.
I can't fix my posts that are older than 1 hour.

So my correct version is as follows:

No one needs seconds of the month, though, since months are different in length

What makes you think this is faster than PeriodSeconds(x) ?
 
Alain Verleyen #:
What makes you think this is faster than PeriodSeconds(x) ?

the test from this post

it is enough to compare the performance of getStartTimeOfBar() with PeriodSeconds() and with PeriodSecondsFast()

The comparison should be done on any TF except MN1

The performance is higher by about 2 times. Maybe 3 times taking into account that we measure the whole iteration.


or is it enough to compare these two values


2023.11.14 22:44:52.581 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_H8========
2023.11.14 22:44:52.581 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000623961600, время выполнения 1 иттерации = 6.80 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 22:44:52.581 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000623961600, время выполнения 1 иттерации = 3.40 наносекунд - Быстрый расчет
2023.11.14 22:44:57.734 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000252960000, время выполнения 1 иттерации = 515301.20 наносекунд - Расчет через iBarShift
2023.11.14 22:44:57.734 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 22:45:16.253 timeToStartMonth (EURUSD,M1)    60 ,120 ,180 ,240 ,300 ,360 ,600 ,720 ,900 ,1200 ,1800 ,3600 ,7200 ,10800 ,14400 ,21600 ,28800 ,43200 ,86400 ,604800 ,2592000 ,
2023.11.14 22:45:16.253 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_M4========
2023.11.14 22:45:16.253 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000769600080, время выполнения 1 иттерации = 3.70 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 22:45:16.253 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000769600080, время выполнения 1 иттерации = 1.90 наносекунд - Быстрый расчет
2023.11.14 22:45:16.471 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000394543440, время выполнения 1 иттерации = 21746.60 наносекунд - Расчет через iBarShift
2023.11.14 22:45:16.471 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 22:45:57.038 timeToStartMonth (EURUSD,M1)    60 ,120 ,180 ,240 ,300 ,360 ,600 ,720 ,900 ,1200 ,1800 ,3600 ,7200 ,10800 ,14400 ,21600 ,28800 ,43200 ,86400 ,604800 ,2592000 ,
2023.11.14 22:45:57.038 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_H1========
2023.11.14 22:45:57.038 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000751999200, время выполнения 1 иттерации = 5.30 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 22:45:57.038 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000751999200, время выполнения 1 иттерации = 3.00 наносекунд - Быстрый расчет
2023.11.14 22:45:57.072 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000378405600, время выполнения 1 иттерации = 3410.10 наносекунд - Расчет через iBarShift
2023.11.14 22:45:57.072 timeToStartMonth (EURUSD,M1)    ========================================================================

 
Nikolai Semko # :

the test from this post

it is enough to compare the work of getStartTimeOfBar() with PeriodSeconds() and with PeriodSecondsFast()

The comparison should be done on any TF except MN1

The performance is higher by about 2 times. Maybe 3 times taking into account that we measure the whole iteration.


or is it enough to compare these two values



I may be missing something, but I used your script to check PeriodSeconds (only).


Files:
__.mq5  13 kb
 
Alain Verleyen #:

I may be missing something, but I used your script to check PeriodSeconds (only).


my results from your test:

2023.11.15 00:26:58.896 DDD__ (EURUSD,M1)       контрольная сумма - 34192800000000, время выполнения 1 иттерации = 29.78 наносекунд - PeriodSecondsFastFXS
2023.11.15 00:26:59.056 DDD__ (EURUSD,M1)       контрольная сумма - 34192800000000, время выполнения 1 иттерации = 16.03 наносекунд - PeriodSecondsFast
2023.11.15 00:26:59.477 DDD__ (EURUSD,M1)       контрольная сумма - 34192800000000, время выполнения 1 иттерации = 42.08 наносекунд - Расчет через PeriodSeconds
2023.11.15 00:26:59.477 DDD__ (EURUSD,M1)       ========================================================================
2023.11.15 00:27:16.018 DDD__ (EURUSD,M1)       =====LOOP=10000000
2023.11.15 00:27:16.318 DDD__ (EURUSD,M1)       контрольная сумма - 34192800000000, время выполнения 1 иттерации = 29.99 наносекунд - PeriodSecondsFastFXS
2023.11.15 00:27:16.474 DDD__ (EURUSD,M1)       контрольная сумма - 34192800000000, время выполнения 1 иттерации = 15.59 наносекунд - PeriodSecondsFast
2023.11.15 00:27:16.901 DDD__ (EURUSD,M1)       контрольная сумма - 34192800000000, время выполнения 1 иттерации = 42.74 наносекунд - Расчет через PeriodSeconds
2023.11.15 00:27:16.901 DDD__ (EURUSD,M1)       ========================================================================
2023.11.15 00:27:25.206 DDD__ (EURUSD,M1)       =====LOOP=10000000
2023.11.15 00:27:25.508 DDD__ (EURUSD,M1)       контрольная сумма - 34192800000000, время выполнения 1 иттерации = 30.14 наносекунд - PeriodSecondsFastFXS
2023.11.15 00:27:25.666 DDD__ (EURUSD,M1)       контрольная сумма - 34192800000000, время выполнения 1 иттерации = 15.77 наносекунд - PeriodSecondsFast
2023.11.15 00:27:26.110 DDD__ (EURUSD,M1)       контрольная сумма - 34192800000000, время выполнения 1 иттерации = 44.47 наносекунд - Расчет через PeriodSeconds
2023.11.15 00:27:26.110 DDD__ (EURUSD,M1)       ========================================================================
2023.11.15 00:27:40.780 DDD__ (EURUSD,M1)       =====LOOP=10000000
2023.11.15 00:27:41.089 DDD__ (EURUSD,M1)       контрольная сумма - 34192800000000, время выполнения 1 иттерации = 30.90 наносекунд - PeriodSecondsFastFXS
2023.11.15 00:27:41.249 DDD__ (EURUSD,M1)       контрольная сумма - 34192800000000, время выполнения 1 иттерации = 15.98 наносекунд - PeriodSecondsFast
2023.11.15 00:27:41.676 DDD__ (EURUSD,M1)       контрольная сумма - 34192800000000, время выполнения 1 иттерации = 42.72 наносекунд - Расчет через PeriodSeconds
2023.11.15 00:27:41.676 DDD__ (EURUSD,M1)       ========================================================================

0 errors, 0 warnings, 234 msec elapsed, cpu='AVX2 + FMA3'               


I don't like the test itself very much, because 10 million of the same calculations take place in the test. In this case, there is no guarantee that the compiler will not give surprises in its attempts to optimise the code.
And these values must be divided by 21 because there are 21*10 000 000 iterations in total.

However, this test also confirms my conclusions, but for my processor, which seems to be fresher and, therefore, uses modern performance features to the maximum and, therefore, is more objective because it is more up-to-date.


It would be interesting to see the results of this test for others.

Reason: