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

 
fxsaber:

It was closed from the very first post. When the minimum number is multiplied by something less than one, you get zero.

what would the correct code look like?

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

What will the right code look like?

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

compilation: expression not boolean

result: inf



not a good option for me

 
There's no problem here
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);
}


I don't do it myself.


For aesthetes, you can create a DOUBLE structure with appropriate operators. But all this has little to do with practice. In the original practical example.

ForUM on trading, automated trading systems and strategy testing

Features of mql5 language, intricacies and techniques

fxsaber, 2019.10.28 07:24

Way to get caught up in division by zero, even with a check.
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    
}


The error is understandable in fact. But while writing code like this, it is not always obvious that such a check is not enough to avoid division by zero.


You just need to zero the array item being created. It is absence of initialization that causes collisions in this case. That's why I simply made zeroing in my code. I don't want to bother with the general view.

 
Igor Makanu:

compilation: expression not boolean

result: inf



not a good option for me

There's something wrong with you.

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

It's more confusing as to why dividing by zero gives an fpu exception, at least for me.

 
Vict:

Something is taking you all the wrong way.

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

fxsaber:
No problem here

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:

check for 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


i.e. as expected inf it is not NaN
 
fxsaber:
There's no problem here.
bool IsNull( const double Num )
{
  return(MathAbs(Num) < DBL_MIN);
}

Googled "C++ double zero divide", your code won't work for non-normalised numbers, you need this:

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


meditation script ))))

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

Interesting topic. Found something here. Particularly noteworthy in the theory block.

 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)

This way all underflow and overflow conditions can be guarded safely. The above however, will not work when v or u is zero. In such cases the solution is to resort to a different algorithm, e.g.(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     
}

To what? All I see is an idiotic warning, if is absolutely valid.

Boolean conversions

A prvalue of integral, floating-point, unscoped enumeration, pointer, and pointer-to-member types can be converted to a prvalue of type bool.

The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values become false. All other values become true.

In general, it is sheer ignorance to write these IsEqual(), IsInf() and IsZerro(). I will not get into the discussion.

 
Vict:

To what? All I see is an idiotic warning, if is perfectly valid.

In general, it is complete ignorance to write such IsEqual(), IsInf(), IsZerro(). I will not get into the discussion.

IsInf() and IsNaN() are working,

IsEqual() and IsZerro() are questionable, googled from some sources as "trick for double".

Reason: