Genel sınıflar kütüphanesi - hatalar, açıklamalar, sorular, kullanım özellikleri ve öneriler - sayfa 19

 
Vasili Sokolov :
Sonuçta, bir sınıf için kendi uzmanlığınızı yazabilirsiniz.
 
birleştirici :
Sonuçta, bir sınıf için kendi uzmanlığınızı yazabilirsiniz.

Arayüz olmadan yapamazsınız.

 
Vasili Sokolov :

Arayüz olmadan yapamazsınız.

Arayüz olmadan imkansız olan nedir? )
 
birleştirici :
Arayüz olmadan imkansız olan nedir? )

Peki, düşünüyorsun. Kısacası dal plizini çöpe atmayın.

 
Vasili Sokolov :

Sorun

Açıkçası, GetHashCode, MQL5 kullanıcı ortamında düzgün bir şekilde uygulanamaz. Bunun nedeni, tüm nesnelere erişilememesidir. Ve eğer double int, vb. Gibi ilkel üyelerde ise. uygulama iyi çalışıyor, daha sonra karmaşık nesneler (sınıflar, yapılar ve hatta numaralandırmalar) için karma ada göre hesaplanır. Açıkçası, CObject türünde veya hatta ENUM _something_there türünde bin nesnemiz varsa, o zaman hem CHashMap hem de CHashSet normal bir LinkedList'e dönüşür:

Bundan kaçınmanın bir yolu yok, çünkü kullanıcı düzeyinde sahip olduğumuz tek şey nesnenin adı:

Bu nedenle, karmaşık türlerdeki tüm nesnelerin karma değerleri birbirine eşittir ve bu arama kodu tam bir dizi araması kullanır:

Aslında, bu o kadar kritik ki, tüm Jenerik'i tomurcukta kullanma noktasını aşıyor. Gerçek şu ki, çoğu durumda karmaşık nesnelerin ilişkilendirilmesi veya depolanması gerekir: numaralandırmalar, yapılar veya sınıflar. Yalnızca basit tiplerin çalıştırılması gerekseydi, daha basit bir şey yapılabilirdi.

Genel koleksiyonların sınıf nesneleriyle doğru şekilde çalışması için bu sınıfların Equals ve HashCode yöntemlerini tanımlayan IEqualityComparable arabirimini uygulaması gerekir. Onlar. kullanıcının hash kodlarını hesaplamak için yöntemler belirlemesi gerekir ve bu, örneğin .Net'te olduğu gibi, MQL5 araçlarını kullanarak bu yöntemleri otomatik olarak uygulamak imkansız olduğundan, şimdiye kadarki tek seçenek budur.

 
Roman Konopelko :

Genel koleksiyonların sınıf nesneleriyle doğru şekilde çalışması için bu sınıfların Equals ve HashCode yöntemlerini tanımlayan IEqualityComparable arabirimini uygulaması gerekir. Onlar. kullanıcının hash kodlarını hesaplamak için yöntemler belirlemesi gerekir ve bu, örneğin .Net'te olduğu gibi, MQL5 araçlarını kullanarak bu yöntemleri otomatik olarak uygulamak imkansız olduğundan, şimdiye kadarki tek seçenek budur.

Roman, MQL5'te arayüz olmadığını söylemeyi unuttun. Günümüzün MQL5'inde arayüzler hakkında herhangi bir konuşma kötü niyetli ima ve demagojidir .

ps Ancak arabirimler MQL5'te görünse bile, yapılar ve numaralandırmalarla ilgili sorun çözülmeden kalacaktır.

 
Vasili Sokolov :

Roman, MQL5'te arayüz olmadığını söylemeyi unuttun. Günümüzün MQL5'inde arayüzler hakkında herhangi bir konuşma kötü niyetli ima ve demagojidir .

ps Ancak arabirimler MQL5'te görünse bile, yapılar ve numaralandırmalarla ilgili sorun çözülmeden kalacaktır.

MQL5'te, veri aktarımının özelliklerinden dolayı sınıflar, yapılar ve numaralandırmalar için aynı anda çalışacak şablon yöntemleri yazmak prensipte şu anda imkansızdır.
 
Roman Konopelko :
MQL5'te, veri aktarımının özelliklerinden dolayı sınıflar, yapılar ve numaralandırmalar için aynı anda çalışacak şablon yöntemleri yazmak prensipte şu anda imkansızdır.

Bununla ilgili. Ancak MQL5 ortamı, nesneleri hakkında her şeyi bilir! Ayrıca nesne işaretçilerine sahiptir ve tüm numaralandırma tanımlayıcılarını (EnumToString) bilir. Bu nedenle GetHashCode bir sistem ve omnivor bir fonksiyon olarak gereklidir.

Son olarak, arabirimlerin çoklu mirasına izin verin. Normal arayüzler için Generic'i yeniden yazın ve bir şeker olacak.

 

Durum açıktır: MQ geliştiricileri, C++'da çoklu kalıtım tarafından o kadar sık yakılmıştır ki, artık tezahürlerinden herhangi birinden korkmaktadırlar. Sonuç olarak, başka bir çöp: gülünç miras zincirleri kullanılarak bir çöpten (çoklu kalıtım) kaçınılması önerilir.

Arayüzlerin kalıtımla ilgisi olmadığını anlayacaksınız. Arayüz, bir sınıfın belirli bir işlevi sağlamayı taahhüt ettiği bir beyandır. İki sınıf aynı işlevi uygularsa, birbirlerinden miras almamalıdırlar. Miras = kötülük .

 

Ticaret, otomatik ticaret sistemleri ve ticaret stratejilerinin test edilmesi hakkında forum

Genel sınıf kitaplığı - hatalar, açıklama, sorular, kullanım ve öneriler

Roman Konopelko , 2017.12.18 16:29

1) Hacim büyüme katsayısı (kapasite) 1.2'ye eşit değildir, CHashMap'te yeni hacmi hesaplamak için CPrimeGenerator::ExpandPrime yöntemi kullanılır:

 int CPrimeGenerator::ExpandPrime( const int old_size)
  {
   int new_size= 2 *old_size;
   if (( uint )new_size> INT_MAX && INT_MAX >old_size)
       return INT_MAX ;
   else
       return GetPrime(new_size);
  }

Bu yöntemde, koleksiyonun eski boyutu iki ile çarpılır, ardından ortaya çıkan değer için üstten en yakın asal sayıyı bulup yeni hacim olarak döndürürüz.

Kapasitenin başlangıç değeri hakkında - Katılıyorum, çok küçük.

Ancak diğer yandan, başlangıç hacmini açıkça belirtebileceğiniz yapıcılar her zaman vardır:

 class CHashMap: public IMap<TKey,TValue>
  {
public :
                     CHashMap( const int capacity );
                     CHashMap( const int capacity ,IEqualityComparer<TKey>*comparer);
  }

Bu nedenle, burada bir şeyi değiştirmenin pek bir anlamı görmüyorum.


Evet, yanılmışım, üzgünüm.
Gerçekten de, CHashMap için hacim büyüme faktörü (kapasite) 2'den büyüktür.
Hatayı belirttiğiniz için teşekkürler ve zamanınızı boşa harcadığım için özür dilerim.



Öte yandan, CPrimeGenerator uygulamasını incelemek için zaman ayırmayı başardım.

 //+------------------------------------------------------------------+
//| Fast generator of parime value.                                  |
//+------------------------------------------------------------------+
int CPrimeGenerator::GetPrime( const int min)
  {
//--- a typical resize algorithm would pick the smallest prime number in this array
//--- that is larger than twice the previous capacity. 
//--- get next prime value from table
   for ( int i= 0 ; i< ArraySize (s_primes); i++)
     {
       int prime=s_primes[i];
       if (prime>=min)
         return (prime);
     }
//--- outside of our predefined table
   for ( int i=(min| 1 ); i< INT_MAX ;i+= 2 )
     {
       if (IsPrime(i) && ((i- 1 )%s_hash_prime!= 0 ))
         return (i);
     }
   return (min);
  }


Ve esas olarak performansı artırmak için birkaç öneri var.


1. Belirsizliği giderme davranışı:
CPrimeGenerator::ExpandPrime'a parametre olarak "INT_MAX - 10" iletmek, "INT_MAX" sonucunu döndürür.
CPrimeGenerator::GetPrime'a parametre olarak "INT_MAX - 10" iletmek aynı sonucu döndürür: "INT_MAX - 10".

Ayrıca her iki durumda da döndürülen değerin asal sayı olmaması kullanıcıyı yanıltır.



2. 7199369'dan büyük numaralar için GetPrime çağrılırken , bellek tasarrufu bir öncelik haline gelir, ancak bu, göreceli olarak düşük performansı ve işe yaramaz hesaplamaları haklı çıkarmaz.

Sunulan:
- CPrimeGenerator::s_primes[] dizisinin son değeriyle sayının bir karşılaştırmasını ekleyin ve 72 dizi öğesinin gereksiz bir numaralandırmasını gerçekleştirmeyin.
- bir asal sayı için dinamik aramayı (bir satırdaki tüm sayılardan geçer) CPrimeGenerator::s_primes[] gibi bir dizi önceden tanımlanmış değerle değiştirin, ancak ikinci dereceden bir artışla değil, doğrusal olanla .
Değerlerdeki artış yaklaşık 1 milyon olacaktır (rakam dizinin son elemanlarındaki s_primes artışına benzer).
3000'e kadar eleman sayısı, 8M ile INT_MAX aralığında değerler.
Dizi araması üst sınır ikili arama yoluyla gerçekleştirilecektir, gerekli yineleme sayısı 12'dir.


3. GetPrime'ı 7199369'dan küçük sayılar için çağırırken , en kötü durumda, CPrimeGenerator::s_primes[] dizisinin 72 değerinin tümünün doğrusal bir numaralandırması gerçekleştirilir.

Sunulan:
- dizideki eleman sayısını 70 adete düşürün. (ilk ikisini veya ilk ve sonuncuyu kaldırarak):

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

- giriş değeri yeni CPrimeGenerator::s_primes dizisindeki 6. değerden küçük veya ona eşitse - o zaman sayıları doğrusal olarak sıralayın (6 karşılaştırmaya kadar).
- aksi takdirde dizinin 7. ve 70. değerleri arasında üst sınır ikili aramayı kullanın (yaklaşık 6 yineleme).

Buradaki fikir, ikili aramaya kıyasla performans cezası olmadığı sürece doğrusal yineleme kullanmaktır.
Önerilen eleman sayısı - 6 örnek olarak kullanılmıştır, gerçekte hepsi üst sınır ikili aramanın özel uygulamasına bağlıdır.
Belirli bir işlevi çağırmanın düşük yoğunluğundan kaynaklanan genel performans kazancı, bu işlevi geliştirmek için herhangi bir çalışma yapacak kadar faydalı olmayabilir.