일반 클래스 라이브러리 - 버그, 설명, 질문, 사용 기능 및 제안 사항 - 페이지 19

 
바실리 소콜로프 :
결국, 클래스에 대한 함수의 고유한 전문화를 작성할 수 있습니다.
 
결합기 :
결국, 클래스에 대한 함수의 고유한 전문화를 작성할 수 있습니다.

인터페이스 없이는 할 수 없습니다.

 
바실리 소콜로프 :

인터페이스 없이는 할 수 없습니다.

인터페이스 없이 불가능한 것은 무엇입니까? )
 
결합기 :
인터페이스 없이 불가능한 것은 무엇입니까? )

글쎄, 당신은 생각합니다. 요컨대, 지점 pliz를 버리지 마십시오.

 
바실리 소콜로프 :

문제

분명히 GetHashCode는 MQL5 사용자 환경에서 제대로 구현될 수 없습니다. 모든 개체에 액세스할 수 있는 것은 아니기 때문입니다. 그리고 double int 등과 같은 기본 멤버의 경우 구현이 제대로 작동하면 복잡한 객체(클래스, 구조 및 열거형)의 경우 해시가 이름으로 계산됩니다. 분명히 CObject 또는 ENUM _something_re 유형의 개체가 천 개라면 CHashMap과 CHashSet 모두 일반 LinkedList로 퇴화합니다.

사용자 수준에서 우리가 가지고 있는 것은 객체의 이름뿐이기 때문에 이것을 피할 수 있는 방법은 없습니다:

따라서 복합 유형 의 모든 개체 해시는 서로 동일하며 이 검색 코드는 전체 배열 검색을 사용합니다.

사실, 이것은 매우 중요하여 새싹에서 전체 Generic을 사용하는 요점을 지웁니다. 사실은 대부분의 경우 열거형, 구조 또는 클래스와 같은 복잡한 개체의 연결 또는 저장이 필요하다는 것입니다. 간단한 유형만 조작해야 하는 경우 더 간단한 작업을 수행할 수 있습니다.

일반 컬렉션이 클래스 개체와 올바르게 작동하려면 이러한 클래스가 Equals 및 HashCode 메서드를 정의하는 IEqualityComparable 인터페이스를 구현해야 합니다. 저것들. 사용자 자신이 해시 코드 계산 방법을 설정해야 하며, MQL5 도구를 사용하여 예를 들어 .Net에서와 같이 이러한 방법을 자동으로 구현하는 것이 불가능하기 때문에 이것이 지금까지 유일한 옵션입니다.

 
로만 코노펠코 :

일반 컬렉션이 클래스 개체와 올바르게 작동하려면 이러한 클래스가 Equals 및 HashCode 메서드를 정의하는 IEqualityComparable 인터페이스를 구현해야 합니다. 저것들. 사용자 자신이 해시 코드 계산 방법을 설정해야 하며, MQL5 도구를 사용하여 예를 들어 .Net에서와 같이 이러한 방법을 자동으로 구현하는 것이 불가능하기 때문에 이것이 지금까지 유일한 옵션입니다.

Roman, 당신 은 MQL5에 인터페이스가 없다는 것을 잊었습니다. 오늘날 MQL5의 인터페이스에 대한 모든 이야기는 악의적인 암시선동 입니다.

ps 그러나 MQL5에 인터페이스가 등장하더라도 구조 및 열거 문제는 해결되지 않은 채로 남아 있습니다.

 
바실리 소콜로프 :

Roman, 당신 은 MQL5에 인터페이스가 없다는 것을 잊었습니다. 오늘날 MQL5의 인터페이스에 대한 모든 이야기는 악의적인 암시선동 입니다.

ps 그러나 MQL5에 인터페이스가 등장하더라도 구조 및 열거 문제는 해결되지 않은 채로 남아 있습니다.

현재 MQL5에서는 데이터 전송의 특성으로 인해 클래스, 구조 및 열거에 대해 동시에 작동하는 템플릿 메서드를 작성하는 것이 원칙적으로 불가능합니다.
 
로만 코노펠코 :
현재 MQL5에서는 데이터 전송의 특성으로 인해 클래스, 구조 및 열거에 대해 동시에 작동하는 템플릿 메서드를 작성하는 것이 원칙적으로 불가능합니다.

그것이 무엇인지에 관한 것입니다. 그러나 MQL5 환경은 개체에 대한 모든 것을 알고 있습니다! 또한 개체 포인터를 소유하고 모든 열거형 식별자(EnumToString)를 알고 있습니다. 이것이 GetHashCode가 시스템 및 잡식 기능으로 필요한 이유입니다.

마지막으로 인터페이스의 다중 상속을 허용합니다. 일반 인터페이스에 대해 Generic을 다시 작성하면 사탕이 생깁니다.

 

