오류, 버그, 질문 - 페이지 2822

 
Nikolai Semko :

반올림만 일반 round(), ceil(), floor()를 통하지 않습니다. 그들은 또한 두 배를 반환합니다.

그리고 이를 통해 일반 작업보다 더 빠르게 작업합니다.

더 빠를 수도 있지만 잘못된 것뿐입니다.
12345.0000000000001과 같은 것을 천장에 전달하면(귀하의 예와 유사) 12346으로 끝날 수 있습니다.
 
Alexey Navoykov :
더 빠를 수도 있지만 잘못된 것뿐입니다.
12345.0000000000001과 같은 것을 천장에 전달하면(귀하의 예와 유사) 12346으로 끝날 수 있습니다.

직접 해보셨나요?
노력하다:

 Print ( ceil ( 12345.0000000000001 ));
Print (Ceil( 12345.0000000000001 ));
Print ( ceil ( 12345.000000000001 ));
Print (Ceil( 12345.000000000001 ));

산출:

 2020.08 . 10 12 : 03 : 23.856 ErrorNormalizeDouble (EURUSD,M1)         12345.0
2020.08 . 10 12 : 03 : 23.856 ErrorNormalizeDouble (EURUSD,M1)         12345
2020.08 . 10 12 : 03 : 23.856 ErrorNormalizeDouble (EURUSD,M1)         12346.0
2020.08 . 10 12 : 03 : 23.856 ErrorNormalizeDouble (EURUSD,M1)         12346
12346이어야 합니다. is ceil (" 위에서 가장 가까운 정수 값을 반환합니다 .")
첫 번째 경우에는 12345가 얻어집니다. 이중 유형 17의 유효 숫자는 18입니다.
 
Nikolai Semko :

사실, 당신은 두 배를 비교할 수 없습니다. 그냥 어려운 규칙입니다.

물론, 두 배를 서로 직접 비교할 수 있고 때로는 필요할 수도 있습니다.

예를 들어 최적화 중에 OnTick은 때때로 1조 번 호출됩니다. 행잉 리밋을 실행할지 여부를 이해하기 위해 Staff Tester는 현재 해당 심볼 가격과 리밋 가격을 비교합니다. 각 OnTick 호출 전에 스누즈마다 이 작업을 수행합니다. 저것들. 이러한 검사는 수십억 번 및 수천억 번 수행됩니다.

그리고 이것은 정규화를 통해 매번 수행됩니다. 그래서 - 이것은 아무것도 아닌 컴퓨팅 리소스 의 끔찍한 낭비입니다. 왜냐하면 가격과 보류 주문 및 기호는 사전 정규화됩니다. 따라서 서로 직접 비교할 수 있고 또 그래야 합니다.

당연하게도 MQL 맞춤형 테스터는 성능 면에서 기본 일반 테스터보다 더 나은 성과를 거두고 있습니다.

 

fxsaber
:

물론, 두 배를 서로 직접 비교할 수 있고 때로는 필요할 수도 있습니다.

예를 들어 최적화 중에 OnTick은 때때로 1조 번 호출됩니다. 행잉 리밋을 실행할지 여부를 이해하기 위해 Staff Tester는 현재 해당 심볼 가격과 리밋 가격을 비교합니다. 각 OnTick 호출 전에 스누즈마다 이 작업을 수행합니다. 저것들. 이러한 검사는 수십억 번 및 수천억 번 수행됩니다.

그리고 이것은 정규화를 통해 매번 수행됩니다. 따라서 이것은 쓸데없는 컴퓨팅 리소스 의 끔찍한 낭비입니다. 왜냐하면 가격과 보류 주문 및 기호는 사전 정규화됩니다. 따라서 서로 직접 비교할 수 있고 또 그래야 합니다.

당연하게도 MQL 맞춤형 테스터는 성능 면에서 기본 일반 테스터보다 더 나은 성과를 거두고 있습니다.

NormalizeDouble()은 매우 비싼 함수입니다. 따라서 잊어 버리는 것이 좋습니다.

다음은 NormalizeDouble()과 int를 사용한 정규화의 차이점을 보여주는 스크립트입니다.

 #define   SIZE 1000000

int Ceil ( double x) { return (x-( int )x> 0 )?( int )x+ 1 :( int )x;}
int Round( double x) { return (x> 0 )?( int )(x+ 0.5 ):( int )(x- 0.5 );}
int Floor( double x) { return (x> 0 )?( int )x:(( int )x-x> 0 )?( int )x- 1 :( int )x;}
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart ()
  {
   double a[SIZE];
   double s1= 0 ,s2= 0 , s3= 0 ;
   for ( int i= 0 ;i<SIZE;i++)  a[i]=( rand ()- 16384 )/ M_PI ;
   
   ulong t1= GetMicrosecondCount ();
   for ( int i= 0 ;i<SIZE;i++) s1+=a[i];
   t1= GetMicrosecondCount ()-t1;  
   
   ulong t2= GetMicrosecondCount ();
   for ( int i= 0 ;i<SIZE;i++) s2+= NormalizeDouble (a[i], 5 );
   t2= GetMicrosecondCount ()-t2; 
   
   ulong t3= GetMicrosecondCount ();
   for ( int i= 0 ;i<SIZE;i++) s3+=Round(a[i]* 100000 );
   s3/= 100000 ;
   t3= GetMicrosecondCount ()-t3; 
   
   Print ( "простая сумма                            - " + string (t1)+ " микросекунд, сумма = " + DoubleToString (s1, 18 ));
   Print ( "сумма с NormalizeDouble                  - " + string (t2)+ " микросекунд, сумма = " + DoubleToString (s2, 18 ));
   Print ( "сумма, нормализированная через int       - " + string (t3)+ " микросекунд, сумма = " + DoubleToString (s3, 18 ));
  }

결과:

 2020.08 . 10 12 : 55 : 30.766 TestSpeedNormalizeDouble (USDCAD,H4)    простая сумма                            - 1394 микросекунд, сумма = 626010.5038610587362201
2020.08 . 10 12 : 55 : 30.766 TestSpeedNormalizeDouble (USDCAD,H4)    сумма с NormalizeDouble                   - 5363 микросекунд, сумма = 626010. 50460 99 795727060
2020.08 . 10 12 : 55 : 30.766 TestSpeedNormalizeDouble (USDCAD,H4)    сумма, нормализированная через int        - 1733 микросекунд, сумма = 626010. 50460 99999 453873
위협 및 int를 통한 정규화는 훨씬 더 정확합니다(이는 정규화의 마지막 숫자(파란색으로 강조 표시됨) 뒤에 있는 9의 숫자로 알 수 있음).
 
Nikolai Semko :

NormalizeDouble()은 매우 비싼 함수입니다. 따라서 잊어 버리는 것이 좋습니다.

다음은 NormalizeDouble()과 int를 사용한 정규화의 차이점을 보여주는 스크립트입니다.

결과:

위협 및 int를 통한 정규화는 훨씬 더 정확합니다(이는 정규화의 마지막 숫자(파란색으로 강조 표시됨) 뒤에 있는 9의 숫자로 알 수 있음).

double이 아닌 long을 통해 요약하면 결과가 훨씬 더 인상적입니다. 왜냐하면 int를 통한 합계(총 합계의 후속 나누기를 통한 곱셈 및 반올림)는 일반적인 이중 합계보다 빠르게 계산됩니다.

 #define   SIZE 1000000

int Ceil ( double x) { return (x-( int )x> 0 )?( int )x+ 1 :( int )x;}
int Round( double x) { return (x> 0 )?( int )(x+ 0.5 ):( int )(x- 0.5 );}
int Floor( double x) { return (x> 0 )?( int )x:(( int )x-x> 0 )?( int )x- 1 :( int )x;}
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart ()
  {
   double a[SIZE];
   double s1= 0 ,s2= 0 , s3= 0 ;
   long s= 0 ;
   for ( int i= 0 ;i<SIZE;i++)  a[i]=( rand ()- 16384 )/ M_PI ;
   
   ulong t1= GetMicrosecondCount ();
   for ( int i= 0 ;i<SIZE;i++) s1+=a[i];
   t1= GetMicrosecondCount ()-t1;  
   
   ulong t2= GetMicrosecondCount ();
   for ( int i= 0 ;i<SIZE;i++) s2+= NormalizeDouble (a[i], 5 );
   t2= GetMicrosecondCount ()-t2; 
   
   ulong t3= GetMicrosecondCount ();
   for ( int i= 0 ;i<SIZE;i++) s+=Round(a[i]* 100000 );
   s3=s/ 100000.0 ;
   t3= GetMicrosecondCount ()-t3; 
   
   Print ( "простая сумма                            - " + string (t1)+ " микросекунд, сумма = " + DoubleToString (s1, 18 ));
   Print ( "сумма с NormalizeDouble                  - " + string (t2)+ " микросекунд, сумма = " + DoubleToString (s2, 18 ));
   Print ( "сумма, нормализированная через int       - " + string (t3)+ " микросекунд, сумма = " + DoubleToString (s3, 18 ));  
  }

결과:

 2020.08 . 10 13 : 15 : 58.982 TestSpeedNormalizeDouble (USDCAD,H4)    простая сумма                            - 1408 микросекунд, сумма = 460384.3207830497995019
2020.08 . 10 13 : 15 : 58.982 TestSpeedNormalizeDouble (USDCAD,H4)    сумма с NormalizeDouble                   - 6277 микросекунд, сумма = 460384.3162300114054233
2020.08 . 10 13 : 15 : 58.982 TestSpeedNormalizeDouble (USDCAD,H4)    сумма, нормализированная через int        - 964 микросекунд,  сумма = 460384.3162299999967218
 
Nikolai Semko :

double이 아닌 long을 통해 요약하면 결과가 훨씬 더 인상적입니다. 왜냐하면 int를 통한 합계(총 합계의 후속 나누기를 통한 곱셈 및 반올림)는 일반적인 이중 합계보다 빠르게 계산됩니다.

결과:

비교를 위해 Decimal 을 추가합니다.

잘못된 링크, 완전한 구현이 없습니다.

 
fxsaber :

그리고 이것은 정규화를 통해 매번 수행됩니다. 그래서 - 이것은 아무것도 아닌 컴퓨팅 리소스 의 끔찍한 낭비입니다.

이것을 어떻게 압니까? 결국 가격이 정규화되지 않은 경우에도 검사는 정규화 없이 간단하게 수행됩니다.

 if ( fabs (price-limitprice) < ticksize/ 2 )

가격이 ticksize의 배수임을 감안할 때

 
Nikolai Semko :
위협 및 int를 통한 정규화는 훨씬 더 정확합니다(이는 정규화의 마지막 숫자(파란색으로 강조 표시됨) 뒤에 있는 9의 숫자로 알 수 있음).

테스트가 잘못되었습니다. 마지막에 한 번만 100000.0으로 나누는 이유는 무엇입니까? 각 반복에서 실행한 다음 요약해야 합니다. 그러면 공정한 비교가 될 것입니다. 그래서 정규화가 없고 테스트 알고리즘을 최적화했습니다. 당연히 더 빠르고 정확할 것입니다(누적 오차가 줄어들기 때문에)

 
Alexey Navoykov :

이것을 어떻게 압니까?

비정규화된 가격을 테스터에 입력으로 제출할 수 있고 테스터와 동일하게 작동하기 때문입니다.

결국 가격이 정상화되지 않아도 정상화 없이 확인만 하고

이 경우 정규화는 단일 표준 알고리즘을 의미했으며 적용 후 이 표준의 두 배를 직접 비교할 수 있습니다.

따라서 테스터는 직접 비교하지 않습니다. 그리고 NormalizeDouble , ticksize 또는 다른 방법을 통해 이 작업을 수행합니다. 그러나 확실히 두 배의 직접적인 비교는 아닙니다. 그리고 이것은 완전히 비합리적입니다.

 
fxsaber :

물론, 두 배를 서로 직접 비교할 수 있고 때로는 필요할 수도 있습니다.

예를 들어 최적화 중에 OnTick은 때때로 1조 번 호출됩니다. 행잉 리밋을 실행할지 여부를 이해하기 위해 Staff Tester는 현재 해당 심볼 가격과 리밋 가격을 비교합니다. 각 OnTick 호출 전에 각 스누즈에 대해 이 작업을 수행합니다. 저것들. 이러한 검사는 수십억 번 및 수천억 번 수행됩니다.

그리고 이것은 정규화를 통해 매번 수행됩니다. 그래서 - 이것은 쓸데없는 컴퓨팅 자원 의 끔찍한 낭비입니다. 왜냐하면 가격 및 보류 중인 주문 및 기호는 사전 정규화됩니다. 따라서 서로 직접 비교할 수 있고 또 그래야 합니다.

당연하게도 MQL 맞춤형 테스터는 성능 면에서 기본 일반 테스터보다 더 나은 성과를 거두고 있습니다.

나는 속도를 위해 미친 버전을 확인하기로 결정했다.
그리고 결과는 놀랐습니다.
사전 정규화 된 double의 비교는 double이 epsilon을 통해 또는 int로 변환을 통해 비교되는 경우보다 평균적으로 훨씬 느립니다.

#define  SIZE 1000000

int Ceil ( double x) { return (x-( int )x> 0 )?( int )x+ 1 :( int )x;}
int Round( double x) { return (x> 0 )?( int )(x+ 0.5 ):( int )(x- 0.5 );}
int Floor( double x) { return (x> 0 )?( int )x:(( int )x-x> 0 )?( int )x- 1 :( int )x;}

bool is_equal( double d1, double d2, double e= 0.000000001 ) { return fabs (d1-d2)<e;}

void OnStart ()
  {
   double a[SIZE], a_norm[SIZE];
   int s1= 0 ,s2= 0 , s3= 0 ;
   for ( int i= 0 ;i<SIZE;i++)  {
     a[i]=( rand ()- 16384 )/ 1641.1452 ;
     a_norm[i]= NormalizeDouble (a[i], 2 );
   }
   double test = 1.11 ;
   
   ulong t1= GetMicrosecondCount ();
   for ( int i= 0 ;i<SIZE;i++) if (a_norm[i]==test) s1++;
   t1= GetMicrosecondCount ()-t1;  
   
   ulong t2= GetMicrosecondCount ();
   for ( int i= 0 ;i<SIZE;i++) if (is_equal(a[i],test, 0.005 )) s2++;
   t2= GetMicrosecondCount ()-t2; 
   
   ulong t3= GetMicrosecondCount ();
   int test_int = test* 100 ;
   for ( int i= 0 ;i<SIZE;i++) if (Round(a[i]* 100 )==test_int) s3++;
   t3= GetMicrosecondCount ()-t3; 
   
   
   Print ("простое сравнение предварительно нормализированых double - " + string (t1)+ " микросекунд, всего совпадений = "+ string (s1));
   Print ("сравнение double через эпсилон                           - " + string (t2)+ " микросекунд, всего совпадений = "+ string (s2));
   Print ("сравнение double через преобразование в int               - " + string (t3)+ " микросекунд, всего совпадений = "+ string (s3));  
  }

결과:

 2020.08 . 10 14 : 31 : 39.620 TestCompareDouble (USDCAD,H4)   простое сравнение предварительно нормализированых double - 900  микросекунд, всего совпадений = 486
2020.08 . 10 14 : 31 : 39.620 TestCompareDouble (USDCAD,H4)   сравнение double через эпсилон                           - 723  микросекунд, всего совпадений = 486
2020.08 . 10 14 : 31 : 39.620 TestCompareDouble (USDCAD,H4)   сравнение double через преобразование в int               - 805  микросекунд, всего совпадений = 486
2020.08 . 10 14 : 31 : 42.607 TestCompareDouble (USDCAD,H4)   простое сравнение предварительно нормализированых double - 1533 микросекунд, всего совпадений = 488
2020.08 . 10 14 : 31 : 42.607 TestCompareDouble (USDCAD,H4)   сравнение double через эпсилон                           - 758  микросекунд, всего совпадений = 488
2020.08 . 10 14 : 31 : 42.607 TestCompareDouble (USDCAD,H4)   сравнение double через преобразование в int               - 790  микросекунд, всего совпадений = 488
2020.08 . 10 14 : 31 : 44.638 TestCompareDouble (USDCAD,H4)   простое сравнение предварительно нормализированых double - 986  микросекунд, всего совпадений = 472
2020.08 . 10 14 : 31 : 44.638 TestCompareDouble (USDCAD,H4)   сравнение double через эпсилон                           - 722  микросекунд, всего совпадений = 472
2020.08 . 10 14 : 31 : 44.638 TestCompareDouble (USDCAD,H4)   сравнение double через преобразование в int               - 834  микросекунд, всего совпадений = 472

나는 많은 것이 프로세서의 참신함과 아키텍처에 달려 있고 누군가에게는 결과가 다를 수 있다는 점을 배제하지 않습니다.

솔직히 위협 - 왜 이런 일이 발생하는지 이해조차 되지 않습니다.
컴파일러는 난수의 합으로 최적화할 것이 없는 것 같습니다. 대괄호에서 반올림을 수행할 수 없습니다.
프로세서에서 double을 비교하는 것은 하나의 명령인 것 같습니다.
엡실론 비교 옵션(가장 빠른 옵션)을 사용하면 두 배를 비교하는 연산이 계속 발생하지만, 이 경우에는 3개의 매개변수를 전달하고 1개의 빼기 연산으로 함수를 추가로 호출합니다.
두 개의 이중 비교 연산의 성능은 실제로 변수 자체의 값에 달려 있습니까? 나는 의심한다.
젠장, 이해가 안 돼요. 도와주세요 - 내가 무엇을 고려하지 않았거나 어디에서 실수를 했습니까?