표준 기능/접근법의 대체 구현 - 페이지 3

 
fxsaber :
#import ex5는 최적화의 악이라는 것이 밝혀졌습니다.

글로벌 최적화 가능성의 관점에서 - 그렇습니다.

우리는 코드를 더 작게 만들지 않고 상당히 공격적인 인라인을 했습니다. 따라서 글로벌 최적화 모드에서는 매우 좋은 코드를 생성합니다.

이것은 결과 속도를 최전선에 두는 컴파일 타임에 볼 수 있습니다.

 
prostotrader :

fxsaber

코드에 오류가 있습니다.

감사합니다. 수정했습니다.
 double MyNormalizeDouble( const double Value, const uint digits )
{
   static const double Points[] = { 1.0 e- 0 , 1.0 e- 1 , 1.0 e- 2 , 1.0 e- 3 , 1.0 e- 4 , 1.0 e- 5 , 1.0 e- 6 , 1.0 e- 7 , 1.0 e- 8 };
   const double point = digits > 8 ? 1.0 e- 8 : Points[digits];

   return (( long )((Value > 0 ) ? Value / point + HALF_PLUS : Value / point - HALF_PLUS) * point);
}
 
fxsaber :
감사합니다. 수정했습니다.

여전히 오류입니다

마지막에 5가 되어야 합니다.

 
prostotrader :

여전히 오류입니다

이것은 오류가 아니라 반올림입니다. 이것이 바로 표준 버전이 하는 일입니다.
 
fxsaber :
이것은 오류가 아니라 반올림입니다. 이것이 바로 표준 버전이 하는 일입니다.
내가 잘못했어 화면을 잘못 올렸어 다시 봐 (사진 교체)
 

여기 당신을 위한 코드가 있습니다, 그것을 테스트하십시오

 //+------------------------------------------------------------------+
//|                                                         Test.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link        "https://www.mql5.com"
#property version    "1.00"
#define EPSILON ( 1.0 e- 7 + 1.0 e- 13 )
#define HALF_PLUS  ( 0.5 + EPSILON)
#property indicator_separate_window
#property indicator_plots    1
#property indicator_buffers 1
double d_value = 12345.012345 ;
//
double MyNormalizeDouble( const double Value, const uint digits )
{
   static const double Points[] = { 1.0 e- 0 , 1.0 e- 1 , 1.0 e- 2 , 1.0 e- 3 , 1.0 e- 4 , 1.0 e- 5 , 1.0 e- 6 , 1.0 e- 7 , 1.0 e- 8 };
   const double point = digits > 8 ? 1.0 e- 8 : Points[digits];

   return (( long )((Value > 0 ) ? Value / point + HALF_PLUS : Value / point - HALF_PLUS) * point);
}
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit ()
  {
//--- indicator buffers mapping
   double new_value = MyNormalizeDouble(d_value, 0 );
   new_value = NormalizeDouble (d_value, 0 );
   new_value = MyNormalizeDouble(d_value, 1 );
   new_value = NormalizeDouble (d_value, 1 );
   new_value = MyNormalizeDouble(d_value, 2 );
   new_value = NormalizeDouble (d_value, 2 );
   new_value = MyNormalizeDouble(d_value, 3 );
   new_value = NormalizeDouble (d_value, 3 );
   new_value = MyNormalizeDouble(d_value, 4 );
   new_value = NormalizeDouble (d_value, 4 );
   new_value = MyNormalizeDouble(d_value, 5 );
   new_value = NormalizeDouble (d_value, 5 );
   new_value = MyNormalizeDouble(d_value, 6 );
   new_value = NormalizeDouble (d_value, 6 );
   new_value = MyNormalizeDouble(d_value, 7 );
   new_value = NormalizeDouble (d_value, 7 );
   new_value = MyNormalizeDouble(d_value, 8 );
   new_value = NormalizeDouble (d_value, 8 );
   new_value = MyNormalizeDouble(d_value, 9 );
   new_value = NormalizeDouble (d_value, 9 );
   if (new_value == 0.0 )
   {}  
//---
   return ( INIT_SUCCEEDED );
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate ( const int rates_total,
                 const int prev_calculated,
                 const int begin,
                 const double &price[])
  {
//---
   
//--- return value of prev_calculated for next call
   return (rates_total);
  }
//+------------------------------------------------------------------+
 
prostotrader :

여기 당신을 위한 코드가 있습니다, 그것을 테스트하십시오

 void OnStart ( void )
{
   double Val = 12345.012345 ;
  
   double Val2 = Val / 1.0 e- 5 ;
  Val2 += HALF_PLUS; // Val2 == 1234501235.0
  
   long Val3 = ( long )Val2; // Val3 == 1234501234
    
   return ;
};

Val2가 맞습니다. long으로 캐스팅한 후 Val3이 올바르지 않습니다. 분명히 부동 소수점 숫자의 이중 표현의 일부 기능입니다. EPSILON을 늘릴 필요가 있습니다. 졸린 머리가 생각나지 않는다. 아는 사람이 끼어들 수도 있습니다.

개발자가 이 글을 쓴 이유 를 이해해야 합니다.

 //+------------------------------------------------------------------+
//| Сравнивает два значения типа double.                             |
//| RESULT                                                           |
//|   Возвращает истину, если значения равны и                       |
//|   ложь в противном случе.                                        |
//+------------------------------------------------------------------+
bool CEnvironment::DoubleEquals( const double a, const double b)
  {
//---
   return ( fabs (a-b)<= 16 * DBL_EPSILON * fmax ( fabs (a), fabs (b)));
//---
  }

개가 이곳에 묻힌 것 같습니다.

 
이제 항상 올바르게 작동하지만 원본보다 10%만 빠릅니다.
 double MyNormalizeDouble( const double Value, const uint digits )
{
   static const double Points[] = { 1.0 e- 0 , 1.0 e- 1 , 1.0 e- 2 , 1.0 e- 3 , 1.0 e- 4 , 1.0 e- 5 , 1.0 e- 6 , 1.0 e- 7 , 1.0 e- 8 };
   const double point = digits > 8 ? 1.0 e- 8 : Points[digits];
   const long Integer = ( long )Value; // чтобы не создавать крайне медленный относительный epsilon

   return (( long )((Value > 0 ) ? (Value - Integer) / point + HALF_PLUS : (Value - Integer) / point - HALF_PLUS) * point + Integer);
}
prostotrader , 불일치를 찾아주셔서 감사합니다!
 
fxsaber :

개가 이곳에 묻힌 것 같습니다.

RSDN 포럼에서 다리 성장

DBL_EPSILON은 숫자 1.0에 적용할 때 1(1!) 유효 지수 비트의 차이를 정의합니다. 실제로 이러한 차이는 발생하지 않습니다. 숫자가 완전히 같거나 둘 이상의 유효 비트만큼 다를 수 있습니다. 따라서 4개의 최하위 비트(또는 사용 가능한 약 16개 중 약 1.5개의 마지막 유효 십진수)의 차이를 무시하려면 16*DBL_EPSILON 과 같은 값을 취해야 합니다.

물론 숫자의 범위가 어느 정도 알려져 있고 예측 가능한 경우가 있습니다. 0...1000이라고 합시다. 이 경우 대략적인 동등성을 비교하기 위해 1000*16*DBL_EPSILON과 같은 상수를 사용할 수 있습니다. 그러나 그러한 비교는 실제로 부동 소수점의 전체 아이디어를 고정 소수점으로 바꿉니다(이유 추측).  

 

CopyTicks의 변형으로 원본보다 몇 배 더 빠른 경우도 있습니다(> 0부터).

 int MyCopyTicks( const string Symb, MqlTick & Ticks[], const uint flags = COPY_TICKS_ALL , const ulong from = 0 , const uint count = 0 )
{
   int Res = (from == 0 ) ? CopyTicks (Symb, Ticks, flags, 0 , count) : - 1 ;
  
   if (from > 0 )
  {    
     uint count2 = 1 ;
    
     MqlTick NewTicks[];    
     int Amount = CopyTicks (Symb, NewTicks, flags, 0 , count2);
    
     while ((Amount > 0 ) && (( ulong )NewTicks[ 0 ].time_msc >= from))
    {
      count2 <<= 1 ;
      
      Amount = CopyTicks (Symb, NewTicks, flags, 0 , count2);
    }

     for ( int i = 1; i < Amount; i++)
       if (( ulong )NewTicks[i].time_msc >= from)
      {
        Res = ArrayCopy (Ticks, NewTicks, 0 , i, (count == 0 ) ? 2000 : count);
        
         break ;
      }    
  }
  
   return (Res);
}