상황은 분명합니다. MQ 개발자는 C ++에서 다중 상속으로 인해 화상을 입는 경우가 너무 많아서 이제 그 어떤 표현도 두려워합니다. 결과적으로 다른 쓰레기를 사용하여 하나의 쓰레기(다중 상속)를 피하는 것이 제안됩니다. 터무니없는 상속 체인입니다.

인터페이스는 상속과 아무 관련이 없음을 이해하게 될 것입니다. 인터페이스는 주어진 기능을 제공하기 위해 클래스가 수행하는 선언입니다. 두 클래스가 동일한 기능을 구현하는 경우 서로 상속하지 않아야 합니다. 상속 = 악 .

 

거래, 자동 거래 시스템 및 거래 전략 테스트에 관한 포럼

일반 클래스 라이브러리 - 버그, 설명, 질문, 사용법 및 제안

로만 코노펠코 , 2017.12.18 16:29

1) 볼륨 성장 계수(용량)가 1.2와 같지 않은 경우 CHashMap에서 새 볼륨을 계산하기 위해 CPrimeGenerator::ExpandPrime 메서드가 사용됩니다.

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

이 방법에서는 컬렉션의 이전 크기에 2를 곱한 다음 결과 값에 대해 위에서 가장 가까운 소수를 찾아 새 볼륨으로 반환합니다.

용량의 초기 값에 대해 - 동의합니다. 매우 작습니다.

그러나 반면에 초기 볼륨을 명시적으로 지정할 수 있는 생성자가 항상 있습니다.

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

따라서 여기서 무언가를 변경하는 것은 별로 의미가 없습니다.


네, 제가 잘못했습니다. 죄송합니다.
실제로 CHashMap의 볼륨 증가율(용량)은 2보다 큽니다.
오류 지적해주셔서 감사하고 시간낭비해서 죄송합니다.



반면에 CPrimeGenerator의 구현을 연구하는 데 시간을 할애했습니다.

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


그리고 주로 성능 향상을 위한 몇 가지 제안이 있습니다.


1. 명확한 행동:
"INT_MAX - 10"을 매개변수로 CPrimeGenerator::ExpandPrime에 전달하면 "INT_MAX" 결과가 반환됩니다.
"INT_MAX - 10"을 매개변수로 CPrimeGenerator::GetPrime에 전달하면 "INT_MAX - 10"과 같은 결과가 반환됩니다.

또한 두 경우 모두 반환된 값은 사용자를 오도하는 소수가 아닙니다.



2. 7199369 보다 큰 숫자에 대해 GetPrime 를 호출할 때 메모리 절약이 우선 순위가 되지만 이것이 상대적으로 성능이 좋지 않고 쓸모 없는 계산을 정당화하지 않습니다.

제공:
- CPrimeGenerator::s_primes[] 배열의 마지막 값과 숫자의 비교를 추가하고 모든 72개의 배열 요소에 대해 불필요한 열거를 수행하지 마십시오.
- 소수에 대한 동적 검색을 CPrimeGenerator::s_primes[] 와 같은 사전 정의된 값 배열로 교체합니다(행의 모든 숫자를 통과함). 그러나 2차 증가가 아니라 선형 증가로 .
값의 증가는 약 100만 개입니다(이 수치는 배열의 마지막 요소에서 s_primes의 증가와 유사함).
최대 3000개의 요소 수, 8M에서 INT_MAX 범위의 값.
배열 검색은 상한 이진 검색을 통해 수행되며 필요한 반복 횟수는 12입니다.


3. 7199369 보다 작은 숫자에 대해 GetPrime 을 호출할 때 최악의 경우 CPrimeGenerator::s_primes[] 배열의 72개 값 모두의 선형 열거가 수행됩니다.

제공:
- 배열의 요소 수를 70개로 줄입니다. (처음 두 개 또는 처음과 마지막을 제거):

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

- 입력 값이 새 배열 CPrimeGenerator::s_primes 의 6번째 값보다 작거나 같으면 숫자를 선형으로 정렬합니다(최대 6개 비교).
- 그렇지 않으면 배열의 7번째 값과 70번째 값 사이의 상한 이진 검색을 사용합니다(약 6회 반복).

아이디어는 이진 검색에 비해 성능 저하가 없는 한 선형 반복을 사용하는 것입니다.
제안된 요소 수 - 6이 예로 사용되며 실제로는 모두 상한 이진 검색의 특정 구현에 따라 다릅니다.
특정 함수를 호출하는 강도가 낮기 때문에 전체 성능이 향상되는 것은 이 기능을 개선하기 위한 작업을 수행하는 데 그다지 도움이 되지 않을 수 있습니다.