MQL5におけるOOPに関する質問 - ページ 70

 
Maxim Kuznetsov:

これは「ループアンローリング」と呼ばれ、OOやテンプレートを使わずにコンパイラによって行われる(少なくともそうでなければならない)。

中間コード(アセンブラ)を見ると、ループの代わりにN個の演算が連続しているだけだ。

また、関数が 再帰的に呼ば れるとどうなるのか、教えてください。

 
Dmitry Fedoseev:

関数が 再帰的に呼ば れるとどうなるか、教えてください。

ターゲット関数への再帰的な呼び出しはありません :-)

上記の例では、N:=constは、テンプレートからコードが生成され、そのテンプレートが調整されたときにのみ再帰が発生します。リンク先では、const-cycleをテンプレート再帰に畳み込み、巧みな言葉としています

マクロにループがある場合、次のように記述されます。

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

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

#endfor

と、マクロプロセッサの後に、N個の王子の連続に展開されるのです。(実際にはテンプレートクラスを通してのみ実現しました)

つまり、コンパイル時にNが分かっている場合にのみ、このトリックは有効です

 
Maxim Kuznetsov:

で、ターゲット関数への再帰的な呼び出しはありません :-)

リンク先のN:=constの例では、再帰はテンプレートからのコード生成時のみで、その1つはtailである。リンク先では、const-cycleをテンプレート再帰に畳み込み、巧みな言葉としています

マクロにループがある場合、次のように記述されます。

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

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

#endfor

と、マクロプロセッサの後に、N個の王子の連続に展開されるのです。(実際にはテンプレートクラスを通してのみ実現しました)

つまり、このトリックはコンパイル時にNが分かっている場合にのみ有効です

信じられないかもしれませんが、私はテンプレートの仕組みやNがあること、その結果どうなるかを知っています。そして、再帰的な関数呼び出しについての 私の質問は、まさに再帰的な関数呼び出しについてのもので、そこでの方法についてのものではありませんでした。

 
Dmitry Fedoseev:

信じられないかもしれませんが、私はテンプレートの仕組みやNがどうなっているか、その結果どうなるかを知っています。そして、再帰的な関数呼び出しについての 私の質問は、まさに再帰的な関数呼び出しについてのもので、そこでの方法についてのものではありませんでした。

は、"あえて?"な試験という感じでしょうか。:-) なんとなくこの例が議論されていると思ったのですが...違いました :-)

コンパイラが再帰を末尾に変換できる場合(あるいは明示的にそうなっている、あるいはそうしろと言われた)、物理的には再帰は発生しません - ループを作り(スイッチバック)、各反復が前のスタックフレームを「踏みつぶす」ことになります。

 
Maxim Kuznetsov:

は、ある種の「あえての」試験なのでしょうか?:-) なんとなくこの例が議論されていると思ったのですが...違いました :-)

コンパイラが再帰を末尾再帰に変換できる場合(あるいは明示的にそのように指示されている場合)、物理的には再帰は発生しません - ループを作り(スイッチバック)、各反復が前のスタックフレームを「踏みつぶす」ことになります。

弱さと何か関係があるのでしょうか?ちょっと質問です。まあ、だからダメなんです。

 
fxsaber:

悩む気にもならない。シンプルな構造を作りました。



単純な構造体の最初のフィールドへのアクセスがそのサイズに依存する理由は何なのか、私には理解できない。

へぇー。些細なことですが、掛け合わせるビットの数が多くなります)))構造体の大き さを表す2進数のビット数が同じだったことを確認する)))1111*10より1111*101を掛ける方が長いというバカプロセッサー、人間としても)
 
Vladimir Simakov:
へぇー。些細なことですが、乗算のビット数の方が多いのです)))構造 体のサイズを表す2進数のビット数が同じだったことを確認する)))1111*10より1111*101を掛ける方が長いというバカプロセッサー、人間としても)

確認しない、他のタスクがたくさんある。でも、信じがたい話ですね。

 

MEでは、mqhで作業し、ALT+Nを押します - ナビゲータウィンドウのツリービューには、ファイルの場所が表示されます。

今、私はそれを開いているmq5ファイルにインクルードしたいと思います。ツリーからmqhをmq5にドラッグしても、適切なinclude行が生成されない。

 
fxsaber:

確認しない、他のタスクがたくさんある。でも、信じがたい話ですね。

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]  

小さな構造物用です。

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]  

これは大型のもの用です。

VS2019、Debug x64、releaseではインライン化されましたが、速度は同じです。

唯一の違いは、第3オペランドであるイムル命令の2カ所です。この命令は、そのまま配列のオフセットを計算し、第3オペランドは構造体のサイズ(バイト)を計算します。

つまり、神秘主義ではなく、物理法則が作用しているのです。

 
Vladimir Simakov:

つまり、神秘主義ではなく、物理の法則が働いているのです。

そのようなクラスを作成する場合

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

ということは、計算で構造体フィールドを多用すると、クラスBの 実行速度が遅くなるのでしょうか?