Generische Klassenbibliothek - Bugs, Beschreibung, Fragen, Nutzungsmöglichkeiten und Vorschläge - Seite 14

 
Sergey Dzyublik:

Wenn ein Objekt eine Schnittstelle oder Methode nicht implementiert, ist es für mich besser, eine Ausnahme zu erzeugen, als zu schweigen und dann nach der Ursache des Problems zu suchen.

  • In MQL5 gibt es keine Schnittstellen.
  • In MQL5 gibt es keine Ausnahmen.

Und am Ende erhält man eine tolle Selbstdarstellung und eine offensichtliche Verschleierung des Problems mit dem Code.

 
Vasiliy Sokolov:

Aus demselben Grund ist der Vergleich falsch. Wie können Sie benutzerdefinierte CHashMap vergleichen und mit Systemfunktionen arbeiten, um eine Handelsumgebung zu erhalten?

Schreiben Sie weiterhin suboptimalen Code, da Sie keine stichhaltigen Argumente akzeptieren.

Forum für Handel, automatisierte Handelssysteme und Strategietests

Generische Klassenbibliothek - Bugs, Beschreibung, Probleme, Anwendungsfälle und Vorschläge

fxsaber, 2017.12.08 22:46

Für einen realistischeren Testfall (2000 Trades und 1.000.000 einzelne Zugriffe auf die Historie) sieht das Ergebnis wie folgt aus

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

Fast 100 ms Einsparung pro Durchgang! Wenn wir z. B. die Optimierung für 10.000 vollständige Durchläufe durchführen, wäre die Hash-Variante am Ende 15 Minuten schneller.

Vasiliy Sokolov:

Alles in allem handelt es sich also um einen noblen Selbstmord und eine offensichtliche Verschleierung des Problems mit dem Code.

Sie haben beide irgendeinen Unsinn geschrieben und nicht verstanden, dass HashMap in der aktuellen Form nicht für struct und union funktioniert.
 
fxsaber:

Schreiben Sie weiterhin suboptimalen Code, wenn Sie keine stichhaltigen Argumente akzeptieren.

Irgendein Unsinn, den ihr beide geschrieben habt, ohne auch nur im Geringsten zu verstehen, dass HashMap in seiner aktuellen Form nicht für struct und union funktioniert.

Lieber, wenn du etwas rauchst und nicht in der Lage bist, den Beitrag deines Gesprächspartners sorgfältig zu lesen, dann ist das dein Problem, und es sind nicht alle anderen, die behandelt werden müssen, sondern nur die kranke Person.
Ich wiederhole: Niemand hat die Frage von Struktur und Gewerkschaft aufgeworfen, niemand hat Ihre Vorstellungen zum Thema bestritten....


Es ging speziell um diese Code-Begriffe.
Aus der Standardbibliothek:

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



Und Ihre zusätzlichen:

Forum zum Thema Handel, automatisierte Handelssysteme und Strategietests

Generische Klassenbibliothek - Bugs, Beschreibung, Probleme, Anwendungsfälle und Vorschläge

fxsaber, 2017.12.08 21:17

Eine weitere Überlast hinzugefügt

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


Was Sie zu vermitteln versuchten:
Hash wird verwendet, um die Suche nach Elementen in einem Container zu beschleunigen. Die Geschwindigkeit ist O(1) - sie hängt nicht davon ab, wie viele Gegenstände dem Behälter hinzugefügt werden.
Situation: Der Benutzer verwendet seine eigene Klasse als Schlüssel.
1) Da es keine Mehrfachvererbung von Schnittstellen gibt(es gibt keine Schnittstellen in MQL5), kann der Benutzer nicht von IEqualityComparableerben;
2) Der Benutzer vergisst auch, eine explizite Spezifikation für die GetHashCode-Vorlagenfunktion anzugeben.

Die Folgen - der Benutzer wird nicht darüber informiert, dass er etwas ausgelassen hat, und der Code wird erfolgreich ausgeführt, ohne Ausnahmen zu erzeugen(es gibt keine Ausnahmen in MQL5).
Die Geschwindigkeit fällt von O(1) mit durchschnittlicher Hash-Berechnungskonstante auf O(n) mit einer im Vergleich recht großen Konstante.
Nur bei einer großen Anzahl von Elementen in einem Container und bei der zeitaufwändigen Suche nach
einem Engpass in der Implementierung könnte der Benutzer die Ursache der Probleme finden - das Fehlen einer expliziten GetHashCode-Spezifikation für seine Klasse.
Nichts für ungut, danke.

 
Aber warum all diese zweifellos coolen Dinge für den Handel?
Noch nie in meinem Leben musste ich Tausende von Geschäften aus der Historie heraussuchen, nach den Aufträgen suchen, die sie erzeugt haben, usw.
 
Sergey Dzyublik:

Sehr geehrter Herr, wenn Sie etwas rauchen und nicht in der Lage sind, den Beitrag Ihres Gesprächspartners aufmerksam zu lesen, ist das Ihr Problem, und nicht alle anderen sollten behandelt werden, sondern nur die kranke Person.

Offenbar gibt es für Abstinenzler keine Möglichkeit, den Fäustling zu schließen

#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)));
}
 
Kommentare, die für dieses Thema nicht relevant sind, wurden in den Bereich "Algorithmen, Lösungsmethoden, Vergleich ihrer Leistung" verschoben.
 

Obwohl es ursprünglich nicht als Beispielsammlung gedacht war, halte ich es dennoch für notwendig, einige Beispiele hinzuzufügen, damit diejenigen, die die Algorithmen noch nicht in ihrer Praxis verwendet haben, verstehen können, warum sie praktisch und vor allem einfach sind.

 

Beispiel 1: Assoziierung eines Laufzeitfehlers mit seiner Stringbeschreibung

Häufig ist es erforderlich, numerische Konstanten in String-Literale zu übersetzen. Es ist zum Beispiel besser, Fehlercodes mit einer klaren Beschriftung zu duplizieren, die den Fehler beschreibt. Dies ist keine sehr schwierige Aufgabe und wird in der Regel durch eine spezielle Funktion oder einen Switch-Case oder viele ifs gelöst:

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

Jede solche Lösung hat ein Recht auf Leben. Aber wir werden hier eine Lösung auf der Basis von CHashMap beschreiben und Ihnen die Vorteile aufzeigen.

Der Algorithmus könnte folgendermaßen aussehen:

  • Wir erstellen ein assoziatives Array der Art <Fehlercode - Fehlerbeschreibung>;
  • Fügen Sie mögliche Fehlercodes und deren Beschreibung in dieses Wörterbuch ein;
  • Wir wenden uns direkt und ohne Vermittler an das Wörterbuch, um die Beschreibung des Fehlers durch seinen Code zu erhalten
Dieser Code sieht wie folgt aus:

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

Sind die Fehlercodes einmal eingegeben, kann mit nur einer Zeile auf sie zugegriffen werden, ohne verschiedene Funktionen zu verwenden. Außerdem möchte ich Sie daran erinnern, dass dieser Code in einigen Fällen sogar schneller arbeitet als mehrere Dutzend ifs, da die Adressierung an den notwendigen Fehler direkt erfolgt, mit einer durchschnittlichen Geschwindigkeit von O(1).

 
Vasiliy Sokolov:

Sobald die Fehlercodes ausgefüllt sind, kann mit nur einer Zeichenkette auf sie zugegriffen werden, ohne verschiedene Funktionen zu verwenden.

ErrorToString muss trotzdem geschrieben werden. Das Argument ist also insgesamt schwach.

Außerdem möchte ich Sie daran erinnern, dass dieser Code in einigen Fällen sogar schneller arbeitet als mehrere Dutzend ifs, da die Adressierung des benötigten Fehlers direkt erfolgt, mit einer durchschnittlichen Geschwindigkeit von O(1).

Aber das ist ein offensichtlicher Vorteil.

 

Die vorgeschlagene Wörterbuchlösung hat mehrere Vorteile, von denen der wichtigste auf den ersten Blick nicht ganz offensichtlich ist. Wenn wir Code wie diesen schreiben:

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

Wir sind fest mit dem Code des Expert Advisors selbst verdrahtet. Wenn wir das Wörterbuch füllen, tun wir dies dynamisch, d.h. im Moment der Programmausführung. Der dynamische Ansatz gibt uns mehr Flexibilität. Beispielsweise können Fehlercodes in einer speziellen Datei enthalten sein, z.B. ErrorsCode.txt:

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

Zum Zeitpunkt des Starts kann das Programm diese Datei lesen und das Wörterbuch mit den erforderlichen Codes füllen und dann die gewünschte Variante der Zeichenkette an den Benutzer zurückgeben. Es kann mehrere solcher Dateien geben: eine Datei pro Sprache. Auf diese Weise kann eine Lokalisierung durchgeführt werden, bei der je nach Sprache des Benutzers Fehlercodes in der Sprache des Benutzers angezeigt werden. Außerdem kann der Benutzer selbst diese Fehlercodes einmal in seine eigene Sprache übersetzen, und das Programm "lernt" selbst, die gewünschte Meldung in seiner Sprache auszugeben. So werden die meisten Programme lokalisiert, wenn die Übersetzung eines Menüs in einer Textdatei enthalten ist und das Programm sie je nach den Einstellungen lädt. D.h. ohne Neukompilierung des Programms und ohne Änderung seines Algorithmus können wir die Darstellung seiner Ergebnisse wesentlich beeinflussen.

Grund der Beschwerde: