通用类库 - 错误、说明、问题、使用功能和建议 - 页 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

每个通道几乎节省100毫秒!如果说,我们对10,000个完整的通行证进行优化,那么Hash变量最终会快15分钟。

瓦西里-索科洛夫

总而言之,是的,这是一个高尚的自查和明显隐瞒问题的代码。

他们都写了一些废话,不明白目前形式的HashMap对struct和union不起作用。
 
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:将一个运行时错误 与它的字符串描述联系起来

很多时候,有必要将数字常数翻译成字符串字面。例如,最好将错误代码与描述错误的明确标题重复。这并不是一项非常困难的任务,它通常由一个特殊的函数或开关盒或许多ifs来解决。

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

任何这样的解决方案都是有生命权的。但我们将在这里描述一个基于CHashMap的解决方案,并向你展示其优势。

该算法可能看起来像这样。

  • 我们创建一个<bug代码-bug描述> 类型的关联数组。
  • 将可能的错误代码和它们的描述添加到这个字典中。
  • 我们直接地、没有中间人地处理字典,通过它的代码获得错误的描述
这段代码看起来如下。

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

一旦填写了错误代码,只需用一行就可以访问它们,无需使用不同的函数。此外,让我提醒你,在某些情况下,这段代码的工作速度甚至比几十个ifs还要快,因为对必要错误的寻址直接发生,平均速度为O(1)。

 
瓦西里-索科洛夫

一旦错误代码被填充,就可以只用一个字符串来访问它们,而不用使用不同的函数。

无论如何,ErrorToString都必须被写入。所以这个论点,作为一个加分项,是很弱的。

此外,让我提醒你,在某些情况下,这段代码的工作速度甚至比几十个ifs还要快,因为对所需错误的寻址直接发生,平均速度为O(1)。

但这是一个明显的优点。

 

所提出的字典解决方案有几个优点,其中最重要的一点乍一看并不完全明显。当我们写这样的代码时。

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

我们是在专家顾问代码本身中硬连接的。当我们填充字典时,我们是动态地 进行的,即在程序执行的 时刻。动态方法给了我们更多的灵活性。例如,错误代码可以包含在一个特殊的文件中,例如ErrorsCode.txt。

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

在启动的那一刻,程序可以读取这个文件并在字典中填入所需的代码,然后将所需的变体字符串返回给用户。可以有几个这样的文件:每种语言一个文件。通过这种方式,可以进行本地化,根据用户的语言,显示用户语言的错误代码。此外,用户自己可以将这些错误代码翻译成自己的语言一次,而程序本身也会 "学习 "用自己的语言输出所需的信息。大多数程序都是这样进行本地化的,当时菜单的翻译包含在一个文本文件中,程序根据设置加载它。也就是说,在不重新编译程序和不改变其算法的情况下,我们可以大大影响其结果的呈现。