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

 
amrali #:

High-performance time-handling functions applicable to the entire MQL5 date and time range (from 1 January 1970 to 31 December 3000):

(Based on the Neri–Schneider calendar conversion algorithm: see here)

The attached script file contains the source code and comprehensive tests.

What are ULL and U?
 
Vladimir Pastushak #:
What are ULL and U?

  • U suffix   : unsigned int 32 (uint)
  • ULL suffix: unsigned long 64 (ulong)

These unsigned divisors (3600ULL, 86400ULL,..) will force unsgnied division and modulus, esp. when the numerator is of datetime type (treated internally as signed long 64). 

The datetime will be promoted to ulong before performing the division / modulus. This ensures faster optimizations by the compiler. 

datetime / 86400ULL is a bit faster than datetime / 86400.

Signed division and modulus will require extra instructions to handle the signedness.

Check it on https://godbolt.org/


Compiler Explorer
Compiler Explorer
  • Matt Godbolt
  • godbolt.org
Compiler Explorer is an interactive online compiler which shows the assembly output of compiled C++, Rust, Go (and many more) code.
 

Signed vs. unsigned div/mod:

int DayOfWeek(const datetime t)
  {
   return (int)(t / 86400 + THURSDAY) % 7;
  }

int DayOfWeekU(const datetime t)
  {
   return (int)((t / 86400ULL + THURSDAY) % 7U);
  }

#define BENCHSIZE 10000000

ulong randUlong() { return((ulong)rand()<<60)|((ulong)rand()<<45)|((ulong)rand()<<30)|((ulong)rand()<<15)|(ulong)rand(); }

void OnStart() {
   Print("\nCompiler Version: " + (string)__MQLBUILD__ + ", " + __CPU_ARCHITECTURE__);
   Print(TerminalInfoString(TERMINAL_CPU_NAME) + ", " + TerminalInfoString(TERMINAL_CPU_ARCHITECTURE));

   datetime t[];
   ArrayResize(t, BENCHSIZE);
   for(int i = 0; i < BENCHSIZE;i++) {
      t[i] = (datetime) (randUlong() % D'3000.01.01');
   }

   // Tests
   ulong sum = 0;
   ulong tt = GetMicrosecondCount();
   for(int i=0; i<BENCHSIZE; i++) { sum += t[i] + DayOfWeek(t[i]); }
   PrintFormat("%5.2f ns, checksum = %llu   // DayOfWeek", (GetMicrosecondCount()-tt)*1000.0/BENCHSIZE, sum);

   sum = 0;
   tt = GetMicrosecondCount();
   for(int i=0; i<BENCHSIZE; i++) { sum += t[i] + DayOfWeekU(t[i]); }
   PrintFormat("%5.2f ns, checksum = %llu   // DayOfWeekU", (GetMicrosecondCount()-tt)*1000.0/BENCHSIZE, sum);
  }

Results:

 Compiler Version: 5836, AVX2 + FMA3
 13th Gen Intel Core i7-13700KF, AVX2 + FMA3
  1.24 ns, checksum = 162509975528847278   // DayOfWeek
  0.72 ns, checksum = 162509975528847278   // DayOfWeekU