Как понять такие числа? 0.07 == 0.07000000000000001

 

Добрый день. На MQL пишу не так давно и все никак не могу понять его принципов работы с дробными числами:

double Var = 0.07;
Alert (Var);
// На выходе: 0.07000000000000001

Почему, задав переменную значением "0.07" я на выходе получаю уже "0.07000000000000001". Как правильно нормализовывать дробные числа?

Если перевожу в тип float:

float Var = 0.07;
Alert (Var);
// На выходе: 0.07

Получаем, что нужно, "0.07". Отлично! Но:

float Var = 0.07 + 0.7 + 7 + 70 + 700;
Alert (Var);
// На выходе: 777.77002
// Должно: 777.77

Так же я пробовал нормализовывать данные:

float Var = DoubleToStr (0.07 + 0.7 + 7 + 70 + 700, 2);
Alert (Var);
// На выходе: 777.77002

float Var = NormalizeDouble (0.07 + 0.7 + 7 + 70 + 700, 2);
Alert (Var);
// На выходе: 777.77002

double Var = DoubleToStr (0.07, 2);
Alert (Var);
// На выходе: 0.07000000000000001

double Var = NormalizeDouble (0.07, 2);
Alert (Var);
// На выходе: 0.07000000000000001

Как говориться, "Толи я дурак, толи лыжи не едут". :)

Прошу, подскажите, как все же работать с дробными числами, чтобы они показывали так, как я привык видеть значения и операции с ними в калькуляторе.
Если такое возможно в MQL.
Или какие альтернативы работы с числами можно придумать?
СПАСИБО!

 
float Var = DoubleToStr (0.07 + 0.7 + 7 + 70 + 700, 2);
Alert (Var);
// На выходе: 777.77002

float Var = NormalizeDouble (0.07 + 0.7 + 7 + 70 + 700, 2);
Alert (Var);
// На выходе: 777.77002

double Var = DoubleToStr (0.07, 2);
Alert (Var);
// На выходе: 0.07000000000000001

double Var = NormalizeDouble (0.07, 2);
Alert (Var);
// На выходе: 0.07000000000000001

здесь у вас неявное преобразование типов из string, получаемого как результат функции DoubleToStr, в double (float), тип переменной которая принимает значение.
Замените выделенные double (float) на string и все буде добре.

 
WePlexus:

читайте документацию

-- https://www.mql5.com/ru/docs/basis/types/double  

-- https://www.mql5.com/ru/docs/convert/normalizedouble

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

 
Можно еще посмотреть статью Особенности работы с числами типа double в MQL4
Особенности работы с числами типа double в MQL4 - Статьи по MQL4
  • www.mql5.com
Особенности работы с числами типа double в MQL4 - Статьи по MQL4: примеры использования экспертов, тестирования и оптимизации
 

Вместимость и точность у double выше чем у float, а ошибки округления (при представлении данных) будут присутствовать всегда.

Используйте:

Alert (DoubleToStr (0.07, 2));
Alert (DoubleToStr (0.07 + 0.7 + 7 + 70 + 700, 2));
 
Ох и задача с числами. :) Я привык как в калькуляторе и, например, в PHP, что считаем - то и получаем, без нужны нормализовать или думать о типах, размерностях...
Спасибо за подсказки, ALXIMIKS методом пользуюсь.
 
ALXIMIKS:

здесь у вас неявное преобразование типов из string, получаемого как результат функции DoubleToStr, в double (float), тип переменной которая принимает значение.
Замените выделенные double (float) на string и все буде добре.

худший совет, который можно дать.
 
abolk:
худший совет, который можно дать.

А где же ссылка на документацию, как верно давать советы?

 

Касательно объявления переменной string, все зависит что надо пользователю, вдруг он это значение будет использовать еще в Print, Comment, SendMail, ........
Зачем каждый раз  преобразовывать?

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

 
ALXIMIKS:

А где же ссылка на документацию, как верно давать советы?

 

Касательно объявления переменной string, все зависит что надо пользователю, вдруг он это значение будет использовать еще в Print, Comment, SendMail, ........
Зачем каждый раз  преобразовывать?

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

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

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

а ведь есть простое решение от  ALXIMIKS -- использовать только string. 

P.s. да вы, оказывается, ещё и заказы выполняете https://www.mql5.com/ru/users/ALXIMIKS/portfolio -- и там тоже string вместо double?

 
ALXIMIKS:

А где же ссылка на документацию, как верно давать советы?

 

Касательно объявления переменной string, все зависит что надо пользователю, вдруг он это значение будет использовать еще в Print, Comment, SendMail, ........
Зачем каждый раз  преобразовывать?

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

Тут же всё понятно что человеку нужно:

double Var = 0.07;
Alert (Var);
// На выходе: 0.07000000000000001

Зачем гадать? Ему нужно вывести double-значение с нужной ему точностью в алерте, т.е. так:

double Var = 0.07;
Alert(DoubleToString(Var,2));
// На выходе: 0.07

А если нужно в переменную (о чём вы говорите), то её нужно задать как string

double Var = 0.07;
string var_str=DoubleToString(Var,2);
Alert(var_str);
// На выходе: 0.07
 
double Var = NormalizeDouble (0.07, 2);
Alert (Var);
// На выходе: 0.07000000000000001

Справку слабо почитать? Например по функции NormalizeDouble:

Примечание

Рассчитываемые значения StopLoss, TakeProfit, а также значения цены открытия отложенных ордеров, должны быть нормализованы с точностью, значение которой можно получить функцией Digits().

Нужно иметь в виду, что нормализованное число при выводе в Журнал с помощью Print() может содержать большее количество знаков после запятой, чем вы ожидаете. Например,

   double a=76.671;             // нормализованное число с 3 знаками после запятой
   Print("Print(76.671)=",a);   // выведем его как есть
   Print("DoubleToString(a,8)=",DoubleToString(a,8)); // выведем с заданной точностью

выдаст в терминале:

 DoubleToString(a,8)=76.67100000

 Print(76.671)=76.67100000000001

Alert очевидно схож с Print и для него это тоже касается. 

Вы вообще в курсе что выполняете двойное преобразование через string?

float Var = DoubleToStr (0.07 + 0.7 + 7 + 70 + 700, 2);
Alert (Var);
// На выходе: 777.77002

Какая задача вообще стоит? Если вывести число на печать, преобразуйте через DoubleToString. Если нужна нормализация то NormalizeDouble.

Тип float не используйте вовсе. Он слишком опасен.

WePlexus:
Ох и задача с числами. :) Я привык как в калькуляторе и, например, в PHP, что считаем - то и получаем, без нужны нормализовать или думать о типах, размерностях...
Спасибо за подсказки, ALXIMIKS методом пользуюсь.
Че, реально сейчас на PHP такие "программисты" есть?
Причина обращения: