汎用クラスライブラリ - バグ、説明、質問、使用上の特徴、提案 - ページ 14

 
セルゲイ・デジュブリク

私としては、あるオブジェクトがあるインターフェースやメソッドを実装していない場合、黙って問題の原因を探すよりも、例外を発生させた方が良いと考えています。

  • MQL5では、インターフェースはありません。
  • MQL5では例外はありません。

そして最後には、素晴らしいセルフシューティングと、コードによる問題の隠蔽を明らかにするのです。

 
ワシリー・ソコロフ

同じ理由で、この比較は正しくありません。カスタムCHashMapの比較やシステム機能との連携で、取引環境を整えるにはどうすればいいのか?

鉄壁の議論を受け入れないので、最適でないコードを書き続ける。

トレーディング、自動売買システム、ストラテジーテストに関するフォーラム

汎用クラスライブラリ - バグ、説明、問題、使用例、提案

fxsaber さん 2017.12.08 22:46

より現実的なテスターケース(2000トレード、1,000,000シングルヒストリーアクセス)の場合、結果は以下のようになります。

2017.12.05 00:00:00   Time[Print(SumProfit(Deals,GetDealProfitFull))] = 122969
2017.12.05 00:00:00   Time[SetHashMap()] = 816
2017.12.05 00:00:00   4829800340.792288
2017.12.05 00:00:00   Time[Print(SumProfit(Deals,GetDealProfitHashClear))] = 23852
2017.12.05 00:00:00   Time[HistorySelect(0,INT_MAX)] = 1
2017.12.05 00:00:00   4829800340.792288
2017.12.05 00:00:00   Time[Print(SumProfit(Deals,GetDealProfitClear))] = 114427

1パスあたり約100msの短縮を実現例えば、10,000回のフルパスで最適化を行った場合、Hashバリアントは15分早く終わります。

ワシリー・ソコロフ

すべてにおいて、そう、立派な自己解決であり、コードの問題点の見かけ上の隠蔽である。

二人ともくだらないことを書いていて、今の形のHashMapは構造体やユニオンには使えないということを理解していない。
 
fxsaber

鉄板の議論を受け入れないなら、最適でないコードを書き続けろ。

HashMapが構造体やユニオンのために機能しないことを少しも理解していない、ナンセンスなことをお二人は書いています。

親愛なる皆さん、もしあなたが何かを吸って、対話者の投稿を注意深く 読むことができないなら、それはあなたの問題であり、治療が必要なのは他のみんなではなく、病人だけなのです。
繰り返しになりますが、誰も構造物と組合の問題を提起していませんし、このテーマについてあなたの考えに異議を唱えた人もいません...。


具体的には、それらのコード用語についてでした。
標準ライブラリから。

//+------------------------------------------------------------------+
//| Returns a hashcode for custom object.                            |
//+------------------------------------------------------------------+
template<typename T>
int GetHashCode(T value)
  {
//--- try to convert to equality comparable object  
   IEqualityComparable<T>*equtable=dynamic_cast<IEqualityComparable<T>*>(value);
   if(equtable)
     {
      //--- calculate hash by specied method   
      return equtable.HashCode();
     }
   else
     {
      //--- calculate hash from name of object
      return GetHashCode(typename(value));
     }
  }
//+------------------------------------------------------------------+



そして、あなたが追加したもの。

トレーディング、自動売買システム、ストラテジーテストに関するフォーラム

汎用クラスライブラリ - バグ、説明、問題、使用例、提案

fxsaber さん 2017.12.08 21:17

別のオーバーロードを追加

template<typename T>
int GetHashCode(T &value)
  {
    return GetHashCode(typename(value));
  }


あなたが伝えようとしたこと。
ハッシュは、コンテナ内のアイテムの検索を高速化するために使用されます。速度はO(1) - コンテナに追加されるアイテムの数には依存しない。
状況 - ユーザーが自分のクラスをキーとして使用している。
1) インターフェースの多重継承ができない(MQL5にはインターフェースが ない ため、IEqualityComparableを継承する ことができない。
2) GetHashCode テンプレート関数に対する明示的な指定も忘れている。

その結果、ユーザーは何かを省略したことを知らされず、コードは例外を発生させずに正常に実行されます(MQL5には例外は 存在しません
平均的なハッシュ計算定数を持つO(1)から、比較の上でかなり大きな定数を持つO(n)へと速度が低下する。
コンテナ内の要素が大量にあり、
実装のボトルネックを探すのに多くの時間を費やした場合にのみ、ユーザーは問題の原因、つまり自分のクラスに明示的にGetHashCodeが指定されていないことを見つけることができるかもしれません。
悪気はないんです、ありがとうございます。

 
しかし、なぜトレーディングのために、このような間違いなくクールなことをするのでしょうか?
何千もの取引を履歴から取り出し、それを発生させた注文を探すなどということは、今までに一度もなかったことです。
 
セルゲイ・デジュブリク

拝啓、何かを吸って対談者の投稿をしっかり 読めないのはあなたの問題であり、治療すべきは他の皆ではなく、病人だけです。

どうやらミトンを閉じる方法はないようだ

#include <TypeToBytes.mqh> // https://www.mql5.com/ru/code/16280
#include <crc64.mqh>       // https://www.mql5.com/en/blogs/post/683577

template<typename T>
int GetHashCode( T &value )
{
  ulong crc = 0;

  return((int)crc64(crc, _R(value).Bytes, sizeof(T)));
}

template<typename T>
int GetHashCode( T &value[] )
{
  ulong crc = 0;

  return((int)crc64(crc, _R(value).Bytes, ArraySize(value) * sizeof(T)));
}
 
このトピックに関係のないコメントは、「アルゴリズム、解法、性能の比較」に移動しました。
 

本来は例題集ではないのですが、まだ実務で使っていない方にも、なぜこのアルゴリズムが便利で、何よりシンプルなのかを理解していただくために、やはり例題を追加する必要性を感じています。

 

例1:実行時エラーと その文字列の説明の関連付け

数値定数を文字列リテラルに変換する必要がある場合が非常に多い。例えば、エラーコードは、エラーを説明する明確なキャプションを付けて重複させた方が良い。これはそれほど難しいことではなく、通常は特殊な関数やスイッチケース、あるいは多くのifによって解決される。

string ErrorDescription(int error_code)
   if(error_code == 40001)
      return ("Неожиданная внутренняя ошибка");
   //...
}

そのような解決策には、生きる権利があるのです。しかし、ここではCHashMapをベースにした解決策を説明し、その利点を紹介します。

アルゴリズムはこんな感じでしょうか。

  • <バグコード - バグの説明> の ような連想配列を作成します。
  • 可能性のあるエラーコードとその説明をこの辞書に追加する。
  • 仲介者を介さずに直接、辞書にアクセスして、エラーのコードによる説明を取得します。
このコードは以下のようになります。

//+------------------------------------------------------------------+
//|                                                     OrdersID.mq5 |
//|                        Copyright 2017, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
#include <Generic\HashMap.mqh>
input ulong FindTicketOrder = 82479995;

CHashMap<int, string> ErrorDescription;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void AddDescriptionInfo(void)
{
   // Добавим коды системных ошибок
   ErrorDescription.Add(0,    "Операция выполнена успешно");
   ErrorDescription.Add(4001, "Неожиданная внутренняя ошибка");
   ErrorDescription.Add(4002, "Ошибочный параметр при внутреннем вызове функции клиентского терминала");
   ErrorDescription.Add(4003, "Ошибочный параметр при вызове системной функции");
   ErrorDescription.Add(4004, "Недостаточно памяти для выполнения системной функции");
   // Можно добавлять константные значения вместо чисел
   ErrorDescription.Add(ERR_STRUCT_WITHOBJECTS_ORCLASS, "Структура содержит объекты строк и/или динамических массивов и/или структуры с такими объектами и/или классы");
   ErrorDescription.Add(ERR_INVALID_ARRAY, "Массив неподходящего типа, неподходящего размера или испорченный объект динамического массива");   
   ErrorDescription.Add(ERR_ARRAY_RESIZE_ERROR, "Недостаточно памяти для перераспределения массива либо попытка изменения размера статического массива");
   //...
}
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
   AddDescriptionInfo();
   string last_error = "";
   ErrorDescription.TryGetValue(GetLastError(), last_error);
   printf("Последняя ошибка: " + last_error);
}
//+------------------------------------------------------------------+

エラーコードを記入すれば、別の機能を使うことなく、1行でアクセスできる。さらに、このコードは、必要なエラーへのアドレス指定が直接行われるため、場合によっては数十個のifよりもさらに高速に動作し、平均速度O(1)となることを念のためお伝えしておきます。

 
ワシリー・ソコロフ

エラーコードを一度入力すれば、別の関数を使わなくても、1つの文字列でアクセスできる。

ErrorToStringはいずれにせよ書かなければならない。だから、プラスアルファとしての論旨は弱い。

さらに、このコードは、必要なエラーへのアドレス指定が直接行われるため、平均速度O(1)で、数十のif関数よりも速く動作する場合があることを思い出してください。

しかし、これは明らかにプラスです。

 

提案する辞書ソリューションにはいくつかの利点があるが、その中でも最も重要なものは、一見しただけでは全く分からない。このようなコードを書くと

string ErrorDescription(int error_code)
   if(error_code == 40001)
      return ("Неожиданная внутренняя ошибка");
   //...
}

Expert Advisorのコード自体にハードウエアされているのです。辞書を埋めるときは、プログラムの実行 時に動的に 行う。ダイナミックアプローチは、より柔軟な対応が可能です。例えば、エラーコードは、ErrorsCode.txtのような特別なファイルに含まれるかもしれません。

4001;Операция выполнена успешно
4002;Неожиданная внутренняя ошибка
4003;Ошибочный параметр при вызове системной функции
...

起動時にプログラムはこのファイルを読み、必要なコードを辞書に詰め、必要な変形の文字列をユーザーに返すことができます。このようなファイルは、言語ごとに1ファイルずつ、複数個存在することができます。このように、ユーザーの言語に応じて、ユーザーの言語でのエラーコードを表示するローカライズを行うことができる。さらに、ユーザー自身がこれらのエラーコードを一度自分の言語に翻訳しておけば、プログラム自身が学習して希望のメッセージを自分の言語で出力してくれる。このように、メニューの翻訳をテキストファイルに入れておき、設定によってプログラムがそれを読み込むというのが、ほとんどのプログラムのローカライズの方法です。つまり、プログラムの再コンパイルやアルゴリズムの変更なしに、その結果の表現に大きな影響を与えることができるのです。