Features of the mql5 language, subtleties and tricks - page 144

 
Igor Makanu:

On NaN you need to check additionally

There's a normal number there. The check is simple - divide by what you divide it by, then check for zero.

 
fxsaber:

There's a normal number there. The check is simple - what you divide by, you check for zero.

but you don't check for zero in this code:

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

expressionNum ? in MQL will be true if there is no value 0x0000000000000000 in 8 bytes of double

in any other case this expression(Num ?) will be true


i brought up a discussion earlier this month about not checking bool in MQL - the answer is no data loss, so no need - it's the same problem, you could try to split the expression into NaN - won't the double bytes be empty?


I can't check it now, but that's probably the way to do it:

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

But you don't check for zero in this code:

Can't check it now, but it probably needs to be like this:

It won't work. Num is a normal number in the crash example. The bool has nothing to do with it.

 
fxsaber:

It won't work. In the crash example Num is a normal number. The bool has nothing to do with it.

Checked NaN search

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

}
//_______________________________________________________________________

it really works in MQL5, you may start the loop from zero, but you'll have to wait longer.

it's a matter of double precision - it's tied to a specific processor type, that's why I made the above comments that the error isn't reproduced


UPD:

it's better to conclude that way:

if(ULongDouble.d != ULongDouble.d) Print("NaN, d = ", ULongDouble.d); // tst1 (EURUSD,H1)	NaN, d = -nan
 
Hmmm, why would an exception be thrown out at all when dividing by zero dubs? Well there would be inf, there's some bullshit.
 
Igor Makanu:

Your question is generally a question of the accuracy of double - it is generally tied to a specific type of processor, which is why the comments above about the error not being reproducible

It is reproducible on any type. To be honest, I don't understand why there are so many talks on this topic. Well, they multiplied two non-zero numbers and got zero. No magic.


Everybody understands this code, don't they?

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


There is an absolutely similar situation here, when d turns into zero.

 
fxsaber:

No magic.

that's the magic, unprinted like this:

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:

The situation is absolutely the same here, when d becomes zero.

I'm not referring to zero. In your example, when 0.1 * Num ? is a bool - it is a simple presence of one bit in 8 bytes of double

and when 0.1 * Num is a double, then if you lose precision, you can go to Nan and get a zero divide

 
I didn't get that one.
#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 is not a minimum positive double.

 
fxsaber:

DBL_MIN is a non-minimal positive double.

I think the second number has invalid double format, but it is still validated in both printer and operations.

 
fxsaber:
I did not get it here.


DBL_MIN is not a minimum positive double.

Well, compare DBL_MIN with NaN - the result will be in bool, right?

And if you divide 1.0 by a non-number, we will get an exception, as it was said above

in general, the fact that developers have written many times that comparing to more than / less than / equal to double is not correct - it's true, sometimes you can get a non-number and the comparison result will not be predictable.