Особенности языка mql5, тонкости и приёмы работы - страница 146

 
fxsaber:

Он был закрыт с первого же поста. Когда минимальное число умножается на что-то меньшее единицы, то получается ноль.

как будет выглядеть правильный код?

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

компиляция: expression not boolean

результат: inf



по моему не самый лучший вариант

 
Да тут нет проблемы
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);
}


У себя так не делаю.


ЗЫ Для эстетов можно создать DOUBLE-структуру с соответствующими операторами. Но это все к практике отношения мало имеет. В исходном практическом примере

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Особенности языка mql5, тонкости и приёмы работы

fxsaber, 2019.10.28 07:24

Способ нарваться на деление на ноль даже с проверкой.
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    
}


Ошибка понятна по факту. Но во время написания подобного кода не всегда очевидно, что такой проверки не достаточно, чтобы избежать деления на ноль.


Нужно просто обнулить создаваемый элемент массива. Именно из-за отсутствия инициализации и возникают коллизии в данном случае. Поэтому у себя просто сделал обнуление. Заморочиваться с общим видом нет никакого желания.

 
Igor Makanu:

компиляция: expression not boolean

результат: inf



по моему не самый лучший вариант

Что-то вас куда-то не туда.

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

Тут больше непонятно - почему деление на ноль даёт исключение fpu, для меня во всяком случае.

 
Vict:

Что-то вас куда-то не туда.

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

fxsaber:
Да тут нет проблемы

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:

проверка на inf

void OnStart()
{
   double dev = 1.0 / 4.940656458412465e-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


т.е. как и ожидалось inf это не NaN
 
fxsaber:
Да тут нет проблемы
bool IsNull( const double Num )
{
  return(MathAbs(Num) < DBL_MIN);
}

прогуглил "C++ double zero divide", в Вашем коде не будут не нормализованные числа работать, нужно так:

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


скрипт для медитации )))

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

Интересная тема. Нарыл вот тут кое-что. Особенно примечательно в блоке про теорию.

 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     
}

К чему? Вижу лишь идиотское предупреждение, if абсолютно валидный.

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.

Вообще, полное невежство писать такие IsEqual(), IsInf(), IsZerro(). В дискуссию втягиваться не буду.

 
Vict:

К чему? Вижу лишь идиотское предупреждение, if абсолютно валидный.

Вообще, полное невежство писать такие IsEqual(), IsInf(), IsZerro(). В дискуссию втягиваться не буду.

 IsInf() и IsNaN() рабочие, 

IsEqual() и IsZerro() под вопросом, нагугленные из неких источников как "trick for double"

Причина обращения: