Может ли цена != цена ? - страница 2

 

Если это для сравнения, то вы можете легко создать свою собственную функцию:

bool checkDoubles(double a, double b, string check)
{
if(check==">"){
if (a - b > Point / 2)return(1);else return (0);
}else if(check=="<"){
if (b - a > Point / 2)return(1);else return (0);
}else if(check==">="){
if (a - b > -Point)return(1);else return (0);
}if(check=="<="){
if (b - a > -Point)return(1);else return (0);
}else if(check=="!="){
if (MathAbs(a - b) > Point / 2)return(1);else return (0);
}else {
Print("Sorry you've entered a wrong check value");
}
return (0);
}

Это просто мысль.

 
heelflip43:

Если это для сравнения, то вы можете легко создать свою собственную функцию:

Это просто мысль.


Это хорошая мысль, спасибо за нее :-)
 

Использование "Point" или "Point/2.0" - не очень хорошее значение разности, IMO. Ошибка округления, вносимая NormalizeDouble (на которой я сегодня обжегся), конечно, гораздо меньше, чем 8 цифр, скорее 15 цифр.

Учитывая предыдущие советы, я сделал некоторые изменения и собрал следующую процедуру, которая, кажется, работает нормально (даже используя "разницу" до 15 знаков после запятой), хотя она еще не была тщательно протестирована:

//+------------------------------------------------------------------+
bool AvsB(double A, string checkStr, double B)
{
   //checkStr = StringTrimLeft(StringTrimRight(checkStr));
   double diff = 0.000000000000001; // 15 decimal places
   //double diff = 0.000000005;
   //double diff = 0.00000001;
   if     (checkStr == ">" ){if (A - B >  diff)return(true);else return(false);}
   else if(checkStr == "<" ){if (B - A >  diff)return(true);else return(false);}
   else if(checkStr == ">="){if (A - B > -diff)return(true);else return(false);}
   else if(checkStr == "<="){if (B - A > -diff)return(true);else return(false);}
   else if(checkStr == "!="){if (MathAbs(A - B) >  diff)return(true);else return(false);}
   else if(checkStr == "=" || checkStr == "=="){if (MathAbs(A - B) <  diff)return(true);else return(false);}
   else {Print("Sorry, bad usage: AvsB(A, checkStr, B).  Wrong checkStr value: ",checkStr);}
   return(false);
} // end of AvsB
//+------------------------------------------------------------------+

Here is a check of the obvious:

   if (1.34929 == NormalizeDouble(1.34929 , 5))  Alert("MT4 Pass");
   else Alert("MT4 FAIL.  ROUNDOFF BUG");    // Yes, this is what MT4 does, a fail.

   if (AvsB(1.34929 ,"==", NormalizeDouble(1.34929 , 5)))  Alert("AvsB Pass");  // It does pass using the AvsB routine!
   else Alert("AvsB FAIL.  ROUNDOFF BUG"); 
 

Вот еще одна возможная процедура, которая может сравнивать, но также может внутренне нормализовать A и/или B, а также ослабить разницу сравнения (A-B или B-A) до большего числа, основанного на "цифрах". Я сомневаюсь, что эта процедура необходима по сравнению с простой "AvsB" выше, но она предлагается для использования по желанию:

//+------------------------------------------------------------------+
bool AvsB_nA_nB_digits(double A, string checkStr, double B, bool normalizeA, bool normalizeB, int digits)
{
   //checkStr = StringTrimLeft(StringTrimRight(checkStr));
   if (normalizeA) A = NormalizeDouble(A,MathMin(8,digits));
   if (normalizeB) B = NormalizeDouble(B,MathMin(8,digits));
   
   double diff;
   switch(digits)
   {
      case 0  : diff = 0.5; break; // Or 1.0 ??
      case 1  : diff = 0.1; break;
      case 2  : diff = 0.01; break;
      case 3  : diff = 0.001; break;
      case 4  : diff = 0.0001; break;
      case 5  : diff = 0.00001; break;
      case 6  : diff = 0.000001; break;
      case 7  : diff = 0.0000001; break;
      case 8  : diff = 0.00000001; break;
      case 9  : diff = 0.000000001; break;
      case 10 : diff = 0.0000000001; break;
      case 11 : diff = 0.00000000001; break;
      case 12 : diff = 0.000000000001; break;
      case 13 : diff = 0.0000000000001; break;
      case 14 : diff = 0.00000000000001; break;
      default : diff = 0.000000000000001; break; // 15 decimal places max (I think)
   }
   
   if     (checkStr == ">" ){if (A - B >  diff)return(true);else return(false);}
   else if(checkStr == "<" ){if (B - A >  diff)return(true);else return(false);}
   else if(checkStr == ">="){if (A - B > -diff)return(true);else return(false);}
   else if(checkStr == "<="){if (B - A > -diff)return(true);else return(false);}
   else if(checkStr == "!="){if (MathAbs(A - B) >  diff)return(true);else return(false);}
   else if(checkStr == "=" || checkStr == "=="){if (MathAbs(A - B) <  diff)return(true);else return(false);}
   else {Print("Sorry, bad usage: AvsB(A, checkStr, B).  Wrong checkStr value: ",checkStr);}
   return(false);
} // end of AvsB_nA_nB_digits
//+------------------------------------------------------------------+
 
pips4life:

Использование "Point" или "Point/2.0" - не очень хорошее значение разности, IMO. Ошибка округления, вносимая NormalizeDouble (на которой я сегодня обжегся), конечно, намного меньше, чем 8 цифр, скорее 15 цифр.

Вам нужно самое большое значение, которое не может считаться ошибкой округления, или, эквивалентно, самое маленькое значение, которое не может считаться изменением цены. Поскольку цены могут изменяться только на величину, кратную пункту, пункт/2 как раз и является таким значением.

Двойное значение от брокера может быть любым от 1,2345750000000000 до 1,234584999999999 и все равно будет считаться той же ценой 1,23458.

Если бы вы использовали это, у вас не было бы проблемы:

if (a > b)
if (a - b > Point / 2.)
if (a >= b)
if (a - b > -Point/2.)
if (a != b)
if (MathAbs(a - b) > Point / 2.)
 

следует ли нам избегать использования normalisedouble?

или может быть... у меня есть мысль, что мы можем использоватьфункцию MathRound

например, double x= (MathRound( 1.37883 * 100000)) / 100000 ;

Таким образом, мы можем сделать функцию

double round ( double value )

{ int D= MathPow(10,Digits);

double x =  ( MathRound (value * D)) / D ;

return(x);

} 
 
*Используйте normalize double только в вычислениях с двойным значением, а не везде, где есть двойное значение.
 
tonny:
*Только используйте normalize double в вычислениях с двойным значением, а не везде, где есть double.
Или просто не используйте NormalizeDouble() вообще, в большинстве случаев, когда она используется, нетабсолютно никакой необходимости в ее использовании ... ошибка 4107 может быть устранена с помощью NormalizeDouble(), но есть и другие способы. Любая цена, полученная из предопределенных переменных или функций временных рядов, никогда не будет нуждаться в нормализации, как и результат умножения целого числа на Point.
 
WDholic:

следует ли нам избегать использования normalisedouble?

или может быть... у меня есть мысль, что мы можем использовать функцию MathRound

например, double x= (MathRound( 1.37883 * 100000)) / 100000 ;


В итоге вы все равно получите двойное число и все еще возможность того, что цена != цена.

Я пришел к такому решению, которое превращает двойные числа в инты для сравнения двойных чисел. . .

int Flat(double ValueToFlatten)
   {
   double Power = MathPow(10, Digits);
   int ReturnValue;
   
   ReturnValue = MathRound(Power * (ValueToFlatten + (4.9/ (Power*10) ) ) ) ;
   return (ReturnValue);
   
   }

так что ...

Flat(price) != Flat(price)

никогда не будет верным.

 
Много вычислений вместо простого решения