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

 
Maxim Kuznetsov #:

And inverse ?

I mean that TimeToStruct is usually paired with the inverse StructToTime function.

to find "first Monday of the previous month" , "the beginning of the current quarter" etc.

And just to decompose the current date into day-month-year (to know) it may be necessary once a day and this moment is not critical. Nobody calls TimeToStruct on every tick :-)

I had to call dt.day_of_week 500k times in a loop that scans history. It happens.
 
amrali #:

For the fastest replacement to the built-in TimeToStruct() function,

I suggest using this function :

The speed-up factor is approx. 4-5x (for the version without cache).

 

After applying optimizations from this paper "Euclidean Affine Functions and Applications to Calendar Algorithms":

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    = 2939745ULL * 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    = 1193047ULL * (t - n * 86400);
   ulong P_3    = 71582789ULL * ((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);
  }

Results:

/*
 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 #:

After applying optimisations from the article "Euclidean affine functions and their application to calendar algorithms ":

Thanks, very interesting solution.


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

You can use smaller numbers in the expression.

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

After applying optimizations from this paper "Euclidean Affine Functions and Applications to Calendar Algorithms":

Results:

Impressive code.

I flew over it and it seems all operations are in the most efficient way structured. I dont think there is more improvement possible, but I said that before already. - Obviously, I was wrong.


 
Supposedly, MQs should now replace the implementation of the inbuilt f-function with this one?
 
JRandomTrader #:
Supposedly MQ should now replace the implementation of the inbuilt f-function with this one?

It should be checked for dates after 2100. The year is 365.2425 days long, not 365.25.

 
JRandomTrader #:
Supposedly, MQs should now replace the implementation of the inbuilt f-function with this one?
It is a mental training for code optimization and we enjoyed it 😀 MQ is not supposed to replace anything. 
 
JRandomTrader #:
Supposedly, MQs should now replace the implementation of the inbuilt f-function with this one?
Also, why. Just replace it yourself. Look at amralis library, he shows how to do it.
 
Dominik Egert #:
Also, why. Just replace it yourself. Look at the amralis library, it shows how to do it.

Meaning, if there is a better implementation than the stock one, it would make sense for MQ to replace the stock one with a better one.

 
JRandomTrader #:

Meaning, if there is a better implementation than the stock one, it would make sense for MQ to replace the stock one with a better one.

Not necessarily. MQ is facing a totally different challenge. They need to make sure to not break old code, and they need to put maintenance towards any code they have in their products.

So if MQ uses some windows API function to do the job, they reduced their code footprint and maintenance labor. MQ is most probably focused on reliable and functional. They do not focus a week on one function to make it the most efficient code possible.

When you run a software as a product, you are focused on other aspects. Think of it  like a car manufacturer. They dont sell you F1 cars. But you can tune it later as you like.

And this code is no different. Its a tuning equipment for your program.