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

 
//+------------------------------------------------------------------+
//|                                              CompareFunction.mqh |
//|                   Copyright 2016-2017, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Generic\Interfaces\IComparable.mqh>
//+------------------------------------------------------------------+
//| Compares two objects and returns a value indicating whether one  |
//| is less than, equal to, or greater than the other.               |
//+------------------------------------------------------------------+
int Compare(const bool x,const bool y)
  {
   if(x>y)
      return(1);
   else if(x<y)
      return(-1);
   else
      return(0);
  }


この関数はグローバルに宣言されています。そのため、ユーザーによる比較と矛盾しています。

'Compare' - function already defined and has body

名前の衝突を減らすために、作者はすべてのグローバル補助Generic関数をpublic-static-methodsにすることができますか?

 

fxsaber:

名前の衝突を減らすために、作者はすべてのグローバル補助Generic関数をpublic-static-methodsにすることができますか?

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

コンパイラのバグ:'operator='-構造体がオブジェクトを持ち、コピーできない

fxsaber 2018.09.10 11:00 2018.09.10 10:00:13 RU
アレクセイ・ナヴォイコフ
これは当分の間です。誰かのライブラリを取り込みたい場合、作者があなたと同じように「プリミティブ」に書いていて、クラスや関数の名前も同じものを使っていることがわかるでしょう。

マクロで釘付けにします。

マクロについてはどうでしょうか?
 
A100:
マクロについてはどうでしょうか?

自分のことを言ってるんじゃないんです。

 

このページを全部読んだけど、使い方がよくわからないんだけど?

どなたか例を教えてください。

 
Vladimir Pastushak:

このページを全部読んだけど、使い方がよくわからないんだけど?

どなたか例を教えてください。

忘れてください。今のままでは使えません。代わりに標準のCObject+CDictionary を使用します。ほとんどの作業では、これで十分です。

 
Vasiliy Sokolov:


クラス商品説明
CHashMapキー・バリュー・セット。キーに基づいたアイテムの挿入、取り出し、検索を効率的に行えるようにします。キーは一意でなければならない。例えば、CHashMapは、番号をキーとして、指定した番号の注文を瞬時に探し出すことができます。

キーによる値の取得についての質問です。ライブラリのコードでは、このメソッドは次のようになります。

//+------------------------------------------------------------------+
//| Find index of entry with specified key.                          |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
int CHashMap::FindEntry(TKey key)
  {
   if(m_capacity!=NULL)
     {
      //--- get hash code from key
      int hash_code=m_comparer.HashCode(key)&0x7FFFFFFF;
      //--- search pair with specified key
      for(int i=m_buckets[hash_code%m_capacity]; i>=0; i=m_entries[i].next)
         if(m_entries[i].hash_code==hash_code && m_comparer.Equals(m_entries[i].key,key))
            return(i);
     }
   return(-1);
  }

ソースによるMEナビゲーションツール(ALT+GとCTRL+-)は、このライブラリでは動作しない。そのため、ロジックの追跡が非常に困難です。特に、ハイライトされたループの初期値がまだわかっていないんです。しかし、もし速度があるならば、この値はキーの数よりずっと少ないはずだという理解があります。


この機能で達成される速度はどの程度なのか、アイデアを明確にしてください。オーバーキルは明らかに存在する。でも、なぜか短いらしい。


SZ デバッガーを順を追って見ていきました。例題はすべてクリア TKey = int: m_bucket[Array[i]] = i.Array[i] == Array[j] (i != j)の場合の衝突のみ不明です。

 
fxsaber:

キーによる値の取得についての質問です。ライブラリのコードでは、このメソッドは次のようになります。
この機能を高速にするのは何か、アイデアを明確にしてください。オーバーシュートが明らかに出ている。でも、なぜか短いらしい。

一時期、CHashMapの 仕組みを復習して記述していました
エントリを検索する必要があります、おそらくこのスレッドにあると思います。

 

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

汎用クラスライブラリ - バグ、説明、質問、使用上の特殊性、提案

セルゲイ・デジブリク さん 2017.12.11 13:41

現在のCHashMapの 実装について簡単に説明します。

template<typename TKey,typename TValue>
class CHashMap: public IMap<TKey,TValue>
  {
protected:
   int               m_buckets[];                        
   Entry<TKey,TValue>m_entries[];
   int               m_count;
   int               m_free_list;
   int               m_free_count;
   IEqualityComparer<TKey>*m_comparer;
   bool              m_delete_comparer;

     .................................

.................................

}

まず、Entry<TKey,TValue>とは 何かについて説明します。
基本的にはCLinkedListのようなNodeで、これを含んでいます。

- コンテナのキーと値に配置された
- hash_code - key に対応するキャッシュされたハッシュ値。
- next - 単連結リストを介して衝突を解決するための,次のEntry<TKey,TValue> への "ポインタ" です.


m_entries[] - 追加されたキーと値、hash_code、next が配置される "セル" の配列。アレイの大きさは容量に相当します。
m_count - m_entries の最初の未使用セルのインデックスを指定する。初期値は0であり、Capacityまで成長し、次にCapacityと全アレイのサイズを増加させながら全アレイをリビルドする。
m_buckets[] - m_entries[] のインデックス配列.初期値は-1である。アレイサイズは容量に相当する。


衝突しない、CHashMap コンテナに一意な値を追加する。

  1. キーでハッシュを計算し、hash_codeを取得する。
  2. m_entries[]にキー、値、hash_codeをインデックスm_countで格納する。(例では衝突がないためnext = -1)
  3. m_entries[]に先ほど追加した要素のインデックス値をhash_code % (ArraySize(m_buckets)) だけm_buckets[]に入れる(これがm_countとなる)。
  4. m_countを+1する

CHashMap コンテナのキーで値を取得する。

  1. キーからハッシュを計算し、hash_codeを取得する。
  2. m_buckets[]から、hash_code % (ArraySize(m_buckets)) で、配列m_entries[]のインデックスとなる値を取得する。
  3. 取得したインデックス m_buckets[hash_code % (ArraySize(m_buckets))] を用いて、配列 m_entries[] から値を取得します。

衝突を解決する

異なるキーでは、hash_code_key_1 % (ArraySize(m_buckets)) と hash_code_key_2 % (ArraySize(m_buckets)) が等しいことがある。これを collision と呼ぶ。
m_entries[]に追加されたコリジョンを持つすべての要素は、nextで1連結リストを通してリンクされる(Entry<TKey,TValue> 構造を参照)。
そして、m_buckets[]は常にこの衝突リストの最初の先頭要素のインデックスを指します。
衝突を伴う1つの大きなリストではなく、多くの小さなリストを得ることができます。


衝突、CHashMap コンテナのキーで値を取得する。

  1. キーに対してハッシュを計算し、hash_codeを取得する。
  2. インデックスhash_code % (ArraySize(m_buckets)) を使って、m_entries[]配列から値を取得する。
  3. nextの値が-1になっていないことから、衝突があることがわかります
  4. m_entries[] の要素からなる単一エントリリストを走査し、求められた値と保存されたキーが等しいかどうかを比較する。


CHashMap コンテナから値を削除する。

- m_entries[] のセルを削除する場合、削除は行わず、空きセルとしてマークし、hash_code = -1 とする。
- free cell は、(Entry<TKey,TValue> から同じ next を使って) 自分自身のリストを形成し、m_free_list
-
フリーセルは、コンテナに新しい値を追加するために最初に使用されます。
-m_free_count は、現在のフリーセル数を制御するために使用される


ハッシュテーブルを再構築する(容量増加処理):

- 容量が100%になったときのみ、再構築する。
- 次の容量サイズをリストから取得します。

const static int  CPrimeGenerator::s_primes[]=
  {
   3,7,11,17,23,29,37,47,59,71,89,107,131,163,197,239,293,353,431,521,631,761,919,
   1103,1327,1597,1931,2333,2801,3371,4049,4861,5839,7013,8419,10103,12143,14591,
   17519,21023,25229,30293,36353,43627,52361,62851,75431,90523,108631,130363,156437,
   187751,225307,270371,324449,389357,467237,560689,672827,807403,968897,1162687,1395263,
   1674319,2009191,2411033,2893249,3471899,4166287,4999559,5999471,7199369
  };

- m_entries[] および m_buckets[] 配列がインクリメントされる。
- m_buckets[]がクリアされ、m_entries[]のデータ(キーに対するキャッシュされたハッシュ値-hash_code)に基づいて完全に再充填される。


2017.12.11
現在、詳細/係数を追加/変更した可能性があります。

 
Sergey Dzyublik:

私は一度、CHashMapの 仕組みを分解して説明したことがあります
多分このスレッドで、エントリーを探す必要があります。

で見つけました。

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

汎用クラスライブラリ - エラー、説明、質問、使用上の特殊性、提案

セルゲイ・デジブリク さん 2017.12.07 14:21


この例では、ハッシュは生徒の誕生日である。
365段の棚に生徒の日記を収めた食器棚があります。
日記は誕生日ごとに棚に並べています。

弟子ペトロフの日記が必要で、彼がいつ生まれたかもわかっている。
さて、O(1)の生年月日から、ペトロフの日記も、他の生徒の日記も、簡単に見つけることができる。
ただし、2人の生徒が同じ誕生日の場合は例外で、これをコリジョン(衝突)と呼びます。

衝突を解決することは、余分な情報を使って、2つ以上の雑誌のうちどれが必要かを見つけることである。
リストによるコリジョン解消は、コリジョンの全エントリーを1つずつ調べて一致するものを見つけるだけです。日記を一枚一枚はがして、誰のものかを確認する。
サブハッシュとは、衝突に関与した項目のハッシュ表を整理することですが、別の基準で整理します。例えば、生徒が生まれた時間単位で。


もしこのトピックに興味があるのなら、私はYoutubeでMailRuからアルゴリズムとデータ構造についての コースをアドバイスしています。

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

Generic クラスライブラリ - エラー、説明、質問、使用上の特殊性、提案

セルゲイ・デジブリク さん 2017.12.08 14:40

このトピックの基本は、怠け者のためのものです。
https://www.slideshare.net/mkurnosov/6-32402313

実際にはもっと複雑で、関連する文献や「アルゴリズムとデータ構造」の講座で議論されている。


ありがとうございます、デバッグが役に立ちました。コリジョン用の小さなリストがあります。スレを駆け足で見て、ゾッとした。話題になっていたことが判明...。

 
Sergey Dzyublik:
2017.12.11より 記述された動作

現時点では、細部や係数を追加・変更した場合があります。

ありがとうございました。説明文がとても役に立ちました。