Se for para comparação, então você poderia facilmente criar sua própria função:
bool checkDoubles(double a, double b, string check)
{
if(check==">"){
if (a - b > Point / 2)return(1);elsereturn (0);
}elseif(check=="<"){
if (b - a > Point / 2)return(1);elsereturn (0);
}elseif(check==">="){
if (a - b > -Point)return(1);elsereturn (0);
}if(check=="<="){
if (b - a > -Point)return(1);elsereturn (0);
}elseif(check=="!="){
if (MathAbs(a - b) > Point / 2)return(1);elsereturn (0);
}else {
Print("Sorry you've entered a wrong check value");
}
return (0);
}
O uso de "Ponto" ou "Ponto/2.0" não é um valor de diferença muito bom, IMO. O erro roundoff introduzido por NormalizeDouble (que hoje me queimei), certamente é muito menor que 8 dígitos, mais provavelmente 15 dígitos.
Tendo em vista as dicas anteriores, e tendo feito algumas mudanças e montado a seguinte rotina que parece funcionar bem (mesmo usando a "diff" até 15 casas decimais), embora ainda não tenha sido rigorosamente testada:
//+------------------------------------------------------------------+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);elsereturn(false);}
elseif(checkStr == "<" ){if (B - A > diff)return(true);elsereturn(false);}
elseif(checkStr == ">="){if (A - B > -diff)return(true);elsereturn(false);}
elseif(checkStr == "<="){if (B - A > -diff)return(true);elsereturn(false);}
elseif(checkStr == "!="){if (MathAbs(A - B) > diff)return(true);elsereturn(false);}
elseif(checkStr == "=" || checkStr == "=="){if (MathAbs(A - B) < diff)return(true);elsereturn(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");
elseAlert("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!elseAlert("AvsB FAIL. ROUNDOFF BUG");
Aqui está mais uma possível rotina que pode comparar, mas também pode normalizar internamente tanto A e/ou B, e também irá relaxar a diferença de comparação (de A-B ou B-A) para um número maior baseado em "dígitos". Duvido que esta rotina seja necessária em comparação com a simples "AvsB" acima, mas ela é oferecida para seu uso conforme desejado:
//+------------------------------------------------------------------+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)
{
case0 : diff = 0.5; break; // Or 1.0 ??case1 : diff = 0.1; break;
case2 : diff = 0.01; break;
case3 : diff = 0.001; break;
case4 : diff = 0.0001; break;
case5 : diff = 0.00001; break;
case6 : diff = 0.000001; break;
case7 : diff = 0.0000001; break;
case8 : diff = 0.00000001; break;
case9 : diff = 0.000000001; break;
case10 : diff = 0.0000000001; break;
case11 : diff = 0.00000000001; break;
case12 : diff = 0.000000000001; break;
case13 : diff = 0.0000000000001; break;
case14 : diff = 0.00000000000001; break;
default : diff = 0.000000000000001; break; // 15 decimal places max (I think)
}
if (checkStr == ">" ){if (A - B > diff)return(true);elsereturn(false);}
elseif(checkStr == "<" ){if (B - A > diff)return(true);elsereturn(false);}
elseif(checkStr == ">="){if (A - B > -diff)return(true);elsereturn(false);}
elseif(checkStr == "<="){if (B - A > -diff)return(true);elsereturn(false);}
elseif(checkStr == "!="){if (MathAbs(A - B) > diff)return(true);elsereturn(false);}
elseif(checkStr == "=" || checkStr == "=="){if (MathAbs(A - B) < diff)return(true);elsereturn(false);}
else {Print("Sorry, bad usage: AvsB(A, checkStr, B). Wrong checkStr value: ",checkStr);}
return(false);
} // end of AvsB_nA_nB_digits//+------------------------------------------------------------------+
O uso de "Ponto" ou "Ponto/2.0" não é um valor de diferença muito bom, IMO. O erro roundoff introduzido por NormalizeDouble (que hoje me queimei), certamente é muito menor que 8 dígitos, mais provavelmente 15 dígitos.
Você quer o maior valor que não pode ser considerado erro roundoff ou equivalente, o menor valor que não pode ser considerado uma mudança de preço. Como os preços só podem mudar por um múltiplo de ponto, o ponto/2 é exatamente isso.
O valor duplo do corretor poderia ser de 1,234575000000000000 a 1,23458499999999999 e ainda ser considerado o mesmo preço de 1,23458.
Se você tivesse usado isto, não teria tido o problema:
*Põe sua gravata em posição com dois dedos* Só use normalizar o dobro nos cálculos que envolvem um valor duplo e não apenas em todos os lugares onde há um dobro.
tonny: *Põe sua gravata em posição com dois dedos* Só use normalizar o dobro nos cálculos que envolvem um valor duplo e não apenas em todos os lugares onde há um dobro.
Ou simplesmente não use NormalizeDouble() de forma alguma, na maioria das vezes quando é usado não háabsolutamente nenhuma necessidade de usá-lo . . . erro 4107 pode ser resolvido usando NormalizeDouble(), mas há outras formas. Qualquer preço que venha de variáveis pré-definidas ou funções de série temporal nunca precisará ser Normalizado, nem o resultado de um número inteiro multiplicado por Ponto.
Se for para comparação, então você poderia facilmente criar sua própria função:
É apenas um pensamento.
Se for para comparação, então você poderia facilmente criar sua própria função:
É apenas um pensamento.
É um bom pensamento, obrigado por isso :-)
O uso de "Ponto" ou "Ponto/2.0" não é um valor de diferença muito bom, IMO. O erro roundoff introduzido por NormalizeDouble (que hoje me queimei), certamente é muito menor que 8 dígitos, mais provavelmente 15 dígitos.
Tendo em vista as dicas anteriores, e tendo feito algumas mudanças e montado a seguinte rotina que parece funcionar bem (mesmo usando a "diff" até 15 casas decimais), embora ainda não tenha sido rigorosamente testada:
Here is a check of the obvious:
Aqui está mais uma possível rotina que pode comparar, mas também pode normalizar internamente tanto A e/ou B, e também irá relaxar a diferença de comparação (de A-B ou B-A) para um número maior baseado em "dígitos". Duvido que esta rotina seja necessária em comparação com a simples "AvsB" acima, mas ela é oferecida para seu uso conforme desejado:
O uso de "Ponto" ou "Ponto/2.0" não é um valor de diferença muito bom, IMO. O erro roundoff introduzido por NormalizeDouble (que hoje me queimei), certamente é muito menor que 8 dígitos, mais provavelmente 15 dígitos.
Você quer o maior valor que não pode ser considerado erro roundoff ou equivalente, o menor valor que não pode ser considerado uma mudança de preço. Como os preços só podem mudar por um múltiplo de ponto, o ponto/2 é exatamente isso.
O valor duplo do corretor poderia ser de 1,234575000000000000 a 1,23458499999999999 e ainda ser considerado o mesmo preço de 1,23458.
Se você tivesse usado isto, não teria tido o problema:
if (a > b)if (a >= b)if (a != b)devemos evitar o uso de ??
ou talvez... eu tenho uma idéia de que podemos usara função MathRound
ex . duplo x= (MathRound( 1,37883 * 100000)) / 100000 ;
para que possamos fazer funcionar
*Põe sua gravata em posição com dois dedos* Só use normalizar o dobro nos cálculos que envolvem um valor duplo e não apenas em todos os lugares onde há um dobro.
devemos evitar o uso de ??
ou talvez... eu tenho uma idéia de que podemos usar a função MathRound
ex . duplo x= (MathRound( 1,37883 * 100000)) / 100000 ;
Você ainda acaba com o dobro e ainda com a possibilidade de preço != preço
Cheguei a esta solução, que transforma as duplas em duplas, com o propósito de comparar as duplas. . .
para que . . .
nunca será verdade.