Caratteristiche del linguaggio mql5, sottigliezze e tecniche - pagina 146

 
fxsaber:

È stato chiuso fin dal primo post. Quando il numero minimo viene moltiplicato per qualcosa di meno di uno, si ottiene zero.

come sarebbe il codice corretto?

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

Come sarà il codice giusto?

 
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);
}

compilazione: espressione non booleana

risultato: inf



non è una buona opzione per me

 
Non c'è nessun problema qui
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);
}


Non lo faccio io.


Per gli esteti, potete creare una struttura DOUBLE con gli operatori appropriati. Ma tutto questo ha poco a che fare con la pratica. Nell'esempio pratico originale.

ForUM sul trading, sistemi di trading automatico e test di strategia

Caratteristiche del linguaggio mql5, complessità e tecniche

fxsaber, 2019.10.28 07:24

Un modo per farsi prendere dalla divisione per zero, anche con un assegno.
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    
}


L'errore è infatti comprensibile. Ma mentre si scrive codice come questo, non è sempre ovvio che un tale controllo non è sufficiente per evitare la divisione per zero.


Avete solo bisogno di azzerare l'elemento dell'array che viene creato. È l'assenza di inizializzazione che causa le collisioni in questo caso. Ecco perché ho semplicemente fatto l'azzeramento nel mio codice. Non voglio preoccuparmi della visione generale.

 
Igor Makanu:

compilazione: espressione non booleana

risultato: inf



non è una buona opzione per me

C'è qualcosa che non va in te.

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

È più confuso sul perché dividere per zero dà un'eccezione fpu, almeno per me.

 
Vict:

Qualcosa ti sta portando nella direzione sbagliata.

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

fxsaber:
Nessun problema qui

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:

controllare l'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


cioè come previsto inf non è NaN
 
fxsaber:
Non c'è nessun problema qui.
bool IsNull( const double Num )
{
  return(MathAbs(Num) < DBL_MIN);
}

Googlato "C++ double zero divide", il tuo codice non funzionerà per i numeri non normalizzati, hai bisogno di questo:

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


script di meditazione ))))

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

Argomento interessante. Ho trovato qualcosa qui. Particolarmente degno di nota il blocco della teoria.

 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)

In questo modo tutte le condizioni di underflow e overflow possono essere protette in modo sicuro. Tuttavia, quanto sopra non funzionerà quando v o u è zero. In questi casi la soluzione è ricorrere a un algoritmo diverso, ad esempio(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 cosa? Tutto quello che vedo è un avvertimento idiota, se è assolutamente valido.

Conversioni booleane

Un prvalore di tipo integrale, a virgola mobile, un'enumerazione nonscoped, un puntatore e un puntatore a membro può essere convertito in un prvalore di tipo bool.

Il valore zero (per gli integrali, i floating-point e le enumerazioni nonscoped) e il puntatore nullo e i valori nulli del puntatore a membro diventano falsi. Tutti gli altri valori diventano veri.

In generale, è pura ignoranza scrivere queste IsEqual(), IsInf() e IsZerro(). Non entrerò nella discussione.

 
Vict:

A cosa? Tutto quello che vedo è un avvertimento idiota, se è perfettamente valido.

In generale, è una completa ignoranza scrivere tali IsEqual(), IsInf(), IsZerro(). Non entrerò nella discussione.

IsInf() e IsNaN() funzionano,

IsEqual() e IsZerro() sono discutibili, cercate su Google da alcune fonti come "trucco per il doppio".