Баг MQL или я не прав?

 

есть функция:

double MathFloor( double x)
Функция возвращает числовое значение, представляющее наибольшее целое число, которое меньше или равно x.

есть отрывок кода:

if (StopLoss/Point-MathFloor(StopLoss/Point)!=0)
{
MessageBox("Некорректно задан уровень StopLoss."+"\n"+
"Количество знаков после запятой не должно превышать "+DoubleToStr(Digits,0)+"\n"+
"Программа проверит ошибки исходных данных и закончит свою работу!","Проверка исходных данных!");
}

суть в следующем - если уровень стоплосс содержит большее количество цифр после запятой, то это некорректный уровень стоплосс.

ошибка в чём? если уровень стоплосс содержит необходимое количество цифр после запятой, то код всё равно возвращает ошибку.

Почему?

потому что к примеру 1.3457/0.0001=13457 после обработки функцией double MathFloor(double x) становится равно 13456. хотя должно возвращать "...числовое значение, представляющее наибольшее целое число, которое меньше или РАВНО х"

прилагаю небольшой скрипт. его нужно повесить на валютную пару с 4-мя или 5-ю знаками после запятой. интересное тут в том, что значение 1.2457 определяется корректно, а значение 1.3457 - уже нет

странно, что для одних значений считается всё корректно, для других - нет

Файлы:
 

Вы не можете влоб сравнивать вещественные типы double, Вы может только проверять разницу. То есть, запись

StopLoss/Point-MathFloor(StopLoss/Point)!=0

не может гарантировать коррректной работы алгоритма. Правильно будет так:

MathAbs(StopLoss/Point-MathFloor(StopLoss/Point))< delta

В данном случае, delta =1 (единице).

 

и что получится? если разность будет равна 0, то будет также некорректно алгоритм работать

если такая строка будет:

if (MathAbs(StopLoss/Point-MathFloor(StopLoss/Point))>0 && MathAbs(StopLoss/Point-MathFloor(StopLoss/Point))<1)
{
MessageBox("Некорректно задан уровень StopLoss."+"\n"+
"Количество знаков после запятой не должно превышать "+DoubleToStr(Digits,0)+"\n"+
"Программа закончит свою работу!","Проверка исходных данных!");
return(0);
}

то всё равно на определённых числовых значениях алгоритм не работает

 

дело не в сравнении вещественных типов double.

дело в том, что функция MathFloor(1.3457/0.0001) возвращает значение не 13457, а 13456

ещё раз второй вариант скрипта прикрепляю, в котором происходит просто округление

вводите цифру 1.2457, делите на 0.0001, округляете и получается корректное значение 12457

вводите цифру 1.3457, делите на 0.0001, округляете и получаете значение 1.3456

вот в чём непонятки...

баг это или что по вашему?

Файлы:
 

при этом можно даже так написать в скрипте:

double a=StopLoss/Point;
double b=MathFloor(a);
Print("Округление до меньшего целого ",b,"; Округляемое значение ",DoubleToStr(a,8));

и получим, что при значении 1.2457 у нас b=12457, тогда как при значении 1.3457 b=13456

как это понимать?

 

Числа типа double могут на самом деле быть не тем, чем они кажутся. Только имея дело с типом int Вы можете быть в чем-то уверены. Вот пример вычисления вашего выраежния, запустите этот скрипт:

//+------------------------------------------------------------------+
//|                                             DemostrateDouble.mq4 |
//|                      Copyright © 2008, MetaQuotes Software Corp. |
//|                                   http://forum.mql4.com/cn/17189 |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2008, MetaQuotes Software Corp."
#property link      "http://forum.mql4.com/cn/17189"

#include <stdlib.mqh>
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
//----
   double div = 1.3457/0.0001;
   int floor = MathFloor(div);
   Print("floor = ", floor,"   div = ",DoubleToStr(div, 8));
   Print(" div с 16 знаками после запятой " , DoubleToStrMorePrecision(div,16));
//----
   return(0);
  }
//+------------------------------------------------------------------+


и увидите такой результат:



Файлы:
 

ну я уже догадался сам, что получается при делении отличное от должного значение.

вопрос в том, какой из вариантов расчёта неверен:

1) расчёт 1.3457/0.0001 с точностью 30 знаков после запятой в таблице Excel;

2) расчёт средствами языка MQL?

и если данную ошибку языка исправить нельзя, то может подскажете обходной алгоритм для определения корректности дробного числа?

например, я таким способом определял необходимый сайз сделки, то есть при заданном риске определял необходимый лот и проверял его на соответствие торговым условиям:

step_lot=MarketInfo(Symbol(),MODE_LOTSTEP);

size=MarketInfo(Symbol(),MODE_LOTSIZE);

size=0.01*Risk*AccountBalance()/(MathAbs(openprice-stoploss)*size);

size=MathFloor(size/step_lot)*step_lot;

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

как теперь поступать, если такой способ неправильно расчитывается?

 

Нужно изменить свое отношение. Если Вы не понимаете чем обусловлено такое поведение при делении типа double, то можно воспользоваться поиском.

Вот например, ветка Неясные приоритеты

 
нужно просто изменить строку:
if (StopLoss/Point-MathFloor(StopLoss/Point)!=0)

на строку:

if (NormalizeDouble(StopLoss/Point,1)!=MathFloor(NormalizeDouble(StopLoss/Point,1)))
{
MessageBox("Некорректно задан уровень StopLoss."+"\n"+
"Количество знаков после запятой не должно превышать "+DoubleToStr(Digits,0)+"\n"+
"Программа закончит свою работу!","Проверка исходных данных!");
return(0);
}

посмотрел ссылку, которую Вы разместили здесь. речь там идёт о приведении типов, что 7/10=0, а 7.0/10.0=0.7

это я уже знал, но никак не могу понять (хоть намекните что забить в поиск...) почему типы double - 1.2457/0.0001=12457.0, а 1.3457/0.0001=13456.9999999999999, почему одинаковые числа считаются так разно, всё равно что по аналогии 7.0/10.0=0.7, а 8.0/10.0=0.799999...

Вы считаете, это не есть ошибочной расчёт?!