Fragen zu OOP in MQL5 - Seite 70

 
Maxim Kuznetsov:

Dies wird "loop unrolling" genannt und wird vom Compiler ohne OO und Templates erledigt (zumindest sollte es so sein).

Wenn man sich den Zwischencode (Assembler) ansieht, gibt es statt einer Schleife nur aufeinanderfolgende N-Operationen.

Und können Sie uns sagen, was passiert, wenn eine Funktion rekursiv aufgerufen wird?

 
Dmitry Fedoseev:

Können Sie mir sagen, was passiert, wenn eine Funktion rekursiv aufgerufen wird?

es gibt keinen rekursiven Aufruf der Zielfunktionen :-)

Im obigen Beispiel N:=const tritt die Rekursion nur auf, wenn der Code aus einer Vorlage generiert wird und diese zugeschnitten ist. Bei der Verknüpfung besteht ein cleverer Trick darin, den const-Zyklus in eine Schablonenrekursion umzuwandeln und ihn ein cleveres Wort zu nennen

Wenn Makros Schleifen hätten, würde es so geschrieben werden

#for x=0, x<N, x++

print("x=%d",x);

#endfor

und nach dem Makroprozessor würde es sich zu einer Folge von N Prinzen entfalten. (was tatsächlich geschah, nur durch Vorlagenklassen)

Das heißt, der Trick funktioniert nur, wenn N zur Kompilierzeit bekannt ist

 
Maxim Kuznetsov:

und es erfolgt kein rekursiver Aufruf der Zielfunktionen :-)

In dem Beispiel, das unter dem Link N:=const angegeben ist, erfolgt die Rekursion nur bei der Codegenerierung aus einer Vorlage und diese ist tail. Bei der Verknüpfung besteht ein cleverer Trick darin, den const-Zyklus in eine Schablonenrekursion umzuwandeln und ihn ein cleveres Wort zu nennen

Wenn Makros Schleifen hätten, würde es so geschrieben werden

#for x=0, x<N, x++

print("x=%d",x);

#endfor

und nach dem Makroprozessor würde es sich zu einer Folge von N Prinzen entfalten. (was tatsächlich geschah, nur durch Vorlagenklassen)

Der Trick funktioniert also nur, wenn N zur Kompilierzeit bekannt ist

Sie werden es nicht glauben, aber ich weiß, wie Vorlagen funktionieren, welches N es gibt und was das Ergebnis ist. Und meine Frage zum rekursiven Funktionsaufruf bezog sich genau auf den rekursiven Funktionsaufruf, nicht auf das Wie?

 
Dmitry Fedoseev:

Sie werden es nicht glauben, aber ich weiß, wie Vorlagen funktionieren und was das N ist und was das Ergebnis ist. Und meine Frage zum rekursiven Funktionsaufruf bezog sich genau auf den rekursiven Funktionsaufruf, nicht auf das Wie?

Ist es eine Art "Mutprobe"? :-) Irgendwie dachte ich, dass dieses Beispiel gerade diskutiert wird... Ich habe mich geirrt :-)

Wenn der Compiler die Rekursion in einen Schwanz umwandeln kann (oder es ist explizit so, oder er wurde dazu aufgefordert), dann wird es physisch keine Rekursion geben - es wird eine Schleife machen (zurückschalten) und jede Iteration wird den vorherigen Stackframe "zertrampeln".

 
Maxim Kuznetsov:

Ist das eine Art "Mutprobe"? :-) Irgendwie dachte ich, dass dieses Beispiel schon diskutiert wurde...ich habe mich geirrt :-)

Wenn der Compiler die Rekursion in eine Tail-Rekursion umwandeln kann (oder explizit so eingestellt ist oder dazu aufgefordert wurde), dann findet physisch keine Rekursion statt - es wird eine Schleife gebildet (zurückgeschaltet) und jede Iteration "trampelt" den vorherigen Stack-Frame.

Was hat das mit Schwäche zu tun? Nur eine Frage. Nun, nein, also nein.

 
fxsaber:

Ich will mir nicht einmal die Mühe machen. Ich habe einfache Strukturen geschaffen.



Aus welchem Grund der Zugriff auf das erste Feld einer einfachen Struktur von ihrer Größe abhängt, ist mir nicht klar.

Hm. Das ist trivial - die Anzahl der zu multiplizierenden Bits ist mehr)))) Vergewissern Sie sich, dass die Anzahl der Bits in der binären Darstellung der Größe der Struktur gleich ist)))) Dummerweise Prozessor, sowie ein Mann, länger zu multiplizieren 1111*101 als 1111*10)
 
Vladimir Simakov:
Hm. Das ist trivial - die Anzahl der Bits für die Multiplikation ist mehr)))) Vergewissern Sie sich, dass die Anzahl der Bits in der binären Darstellung der Größe der Struktur gleich ist))) Dummerweise Prozessor, sowie ein Mann, länger zu multiplizieren 1111*101 als 1111*10)

Ich werde nicht nachsehen, es gibt genug andere Aufgaben. Aber es fällt mir schwer, das zu glauben.

 

In ME arbeite ich mit mqh, drücke ALT+N - die Baumansicht im Navigatorfenster zeigt den Ort der Datei.

Jetzt möchte ich sie in eine offene mq5-Datei einfügen. Ich ziehe mqh aus dem Baum auf mq5, aber es wird keine entsprechende Include-Zeile erzeugt.

 
fxsaber:

Ich werde nicht nachsehen, es gibt genug andere Aufgaben. Aber es fällt mir schwer, das zu glauben.

template <typename T>
size_t Func(T* arr,size_t arrSize)
{
000000013 FFC1DA0  mov         qword ptr [rsp+10 h],rdx  
000000013 FFC1DA5  mov         qword ptr [rsp+8],rcx  
000000013 FFC1DAA  push        rbp  
000000013 FFC1DAB  push        rdi  
000000013 FFC1DAC  sub         rsp,148 h  
000000013 FFC1DB3  lea         rbp,[rsp+20 h]  
000000013 FFC1DB8  mov         rdi,rsp  
000000013 FFC1DBB  mov         ecx,52 h  
000000013 FFC1DC0  mov         eax,0 CCCCCCCCh  
000000013 FFC1DC5  rep stos    dword ptr [rdi]  
000000013 FFC1DC7  mov         rcx,qword ptr [rsp+168 h]  
000000013 FFC1DCF  lea         rcx,[__116109BC_Test@cpp (013 FFD5029h)]  
000000013 FFC1DD6  call        __CheckForDebuggerJustMyCode (013 FFC10B9h)  
    // Write
    for (size_t i = 0; i <arrSize; ++i)
000000013 FFC1DDB  mov         qword ptr [rbp+8],0  
000000013 FFC1DE3  jmp         Func<STRUCT1>+50 h (013 FFC1DF0h)  
000000013 FFC1DE5  mov         rax,qword ptr [rbp+8]  
000000013 FFC1DE9  inc         rax  
000000013 FFC1DEC  mov         qword ptr [rbp+8],rax  
000000013 FFC1DF0  mov         rax,qword ptr [arrSize]  
000000013 FFC1DF7  cmp         qword ptr [rbp+8],rax  
000000013 FFC1DFB  jae         Func<STRUCT1>+71 h (013 FFC1E11h)  
        arr[i].i = i;
000000013 FFC1DFD  imul        rax,qword ptr [rbp+8],18 h  
000000013 FFC1E02  mov         rcx,qword ptr [arr]  
000000013 FFC1E09  mov         edx,dword ptr [rbp+8]  
000000013 FFC1E0C  mov         dword ptr [rcx+rax],edx  
000000013 FFC1E0F  jmp         Func<STRUCT1>+45 h (013 FFC1DE5h)  

    size_t Sum = 0;
000000013 FFC1E11  mov         qword ptr [Sum],0  

    // Read
    for (size_t i = 0; i < arrSize; ++i)
000000013 FFC1E19  mov         qword ptr [rbp+48 h],0  
000000013 FFC1E21  jmp         Func<STRUCT1>+8 Eh (013 FFC1E2Eh)  
000000013 FFC1E23  mov         rax,qword ptr [rbp+48 h]  
000000013 FFC1E27  inc         rax  
000000013 FFC1E2A  mov         qword ptr [rbp+48 h],rax  
000000013 FFC1E2E  mov         rax,qword ptr [arrSize]  
000000013 FFC1E35  cmp         qword ptr [rbp+48 h],rax  
000000013 FFC1E39  jae         Func<STRUCT1>+0 BBh (013 FFC1E5Bh)  
        Sum += arr[i].i;
000000013 FFC1E3B  imul        rax,qword ptr [rbp+48 h],18 h  
000000013 FFC1E40  mov         rcx,qword ptr [arr]  
000000013 FFC1E47  movsxd      rax,dword ptr [rcx+rax]  
000000013 FFC1E4B  mov         rcx,qword ptr [Sum]  
000000013 FFC1E4F  add         rcx,rax  
000000013 FFC1E52  mov         rax,rcx  
000000013 FFC1E55  mov         qword ptr [Sum],rax  
000000013 FFC1E59  jmp         Func<STRUCT1>+83 h (013 FFC1E23h)  

    return Sum + arrSize;
000000013 FFC1E5B  mov         rax,qword ptr [arrSize]  
000000013 FFC1E62  mov         rcx,qword ptr [Sum]  
000000013 FFC1E66  add         rcx,rax  
000000013 FFC1E69  mov         rax,rcx  
}
000000013 FFC1E6C  lea         rsp,[rbp+128 h]  

Es geht um eine kleine Struktur.

template <typename T>
size_t Func(T* arr,size_t arrSize)
{
000000013 FFC1EB0  mov         qword ptr [rsp+10 h],rdx  
000000013 FFC1EB5  mov         qword ptr [rsp+8],rcx  
000000013 FFC1EBA  push        rbp  
000000013 FFC1EBB  push        rdi  
000000013 FFC1EBC  sub         rsp,148 h  
000000013 FFC1EC3  lea         rbp,[rsp+20 h]  
000000013 FFC1EC8  mov         rdi,rsp  
000000013 FFC1ECB  mov         ecx,52 h  
000000013 FFC1ED0  mov         eax,0 CCCCCCCCh  
000000013 FFC1ED5  rep stos    dword ptr [rdi]  
000000013 FFC1ED7  mov         rcx,qword ptr [rsp+168 h]  
000000013 FFC1EDF  lea         rcx,[__116109BC_Test@cpp (013 FFD5029h)]  
000000013 FFC1EE6  call        __CheckForDebuggerJustMyCode (013 FFC10B9h)  
    // Write
    for (size_t i = 0; i <arrSize; ++i)
000000013 FFC1EEB  mov         qword ptr [rbp+8],0  
000000013 FFC1EF3  jmp         Func<STRUCT3>+50 h (013 FFC1F00h)  
000000013 FFC1EF5  mov         rax,qword ptr [rbp+8]  
000000013 FFC1EF9  inc         rax  
000000013 FFC1EFC  mov         qword ptr [rbp+8],rax  
000000013 FFC1F00  mov         rax,qword ptr [arrSize]  
000000013 FFC1F07  cmp         qword ptr [rbp+8],rax  
000000013 FFC1F0B  jae         Func<STRUCT3>+71 h (013 FFC1F21h)  
        arr[i].i = i;
000000013 FFC1F0D  imul        rax,qword ptr [rbp+8],58 h  
000000013 FFC1F12  mov         rcx,qword ptr [arr]  
000000013 FFC1F19  mov         edx,dword ptr [rbp+8]  
000000013 FFC1F1C  mov         dword ptr [rcx+rax],edx  
000000013 FFC1F1F  jmp         Func<STRUCT3>+45 h (013 FFC1EF5h)  

    size_t Sum = 0;
000000013 FFC1F21  mov         qword ptr [Sum],0  

    // Read
    for (size_t i = 0; i < arrSize; ++i)
000000013 FFC1F29  mov         qword ptr [rbp+48 h],0  
000000013 FFC1F31  jmp         Func<STRUCT3>+8 Eh (013 FFC1F3Eh)  
000000013 FFC1F33  mov         rax,qword ptr [rbp+48 h]  
000000013 FFC1F37  inc         rax  
000000013 FFC1F3A  mov         qword ptr [rbp+48 h],rax  
000000013 FFC1F3E  mov         rax,qword ptr [arrSize]  
000000013 FFC1F45  cmp         qword ptr [rbp+48 h],rax  
000000013 FFC1F49  jae         Func<STRUCT3>+0 BBh (013 FFC1F6Bh)  
        Sum += arr[i].i;
000000013 FFC1F4B  imul        rax,qword ptr [rbp+48 h],58 h  
000000013 FFC1F50  mov         rcx,qword ptr [arr]  
000000013 FFC1F57  movsxd      rax,dword ptr [rcx+rax]  
000000013 FFC1F5B  mov         rcx,qword ptr [Sum]  
000000013 FFC1F5F  add         rcx,rax  
000000013 FFC1F62  mov         rax,rcx  
000000013 FFC1F65  mov         qword ptr [Sum],rax  
000000013 FFC1F69  jmp         Func<STRUCT3>+83 h (013 FFC1F33h)  

    return Sum + arrSize;
000000013 FFC1F6B  mov         rax,qword ptr [arrSize]  
000000013 FFC1F72  mov         rcx,qword ptr [Sum]  
000000013 FFC1F76  add         rcx,rax  
000000013 FFC1F79  mov         rax,rcx  
}
000000013 FFC1F7C  lea         rsp,[rbp+128 h]  

Dies ist für einen großen.

VS2019, Debug x64, in Version es inlined sie, aber die Geschwindigkeit ist die gleiche.

Der einzige Unterschied besteht in den imul-Befehlen, dem dritten Operanden, an zwei Stellen. Die Anweisung ist genau das: die Berechnung des Offsets im Array, und der dritte Operand istdie Größe der Struktur in Bytes.

Also keine Mystik - physikalische Gesetze in Aktion.

 
Vladimir Simakov:

Also keine Mystik - die Gesetze der Physik sind in Kraft.

wenn Sie solche Klassen schreiben:

//+------------------------------------------------------------------+
struct STRUCT
{
   int i;
   double d;
   uchar uc[16];
};
//+------------------------------------------------------------------+
class A
{
private:
   int i;
   double d;
   uchar uc[16];
public:
   A(const STRUCT &ini) { i = ini.i; d = ini.d; ArrayCopy(uc,ini.uc); }
};
//+------------------------------------------------------------------+
class B
{
private:
   STRUCT data;
public:
   B(const STRUCT &ini) { data = ini; }
};
//+------------------------------------------------------------------+

Nach Ihren Recherchen zu urteilen, wird die Klasse B langsamer ausgeführt, wenn Sie häufig Strukturfelder in Berechnungen verwenden?

Grund der Beschwerde: