标准功能/方法的其他实现方式 - 页 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--正确。转换为长线后的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(一个!)有效位的差异。在实践中,没有这样的区别--数字要么严格相等,要么可以相差一个以上的有效位。因此,你必须采取类似16*DBL_EPSILON 的方法来忽略4个最小有效位的差异(或大约16个可用的最后有效十进制数字中的一个半)。

当然,有些情况下,数字的范围或多或少是已知和可预测的。比如,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);
}