Caratteristiche del linguaggio mql5, sottigliezze e tecniche - pagina 144

 
Igor Makanu:

Su NaN è necessario controllare anche

Lì c'è un numero normale. Il controllo è semplice: dividi per quello per cui lo dividi, poi controlla se c'è uno zero.

 
fxsaber:

Lì c'è un numero normale. Il controllo è semplice: per cosa lo si divide, si controlla che sia zero.

ma non si controlla lo zero in questo codice:

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

L'espressioneNum ? in MQL sarà vera se non c'è nessun valore 0x0000000000000000 in 8 byte di doppio

in ogni altro caso questa espressione(Num ?) sarà vera


Ho portato avanti una discussione all'inizio di questo mese sul non controllare bool in MQL - la risposta è nessuna perdita di dati, quindi non c'è bisogno - è lo stesso problema, si potrebbe provare a dividere l'espressione in NaN - i doppi byte non saranno vuoti?


Non posso controllare ora, ma probabilmente è il modo per farlo:

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

Ma non si controlla lo zero in questo codice:

Non posso controllare ora, ma probabilmente deve essere così:

Non funzionerà. Num è un numero normale nell'esempio dell'incidente. Il bool non c'entra niente.

 
fxsaber:

Non funzionerà. Nell'esempio dell'incidente Num è un numero normale. Il bool non c'entra niente.

Ricerca NaN controllata

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

}
//_______________________________________________________________________

funziona davvero in MQL5, potete iniziare il ciclo da zero, ma dovrete aspettare più a lungo.

è una questione di doppia precisione - è legata a un tipo di processore specifico, ecco perché ho fatto i commenti precedenti che l'errore non viene riprodotto


UPD:

è meglio concludere così:

if(ULongDouble.d != ULongDouble.d) Print("NaN, d = ", ULongDouble.d); // tst1 (EURUSD,H1)	NaN, d = -nan
 
Hmmm, perché dovrebbe essere lanciata un'eccezione quando si divide per zero dubs? Beh, ci sarebbe inf, c'è qualche stronzata.
 
Igor Makanu:

La tua domanda è generalmente una domanda sull'accuratezza del doppio - è generalmente legata a un tipo specifico di processore, che è il motivo per cui i commenti sopra sull'errore non è riproducibile

È riproducibile su qualsiasi tipo. Ad essere onesti, non capisco perché ci siano così tanti discorsi su questo argomento. Beh, hanno moltiplicato due numeri non zero e hanno ottenuto zero. Nessuna magia.


Tutti capiscono questo codice, vero?

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


Qui c'è una situazione assolutamente simile, quando d diventa zero.

 
fxsaber:

Nessuna magia.

Questa è la magia, non stampata come questa:

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 situazione è assolutamente la stessa qui, quando d diventa zero.

Non mi riferisco allo zero. Nel tuo esempio, quando 0,1 * Num ? è un bool - è una semplice presenza di un bit in 8 byte di doppio

e quando 0,1 * Num è un doppio, allora se si perde la precisione, si può andare a Nan e ottenere una divisione a zero

 
Questo non l'ho capito.
#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 non è un doppio positivo minimo.

 
fxsaber:

DBL_MIN è un doppio positivo non minimo.

Penso che il secondo numero abbia un formato doppio non valido, ma è ancora convalidato sia nella stampante che nelle operazioni.

 
fxsaber:
Non l'ho capito qui.


DBL_MIN non è un doppio positivo minimo.

Bene, confrontate DBL_MIN con NaN - il risultato sarà in bool, giusto?

E se si divide 1,0 per un non numero, otterremo un'eccezione, come è stato detto sopra

in generale, il fatto che gli sviluppatori hanno scritto molte volte che confrontare a più di / meno di / uguale a doppio non è corretto - questo è vero, si può a volte ottenere un non numero e il risultato del confronto non sarà prevedibile.

Motivazione: