Domande su OOP in MQL5 - pagina 70

 
Maxim Kuznetsov:

questo si chiama "loop unrolling" ed è fatto dal compilatore senza OO e template (almeno dovrebbe essere così).

Se guardate il codice intermedio (assembler), ci sono solo N operazioni consecutive invece di un ciclo.

E puoi dirci cosa succede quando una funzione viene chiamata ricorsivamente?

 
Dmitry Fedoseev:

Potete dirmi cosa succede quando una funzione viene chiamata ricorsivamente?

non c'è nessuna chiamata ricorsiva alle funzioni di destinazione :-)

Nell'esempio dato sopra N:=const, la ricorsione avviene solo quando il codice viene generato da un modello e questo viene adattato. Al link, una torsione intelligente è quella di far collassare il ciclo const in una ricorsione template e chiamarlo una parola intelligente

se le macro avessero dei cicli sarebbe scritto così

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

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

#endfor

e dopo il processore macro si dispiegherebbe in una sequenza di N principi. (cosa che in realtà è avvenuta, solo attraverso le classi template)

Cioè, il trucco funziona solo se N è noto al momento della compilazione

 
Maxim Kuznetsov:

e non c'è nessuna chiamata ricorsiva alle funzioni di destinazione :-)

Nell'esempio dato al link N:=const, la ricorsione è solo alla generazione di codice da un modello e quello è la coda. Al link, una torsione intelligente è quella di far collassare il ciclo const in ricorsione template e chiamarlo una parola intelligente

se le macro avessero dei cicli sarebbe scritto così

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

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

#endfor

e dopo il processore macro si dispiegherebbe in una sequenza di N stampe. (che in realtà è successo, solo attraverso le classi template)

Quindi il trucco funziona solo se N è noto al momento della compilazione

Non ci crederete, ma so come funzionano i template e che N c'è, e qual è il risultato. E la mia domanda sulla chiamata di funzione ricorsiva era esattamente sulla chiamata di funzione ricorsiva, non su come lì?

 
Dmitry Fedoseev:

Non ci crederete, ma so come funzionano i template, qual è la N e qual è il risultato. E la mia domanda sulla chiamata di funzione ricorsiva era esattamente sulla chiamata di funzione ricorsiva, non su come lì?

è come un esame "obbligo?"? :-) In qualche modo pensavo che questo esempio fosse stato discusso... mi sbagliavo :-)

Se il compilatore può convertire la ricorsione in una coda (o è esplicitamente tale, o gli è stato detto di farlo), allora fisicamente non ci sarà ricorsione - farà un ciclo (switch back) e ogni iterazione "calpesterà" il precedente stack frame.

 
Maxim Kuznetsov:

è una specie di esame "obbligo"? :-) In qualche modo pensavo che questo esempio fosse stato discusso...mi sbagliavo :-)

Se il compilatore può convertire la ricorsione in una ricorsione di coda (o è esplicitamente tale o gli è stato detto di farlo), allora fisicamente non ci sarà ricorsione - farà un ciclo (switch back) e ogni iterazione "calpesterà" lo stack frame precedente.

Cosa c'entra questo con la debolezza? Solo una domanda. Beh, no, quindi no.

 
fxsaber:

Non voglio nemmeno disturbare. Ho fatto strutture semplici.



Per quale motivo l'accesso al primo campo di una struttura semplice dipende dalla sua dimensione - non capisco.

Huh. È banale - il numero di bit da moltiplicare è più)))) Assicuratevi che il numero di bit nella rappresentazione binaria della dimensione della struttura sia lo stesso)))) Stupidamente processore, così come un uomo, più lungo per moltiplicare 1111*101 che 1111*10)
 
Vladimir Simakov:
Huh. È banale - il numero di bit per la moltiplicazione è più)))) Assicurarsi che il numero di bit nella rappresentazione binaria della dimensione della struttura fosse lo stesso))) Stupidamente processore, così come un uomo, più lungo per moltiplicare 1111*101 che 1111*10)

Non controllerò, ci sono molti altri compiti. Ma lo trovo difficile da credere.

 

In ME, lavoro con mqh, premi ALT+N - la vista ad albero nella finestra Navigatore mostra la posizione del file.

Ora voglio fare un incluedere in un file mq5 aperto. Trascino mqh dall'albero a mq5, ma non viene generata nessuna linea include appropriata.

 
fxsaber:

Non controllerò, ci sono molti altri compiti. Ma lo trovo difficile da credere.

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]  

È per una piccola struttura.

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]  

Questo è per un grande.

VS2019, Debug x64, nel rilascio li ha delineati, ma la velocità è la stessa.

L'unica differenza è nelle istruzioni imul, il terzo operando, in due punti. L'istruzione è proprio questo, calcolare l'offset nell'array, e il terzo operando è ladimensione della struttura in byte.

Quindi, nessun misticismo - leggi della fisica in azione.

 
Vladimir Simakov:

Quindi, nessun misticismo - le leggi della fisica sono in azione.

se si scrivono tali classi:

//+------------------------------------------------------------------+
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; }
};
//+------------------------------------------------------------------+

A giudicare dalla tua ricerca, la classe B sarà più lenta da eseguire se usi frequentemente campi struttura nei calcoli?