Características del lenguaje mql5, sutilezas y técnicas - página 146

 
fxsaber:

Estaba cerrado desde el primer puesto. Cuando el número mínimo se multiplica por algo menos que uno, se obtiene el cero.

¿cómo sería el código correcto?

// Неправильно написанная функция.
double WrongFunc( const double Num )
{
  return(Num ? 1 / (0.1 * Num) : 0);
}
 
Igor Makanu:

¿Cómo será el código correcto?

 
fxsaber:
void OnStart()
{
  double d = DBL_MIN - DBL_MIN/10.0;
  Print(WrongFunc(d));
}
//_______________________________________________________________________
double WrongFunc( const double Num )
{
  return(0.1 * Num ? 1 / (0.1 * Num) : 0);
}

compilación: expresión no booleana

resultado: inf



no es una buena opción para mí

 
No hay ningún problema
bool IsNull( const double Num )
{
  return(MathAbs(Num) < DBL_MIN);
}

double WrongFunc( const double Num )
{
  return(!IsNull(0.1 * Num) ? 1 / (0.1 * Num) : 0);
}


Yo no lo hago.


Para los estetas, se puede crear una estructura DOBLE con los operadores adecuados. Pero esto tiene poco que ver con la práctica. En el ejemplo práctico original.

ForUM sobre el comercio, los sistemas de comercio automatizados y la comprobación de estrategias

Características del lenguaje mql5, complejidades y técnicas

fxsaber, 2019.10.28 07:24

Que manera de quedar atrapado en la división por cero, incluso con un cheque.
void OnStart()
{  
  const double Profit = 100;
  const double Lots = 1;

  double TickValue[];  
  ArrayResize(TickValue, 1);
  
  const double Points = TickValue[0] ? Profit / (Lots * TickValue[0] * _Point) : 0; // zero divide    
}


De hecho, el error es comprensible. Pero al escribir un código como éste, no siempre es obvio que esa comprobación no es suficiente para evitar la división por cero.


Sólo hay que poner a cero el elemento del array que se está creando. La ausencia de inicialización es lo que provoca las colisiones en este caso. Por eso simplemente hice la puesta a cero en mi código. No quiero molestar con la visión general.

 
Igor Makanu:

compilación: expresión no booleana

resultado: inf



no es una buena opción para mí

Hay algo malo en ti.

#define  DBL_MIN_DENORM  4.94066 e-324
   Print(DBL_MAX*1.1); // inf
   Print(DBL_MIN_DENORM*0.5); // 0

Es más confuso por qué dividir por cero da una excepción de fpu, al menos para mí.

 
Vict:

Algo te está llevando por el camino equivocado.

void OnStart()
{
  double Num=0.0;
  if(0.1 * Num){} // expression not boolean     
}

fxsaber:
No hay problema.

bool IsNull( const double Num )
{
  return(MathAbs(Num) < DBL_MIN);
}

void OnStart()
{
  union ULongTODouble {
      ulong ul;
      double d;
   } ULongDouble;

   ulong nan = 18446744073708624091;
   ULongDouble.ul = nan;
   double tst = DBL_MIN - DBL_MIN/10000.0;
   Print(tst," --> ",IsNull(tst));
   tst = ULongDouble.d;
   Print(tst," --> ",IsNull(tst));
}
//_______________________________________________________________________

bool IsNull( const double Num )
{
  return(MathAbs(Num) < DBL_MIN || Num!=Num);
}

2019.10.28 20:45:47.010 tst1 (EURUSD,H4) 2.224851351121351e-308 --> true

2019.10.28 20:45:47.010 tst1 (EURUSD,H4) -nan --> true

UPD:

comprobar si hay inf

void OnStart()
{
   double dev = 1.0 / 4.940656458412465 e-324;
   Print("1. dev = ", dev, " ---> ", dev != dev);
   Print("2. dev = ", dev, " ---> ", IsInf(dev));
   dev = 1.0 / dev;

}
//+------------------------------------------------------------------+
bool IsInf(const double Num)
{
   return (Num > DBL_MAX || Num < DBL_MIN);
}
//+------------------------------------------------------------------+

2019.10.28 22:04:00.163 tst1 (EURUSD,H4) 1. dev = inf ---> false

2019.10.28 22:04:00.163 tst1 (EURUSD,H4) 2. dev = inf ---> true


es decir, como se esperaba inf no es NaN
 
fxsaber:
No hay ningún problema.
bool IsNull( const double Num )
{
  return(MathAbs(Num) < DBL_MIN);
}

Busqué en Google "C++ double zero divide", tu código no funcionará para números no normalizados, necesitas esto:

bool IsZerro(const double value)
{
   return(fabs(value) * DBL_EPSILON == 0.0);
}


guión de meditación ))))

void OnStart()
{
   union ULongTODouble {
      ulong ulong_;
      double double_;
   } ULongDouble;
   ulong i = 0;
   ulong count_NaN = 0;
   ulong count_Zerro = 0;
   double last_double = 0.0;
   while(i < ULONG_MAX) {
      ULongDouble.ulong_ = i;
      double double_result = ULongDouble.double_;
      if(IsNaN(double_result)) count_NaN++;
      else {
         if(IsZerro(double_result)) {
            count_Zerro++;
            last_double = double_result;
         }
      }
      if(i % 1000000000 == 0) Print("i = ", i, " , NaN = ", count_NaN, " , Zerro = ", count_Zerro, " , last_double = ", last_double);
      i++;
   }
   Print("NaN = ", count_NaN);
   Print("Zerro = ", count_Zerro);
}
//+------------------------------------------------------------------+
bool IsZerro(const double value)
{
   return(fabs(value) * DBL_EPSILON == 0.0);
}
//+------------------------------------------------------------------+
bool IsNaN(const double value)
{
   return(value != value);
}
//+------------------------------------------------------------------+
bool IsInf(const double value)
{
   return (value > DBL_MAX || value < DBL_MIN);
}
//+------------------------------------------------------------------+
bool IsEqual(const double value1, const double value2)
{
   return(fabs(value1 - value2) <= DBL_EPSILON);
}
//+------------------------------------------------------------------+
 

Un tema interesante. Encontré algo aquí. Cabe destacar el bloque de teoría.

 abs(u - v)/abs(u) <= epsilon
&& abs(u - v)/abs(v) <= epsilon; // (4)
   abs(u - v)/abs(u) <= epsilon
|| abs(u - v)/abs(v) <= epsilon; // (5)

De este modo, todas las condiciones de desbordamiento y subdesbordamiento pueden protegerse de forma segura. Sin embargo, lo anterior no funcionará cuando v o u sea cero. En estos casos, la solución es recurrir a un algoritmo diferente, por ejemplo(1).

Floating point comparison - 1.71.0
  • www.boost.org
Unless specified otherwise, when a value of floating-point type is compared inside a assertion, operators , , etc. defined for this type are used. However for floating point type, in most cases what is needed is not an equality (or inequality), but a verification that two numbers are or . For that purpose, a parameter that will instruct the...
 
Igor Makanu:
void OnStart()
{
  double Num=0.0;
  if(0.1 * Num){} // expression not boolean     
}

¿A qué? Todo lo que veo es una advertencia idiota, si es perfectamente válida.

Conversiones booleanas

Un prvalue de tipo integral, de punto flotante, de enumeración sin cobertura, de puntero y de puntero a miembro puede convertirse en un prvalue de tipo bool.

El valor cero (para la integral, el punto flotante y la enumeración sin escalas) y el puntero nulo y los valores del puntero nulo a miembro se convierten en falsos. Todos los demás valores se convierten en verdaderos.

En general, es pura ignorancia escribir estos IsEqual(), IsInf() e IsZerro(). No voy a entrar en la discusión.

 
Vict:

¿A qué? Todo lo que veo es una advertencia idiota, si es absolutamente válida.

En general, es una completa ignorancia escribir tales IsEqual(), IsInf(), IsZerro(). No voy a entrar en la discusión.

IsInf() y IsNaN() funcionan,

IsEqual() e IsZerro() son cuestionables, buscados en Google como "truco para el doble".

Razón de la queja: