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

 
Igor Makanu:

En el caso de NaN es necesario comprobar adicionalmente

Ahí hay un número normal. La comprobación es sencilla: se divide por lo que se divide, y luego se comprueba si es cero.

 
fxsaber:

Ahí hay un número normal. La comprobación es sencilla: lo que se divide por, se comprueba si es cero.

pero no se comprueba el cero en este código:

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

La expresiónNum ? en MQL será verdadera si no hay ningún valor 0x000000000000 en 8 bytes de doble

en cualquier otro caso esta expresión(Num ?) será verdadera


A principios de este mes, planteé una discusión sobre la no comprobación de bool en MQL - la respuesta es que no hay pérdida de datos, por lo que no es necesario - es el mismo problema, usted podría tratar de dividir la expresión en NaN - ¿no serán los bytes dobles vacíos?


No puedo comprobarlo ahora, pero probablemente sea la forma de hacerlo:

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

Pero no se comprueba el cero en este código:

No puedo comprobarlo ahora, pero probablemente tiene que ser así:

No funcionará. Num es un número normal en el ejemplo del choque. El bool no tiene nada que ver.

 
fxsaber:

No funcionará. En el ejemplo del choque, Num es un número normal. El bool no tiene nada que ver.

Comprobada la búsqueda de NaN

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

   ulong i = 0xFFFFFFFFFFFFFFFF;
   while(i > 0 && !IsStopped()) {
      ULongDouble.ul = i;
      if(ULongDouble.d != ULongDouble.d) Print("NaN, i = ", i);
      i--;
   }

}
//_______________________________________________________________________

realmente funciona en MQL5, puede iniciar el bucle desde cero, pero tendrá que esperar más tiempo.

es una cuestión de doble precisión - está ligado a un tipo de procesador específico, por eso hice los comentarios anteriores que el error no se reproduce


UPD:

es mejor concluir así:

if(ULongDouble.d != ULongDouble.d) Print("NaN, d = ", ULongDouble.d); // tst1 (EURUSD,H1)	NaN, d = -nan
 
Hmmm, ¿por qué se lanzaría una excepción al dividir por cero dobles? Bueno, habría inf, hay una mierda.
 
Igor Makanu:

Su pregunta se refiere en general a la precisión del doble - generalmente está ligada a un tipo específico de procesador, por lo que los comentarios anteriores sobre el error no son reproducibles

Es reproducible en cualquier tipo. Para ser sincero, no entiendo por qué hay tantas charlas sobre este tema. Pues bien, multiplicaron dos números no nulos y obtuvieron el cero. No hay magia.


Todo el mundo entiende este código, ¿no?

void OnStart()
{
  double d = 0.5;  
  int Count = 1;
  
  while (d *= d)
    Count <<= 1;
    
  Print(Count);
}


Aquí se da una situación absolutamente similar, cuando d se convierte en cero.

 
fxsaber:

No hay magia.

esa es la magia, sin imprimir así:

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

   ulong nan = 18446744073708624091;
   ULongDouble.ul = nan;
   
   Print("ULongDouble.d != ULongDouble.d ", ULongDouble.d != ULongDouble.d);
   double d_value = 0.1 * ULongDouble.d;
   bool b_value = d_value;
   Print("b_value =  ", b_value);
   Print("d_value =  ", d_value);
   Print("1 / d_value =  ", 1 / d_value);

}
//_______________________________________________________________________

2019.10.28 16:25:28.643 tst1 (EURUSD,H4) ULongDouble.d != ULongDouble.d true

2019.10.28 16:25:28.643 tst1 (EURUSD,H4) b_value = true

2019.10.28 16:25:28.643 tst1 (EURUSD,H4) d_value = nan

2019.10.28 16:25:28.667 tst1 (EURUSD,H4) zero divide in 'tst1.mq5' (28,31)



fxsaber:

La situación es absolutamente la misma aquí, cuando d se convierte en cero.

No me refiero al cero. En tu ejemplo, cuando 0.1 * Num ? es un bool - es una simple presencia de un bit en 8 bytes de doble

y cuando 0.1 * Num es un doble, entonces si se pierde la precisión, se puede ir a Nan y obtener una división de cero

 
No lo entendí.
#include <TypeToBytes.mqh> // https://www.mql5.com/ru/code/16280

void OnStart()
{
  double Num = 0;
  
  _W(Num) = (uchar)1;
  
  Print(Num < DBL_MIN); // true
  Print(DBL_MIN);       // 2.225073858507201e-308
  Print(Num);           // 4.940656458412465e-324
}


DBL_MIN no es un doble positivo mínimo.

 
fxsaber:

DBL_MIN es un doble positivo no mínimo.

Creo que el segundo número tiene un formato doble no válido, pero sigue siendo validado tanto en la impresora como en las operaciones.

 
fxsaber:
No lo conseguí aquí.


DBL_MIN no es un doble positivo mínimo.

Bien, compara DBL_MIN con NaN - el resultado estará en bool, ¿verdad?

Y si se divide 1,0 por un número que no es, obtendremos una excepción, como se dijo anteriormente

en general, el hecho de que los desarrolladores han escrito muchas veces que comparar a más de / menos de / igual a doble no es correcto - esto es cierto, a veces se puede obtener un no-número y el resultado de la comparación no será predecible.

Razón de la queja: