Merkmale der Sprache mql5, Feinheiten und Techniken - Seite 144

 
Igor Makanu:

Bei NaN müssen Sie zusätzlich prüfen

Das ist eine normale Zahl. Die Prüfung ist einfach: Dividieren Sie durch den Wert, durch den Sie den Wert dividieren, und prüfen Sie dann, ob der Wert Null ist.

 
fxsaber:

Das ist eine normale Zahl. Die Prüfung ist einfach: Durch was Sie teilen, prüfen Sie auf Null.

aber in diesem Code wird nicht auf Null geprüft:

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

AusdruckNum ? in MQL wird wahr sein, wenn es keinen Wert 0x0000000000000000 in 8 Bytes von double gibt

in jedem anderen Fall wird dieser Ausdruck(Num ?) wahr sein


Ich brachte eine Diskussion früher in diesem Monat über nicht überprüfen bool in MQL - die Antwort ist kein Datenverlust, so dass keine Notwendigkeit - es ist das gleiche Problem, Sie könnten versuchen, den Ausdruck in NaN aufgeteilt - wird nicht die Doppelbytes leer sein?


Ich kann das jetzt nicht nachprüfen, aber wahrscheinlich ist das der richtige Weg:

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

Aber in diesem Code wird nicht auf Null geprüft:

Ich kann es jetzt nicht überprüfen, aber wahrscheinlich muss es so sein:

Es wird nicht funktionieren. Num ist im Beispiel des Absturzes eine normale Zahl. Das bool hat damit nichts zu tun.

 
fxsaber:

Es wird nicht funktionieren. In dem Beispiel mit dem Absturz ist Num eine normale Zahl. Das bool hat damit nichts zu tun.

Geprüfte NaN-Suche

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

}
//_______________________________________________________________________

es in MQL5 wirklich funktioniert, können Sie die Schleife bei Null beginnen, aber Sie müssen länger warten.

Es handelt sich um eine Frage der doppelten Genauigkeit - sie ist an einen bestimmten Prozessortyp gebunden, deshalb habe ich die obigen Bemerkungen gemacht, dass der Fehler nicht reproduziert wird


UPD:

ist es besser, auf diese Weise zu schließen:

if(ULongDouble.d != ULongDouble.d) Print("NaN, d = ", ULongDouble.d); // tst1 (EURUSD,H1)	NaN, d = -nan
 
Hmmm, warum sollte überhaupt eine Ausnahme ausgelöst werden, wenn die Division durch Null-Doppelgänger? Nun, es gäbe Inf, es gäbe irgendeinen Blödsinn.
 
Igor Makanu:

Ihre Frage bezieht sich im Allgemeinen auf die Genauigkeit der Verdopplung - sie ist im Allgemeinen an einen bestimmten Prozessortyp gebunden, weshalb die obigen Bemerkungen über die Nichtreproduzierbarkeit des Fehlers

Sie ist auf jedem Typ reproduzierbar. Um ehrlich zu sein, verstehe ich nicht, warum es so viele Gespräche zu diesem Thema gibt. Nun, sie haben zwei Zahlen, die nicht Null sind, multipliziert und erhielten Null. Keine Magie.


Jeder versteht diesen Code, nicht wahr?

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


Eine ganz ähnliche Situation liegt vor, wenn d zu Null wird.

 
fxsaber:

Keine Magie.

Das ist die Magie, unbedruckt wie hier:

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:

Die Situation ist hier absolut gleich, wenn d zu Null wird.

In Ihrem Beispiel ist 0.1 * Num ? ein bool - es ist ein einfaches Vorhandensein eines Bits in 8 Bytes von double

und wenn 0.1 * Num ein Double ist, dann kann man, wenn man die Genauigkeit verliert, zu Nan gehen und eine Nullteilung erhalten

 
Das habe ich nicht verstanden.
#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 ist kein minimales positives Double.

 
fxsaber:

DBL_MIN ist ein nicht minimaler positiver Double.

Ich glaube, die zweite Zahl hat ein ungültiges doppeltes Format, aber sie wird trotzdem sowohl im Drucker als auch in den Operationen validiert.

 
fxsaber:
Ich habe es hier nicht verstanden.


DBL_MIN ist kein minimales positives Double.

Nun, vergleichen Sie DBL_MIN mit NaN - das Ergebnis wird in bool sein, richtig?

Und wenn Sie 1,0 durch eine Nicht-Zahl teilen, erhalten wir eine Ausnahme, wie oben gesagt wurde

im Allgemeinen die Tatsache, dass die Entwickler viele Male geschrieben haben, dass der Vergleich mit mehr als / weniger als / gleich double nicht korrekt ist - es ist wahr, manchmal kann man eine Nicht-Zahl erhalten und das Vergleichsergebnis wird nicht vorhersehbar sein.

Grund der Beschwerde: