エラー、バグ、質問 - ページ 2165

 

負の値に対する最適化グラフが表示されないのですが。

このデータは、最適化結果で利用できます。

EAにマイナス値を設定してみてください。値はチェックのため * -1 とすることができる。

 
Renat Fatkhullin:

調べてみると、そうだった。

  1. SQRTをCPUのダイレクト命令へマッピング

  2. SQRT +数学計算を 分岐なしで行い、1命令(128ビットデータ)で2つの根を同時に計算する

    このコードは、次のようなアセンブラSSEコードに変化します。
    これは、実は芸術作品なんです。アセンブラ命令の4回の呼び出しで8個の根を計算した。1回の呼び出しで2つの倍数が評価される。

  3. 配列を操作する場合、チェック、分岐、ダブルから整数へのインデックス変換時の損失など、すべて通常通り行われます。

  4. この例で配列を扱う場合、FPUとALUが常に混在することになり、生産性が非常に悪くなる

  5. 動的配列アクセスの最適化は、賞賛に値する素晴らしいものです。しかし、FPU/ALU演算+ダブル→整数+分岐の混在は時間を浪費する

一般的な結論は、完璧な最適化により、MQL5では数学が勝利した、というものです。ここで負けるのはアレイではなく、数学の勝利です。

貴重な情報をありがとうございました。

もちろん、もっと嬉しいニュースもある。本当にカッコイイです!

MQは美品だ!といつも言っています。

しかし、データ型の混在には十分注意しなければならないことも実感しています。しかし、予断は禁物です。
このような観点から、開発者の方々のアドバイスを頂ければ幸いです。

では、通常の変数と配列の両方の型について実験してみます。何が出てくるんでしょうね。

 
Renat Fatkhullin:

実験してみました。

まだ、パズルが解けないようです。

2種類のバリエーションを作りました。1つ目 - すべてをint型に 変換しました。2つ目は、「2倍にする」。

はい、少し速くなりました。しかし、最大の欠点はまだあります。

こちらは、int型の変形を加えたメインブレーキブロックです。

 if(arr)
        {  // расчет квадратных корней через массив значений SQRT[]
         D1=SQRT[((X1-X)*(X1-X)+(Y1-Y)*(Y1-Y))];
         D2=SQRT[((X2-X)*(X2-X)+(Y2-Y)*(Y2-Y))];
         D3=SQRT[((X3-X)*(X3-X)+(Y3-Y)*(Y3-Y))];
         D4=SQRT[((X4-X)*(X4-X)+(Y4-Y)*(Y4-Y))];
         D5=SQRT[((X5-X)*(X5-X)+(Y5-Y)*(Y5-Y))];
         D6=SQRT[((X6-X)*(X6-X)+(Y6-Y)*(Y6-Y))];
         D7=SQRT[((X7-X)*(X7-X)+(Y7-Y)*(Y7-Y))];
         D8=SQRT[((X8-X)*(X8-X)+(Y8-Y)*(Y8-Y))];
        }

int型のみで、型の混在はありません。SQRT配列自体がint型になりました。

10%だけ速く動作します。

ダブルバリアントの状況も同様です。

最初のケースでは、sqrt()関数が計算され、型が混在しているだけで、すべて同じです。

一方、2番目のケースはint型の配列を参照しており、型の混在はなく、理論的にはALUのみを使用するはずです。

しかし、2番目の方法は3倍も遅い。まあ、理由はどうであれ、配列ですからね。

もうひとつ、大切なことがあります。

intの例では、キャンバスのサイズが100x100の場合、つまり次のようなパラメータを持つ場合です。

を使用すると、配列にアクセスする際の速度が向上します。

例えば、サイズが20 000のSQRT配列を使用した場合、15-20%の利益が得られ、サイズが3 000 000の配列を使用した場合、全く同じ数学にもかかわらず、200%の損失が得られます。

配列の大きさがブレーキの原因なんですね。

ファイル:
LSD_double.mq5  10 kb
LSD_int.mq5  10 kb
 

現代のC++コンパイラの結果を理解する能力を、人々はとっくの昔に失っている。

さらに、コードがごちゃごちゃしているので、「こういう条件なら、結果はこうなる」という素朴な公理を作る可能性はほとんどゼロです。つまり、最適化の結果、すべてが再配置され、コードをごくわずかに変更しただけでも、仮説が何十パーセントも異なる結果を生み出すことになるのです。

4つのアセンブラコマンドに8つのルーツを詰め込むことをもう一度見直して、自分の論理を主張したり要求したり訴えたりするチャンスがないことに気づいてください。オプティマイザーは、長い間、プログラマーの手の届かない法外なレベルで運用されてきた。

コンパイラがルートを分解する方法は芸術です。しかも、配列からの読み込みはすでに失敗している、という最も単純な制約すら理解せずに配列で叩こうとしているのです。完璧なレジスタワークと、根っこと分岐の一括計算(ペナルティ)、キャッシュミスが頻発するメモリへの登載。

なぜ小さいバッファでは速く、大きいバッファでは惨敗するのか」という質問は、CPUのL1/L2/L3キャッシュのことを全く知らないからです。キャッシュに入れば、すぐにカウントされた。捕捉されない - 上位キャッシュまたはメモリからのデータ読み出しの数十サイクルを待つ。
 
Renat Fatkhullin:

現代のC++コンパイラの結果を理解する能力を、人々はとっくの昔に失っている。

さらに、コードがごちゃごちゃしているので、「こういう条件なら、結果はこうなる」という素朴な公理を作る可能性はほとんどゼロです。つまり、最終的な最適化によってすべてが再配置されるため、コードをごくわずかに変更しただけでも、仮説が数十パーセントも異なる結果を生み出すことになるのです。

4つのアセンブラコマンドに8つのルーツを詰め込むことをもう一度見直して、自分の論理を主張したり要求したり訴えたりするチャンスがないことに気づいてください。オプティマイザーは、長い間、プログラマーの手の届かない法外なレベルで運用されてきた。

VSと比較した結果が完璧にわかるので、嬉しく思います。
しかし、疑問は残ります。

混沌とした作業コードで申し訳ないのですが、この部分のコードの話と、2つの実行オプションの比較だけです。

 if(arr)
        {  // расчет квадратных корней через массив значений SQRT[]
         D1=SQRT[((X1-X)*(X1-X)+(Y1-Y)*(Y1-Y))];
         D2=SQRT[((X2-X)*(X2-X)+(Y2-Y)*(Y2-Y))];
         D3=SQRT[((X3-X)*(X3-X)+(Y3-Y)*(Y3-Y))];
         D4=SQRT[((X4-X)*(X4-X)+(Y4-Y)*(Y4-Y))];
         D5=SQRT[((X5-X)*(X5-X)+(Y5-Y)*(Y5-Y))];
         D6=SQRT[((X6-X)*(X6-X)+(Y6-Y)*(Y6-Y))];
         D7=SQRT[((X7-X)*(X7-X)+(Y7-Y)*(Y7-Y))];
         D8=SQRT[((X8-X)*(X8-X)+(Y8-Y)*(Y8-Y))];
        }
 else // расчет квадратных корней через функцию кв. корня sqrt()
        {
         D1=(int)sqrt((X1-X)*(X1-X)+(Y1-Y)*(Y1-Y));
         D2=(int)sqrt((X2-X)*(X2-X)+(Y2-Y)*(Y2-Y));
         D3=(int)sqrt((X3-X)*(X3-X)+(Y3-Y)*(Y3-Y));
         D4=(int)sqrt((X4-X)*(X4-X)+(Y4-Y)*(Y4-Y));
         D5=(int)sqrt((X5-X)*(X5-X)+(Y5-Y)*(Y5-Y));
         D6=(int)sqrt((X6-X)*(X6-X)+(Y6-Y)*(Y6-Y));
         D7=(int)sqrt((X7-X)*(X7-X)+(Y7-Y)*(Y7-Y));
         D8=(int)sqrt((X8-X)*(X8-X)+(Y8-Y)*(Y8-Y));
        }

ここにはゴミがない。

"ダイナミックアレイアクセスの 最適化は、賞賛に値するほど素晴らしい "とおっしゃっていましたね。

でも...前回のメッセージをご覧ください。

前回の実験をどう説明するんだ?

"つまり、サイズ20,000のSQRT配列を使うと15〜20%の利得になり、サイズ3,000,000の配列を使うと、まったく同じ計算で200%の損失となるのです。

アレイの大きさがブレーキの原因なんですね。"

 

私の前回の返信をよく読んでみてください。

ご質問を簡単に説明しますと、プロセッサの設計について、性能とそれに影響を与える要因の観点から5つの技術論文を熟読してください。基本的なことを説明する必要があるので、それがないと議論にならないのです。

 
Renat Fatkhullin:

コンパイラが根こそぎ分解した方法は芸術だ。しかも、配列からの読み込みはすでに失敗している、という最も単純な制約すら理解せずに配列で叩こうとしてるんですね。完璧なレジスタワークと、根っこと分岐の一括計算(ペナルティ)、キャッシュミスが頻発するメモリへの登載。

プロセッサのL1/L2/L3キャッシュのことを全く知らないから「なぜ小さなバッファでは速く、大きなバッファでは耳障りなほど失敗するのか」と質問しているのでしょう。キャッシュに入れば、すぐにカウントされた。これがないと、上位キャッシュやメモリからデータを読み出すのに数十サイクルも待たされることになります。
レナト・ファットフーリン

前の返信をよく読んでください。正確な答えで終わっています。

ご質問の内容を簡単に説明しますと、プロセッサの設計について、性能とそれに影響を与える要因の観点から5つの技術論文を熟読してください。基本的なことを説明する必要があるので、それがないと議論にならないのです。

やったーーーーーーーーーーーー
ついに登場!
レナート君、何でもかんでもつまみ食いするのはいかがなものか。

私の中でイメージが明確になりました。

コンパイラのせいにしていたのは私の間違いでした。ごめんなさい、私が間違っていました。その理由は、プロセッサの限られたキャッシュにあると推測していたかもしれません。現代のプロセッサーは本当に苦手で、どうしても読んでおきたい。

それでも、このコード-ラボラトリーラット-を書き、この波を作ったことは無駄ではありません。

そこで、このスレッドを読んでいるプログラマのために、私自身がこの波の結果、分かったことをまとめておきます。

  • sqrt()関数や他の多くの初等関数は非常に高速で、コンパイラレベルではなく、CPUレベルで実行されることがほとんどです。
  • MQL5コンパイラは、数学的ロジックの最適化に強く、最新のVS C++コンパイラを簡単に打ち負かすことができるのです。それはとても感動的なことです。
  • リソースを大量に消費するタスクでは、タイプを混在させないようにするのが合理的です。タイプが混在すると、計算速度が低下する。
  • サイズが重要( というのも、プロセッサの多値キャッシュの 動作の特殊性と、そのサイズに制限があるためです。そしてプログラマーは、配列の総サイズに注意し、大きな配列を使うと計算速度に大きな影響を与える可能性があることを理解しておくとよいでしょう。私が理解する限り、ポイントは、合計サイズが512kB程度を超えない配列で、double型で〜65000要素、int型で〜130000要素で、比較的快適に作業できることだと思うのですが...。

この情報を頼りに、自分のコードを修正しに行った。私はよく配列の大きさを乱用します。

皆さん、ありがとうございました。

 

十字キーが押されたか離されたかを知るにはどうしたらよいですか?

マウスホイールが押されたときにキャッチすることはできますが、マウスが使用中でない場合はどのようにすればよいのでしょうか。

 
Alexandr Bryzgalov:

十字キーが押されたか離されたかを知るにはどうしたらよいですか?

マウスのホイールクリックをキャッチすることはできますが、マウスを使用していない場合はどうでしょう。

必要なときに無理やり押し込む、押し戻すというのはどうでしょうか。

チャートクロスヘアツール

マウスの中ボタンを押すことで「十字キー」ツールを使用可能/不可能にできる

ブール(初期値true)

 
Alexey Viktorov:

必要であれば、強制的に、あるいは押し戻すことができるのか?

チャートクロスヘアツール

マウスの中ボタンで十字キーにアクセスできるようにした。

ブール(デフォルトでは真)

私の理解では、ツールにアクセスするだけで、オフにすることはできません。