Caractéristiques du langage mql5, subtilités et techniques - page 144

 
Igor Makanu:

Pour les NaN, vous devez vérifier en plus

Il y a un nombre normal là. La vérification est simple - divisez par ce par quoi vous le divisez, puis vérifiez si vous avez zéro.

 
fxsaber:

Il y a un nombre normal là. La vérification est simple : on vérifie que le résultat de la division est égal à zéro.

mais vous ne vérifiez pas le zéro dans ce code :

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

L'expressionNum ? en MQL sera vraie s'il n'y a pas de valeur 0x0000000000000000 dans 8 octets de double.

dans tout autre cas, cette expression(Num ?) sera vraie.


J'ai soulevé une discussion au début du mois sur le fait de ne pas vérifier les bools dans MQL - la réponse est qu'il n'y a pas de perte de données, donc pas besoin - c'est le même problème, vous pourriez essayer de diviser l'expression en NaN - les doubles octets ne seront-ils pas vides ?


Je ne peux pas le vérifier maintenant, mais c'est probablement la façon de faire :

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

Mais vous ne vérifiez pas le zéro dans ce code :

Je ne peux pas le vérifier maintenant, mais ça doit probablement être comme ça :

Ça ne marchera pas. Num est un nombre normal dans l'exemple de l'accident. Le bool n'a rien à voir avec cela.

 
fxsaber:

Ça ne marchera pas. Dans l'exemple de l'accident, Num est un nombre normal. Le bool n'a rien à voir avec cela.

Recherche NaN vérifiée

//+------------------------------------------------------------------+
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--;
   }

}
//_______________________________________________________________________

cela fonctionne vraiment dans MQL5, vous pouvez démarrer la boucle à partir de zéro, mais vous devrez attendre plus longtemps.

c'est une question de double précision - c'est lié à un type de processeur spécifique, c'est pourquoi j'ai fait les commentaires ci-dessus que l'erreur n'est pas reproduite


UPD :

il est préférable de conclure de cette façon :

if(ULongDouble.d != ULongDouble.d) Print("NaN, d = ", ULongDouble.d); // tst1 (EURUSD,H1)	NaN, d = -nan
 
Hmmm, pourquoi une exception serait-elle levée lors d'une division par zéro? Il y aurait des conneries, il y a des conneries.
 
Igor Makanu:

Votre question porte généralement sur la précision du double - elle est généralement liée à un type spécifique de processeur, ce qui explique les commentaires ci-dessus concernant l'impossibilité de reproduire l'erreur.

Il est reproductible sur n'importe quel type. Pour être honnête, je ne comprends pas pourquoi il y a tant de discussions sur ce sujet. Eh bien, ils ont multiplié deux nombres non nuls et ont obtenu zéro. Pas de magie.


Tout le monde comprend ce code, n'est-ce pas ?

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


Il y a une situation absolument similaire ici, lorsque d devient zéro.

 
fxsaber:

Pas de magie.

c'est la magie, non imprimée comme ça :

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 situation est absolument identique ici, lorsque d devient nul.

Dans votre exemple, lorsque 0,1 * Num ? est un bool, il s'agit de la simple présence d'un bit dans 8 octets de double.

et lorsque 0,1 * Num est un double, alors si vous perdez la précision, vous pouvez aller à Nan et obtenir une division par zéro.

 
Je n'ai pas eu celui-là.
#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 n'est pas un double positif minimum.

 
fxsaber:

DBL_MIN est un double positif non minime.

Je pense que le deuxième nombre a un double format invalide, mais il est toujours validé dans l'imprimante et les opérations.

 
fxsaber:
Je ne l'ai pas eu ici.


DBL_MIN n'est pas un double positif minimum.

Eh bien, comparez DBL_MIN avec NaN - le résultat sera dans bool, non ?

Et si on divise 1.0 par un non-nombre, on obtiendra une exception, comme il a été dit plus haut

en général, le fait que les développeurs ont écrit de nombreuses fois que comparer à plus que / moins que / égal à double n'est pas correct - c'est vrai, vous pouvez parfois obtenir un non-nombre et le résultat de la comparaison ne sera pas prévisible.

Raison: