Вопрос к мастерам MQL4. Опять про Double Compare. - страница 6

 
VBAG:
...
Вся прелесть, кода который предложил Irtron, заключается в его компактности( абсолютно ничего лишнего-даже на переменных экономия!)
...


Вот, посмотрел метод, который предложил Irtron

int ComparePrice(double a, double b, double digit)
{
     a -= b;
     b = digit;
     if (a > b)
         return (1);
     if (a < -b)
         return (-1);
     return (0);
 }

Он и Компактный и быстрее моего, но даже на первый взглят выглядит подозрительным, потому что в сравнении участвуют две переменные double!!!!

В этой схеме только digit выступает как константа и может сравниваться, а переменная а, которая тоже сравнивается, как была ненормализованная double так ею и осталась!
Это вызывает подозрение? (Под коонстантой я понимаю обычные константы - "#define" и те переменный которые не участвовали в операциях).

Так же в других ветка сами разработчики писали, что даже константы double лучше не сравнивать!!!
И так тоже не правильно делать NormalizeDouble(а)  !OC!   NormalizeDouble(b), !OC! - оператор сравнения!

Тем более, что в первоначальном варианте вместо константы digits было так b = Point / 2 - здесь уже две из двух ненормализованных переменных?

Хотелось бы верить, что этот вариант гениальный, но прежде развейте мои сомнения!

Может и в моем варианте кто-нибудь ошибки найдет?
 
gravity001:

Вот, посмотрел метод, который предложил Irtron

int ComparePrice(double a, double b, double digit)
{
     a -= b;
     b = digit;
     if (a > b)
         return (1);
     if (a < -b)
         return (-1);
     return (0);
 }
Я предлагал иной метод.
Смотрите внимательнее, пожалуйста.


Тем более, что в первоначальном варианте вместо константы digits было так b = Point / 2 - здесь уже две из двух ненормализованных переменных?

О каких вариантах речь?

Про нормализацию я уже говорил. Сначала расскажите, зачем ее применять, а уже потом как и где.

Например, может Вы знаете, зачем сравнивать цены с точностью именно 14 знаков, которая упомянута как некое достижение в обсуждении выше? :) Напомню, функция, которую я предложил, называется ComparePrice. :)
 

Irtron писал (а):
...
Я предлагал иной метод.
Смотрите внимательнее, пожалуйста.
...

О каких вариантах речь?

Про нормализацию я уже говорил. Сначала расскажите, зачем ее применять, а уже потом как и где.

Например, может Вы знаете, зачем сравнивать цены с точностью именно 14 знаков, которая упомянута как некое достижение в обсуждении выше? :) Напомню, функция, которую я предложил, называется ComparePrice. :)
Вот, это Ваше? Я правильно щаз цитирую?
Irtron 10.09.2007 04:07

...

int ComparePrice(double a, double b)
{
    a -= b;
    b = Point / 2.;
    if (a > b)
        return (1);
    if (a < -b)
       return (-1);
    return (0);
}
...
Напомню, функция, которую я предложил, называется ComparePrice. :)

Если вы заметили, я тоже цитировал функцию, которая называлась ComparePrice. Просто Вашу уже модифицировал VBAG. Поэтому я и писал про перваначальный вариант имея виду оригинал, т.е. Вашу функцию!
Сам Тестировал обе функции. Да оказались они быстрее. Но как проверить надежность сравнения? Меня сильно смущает сравнение двух переменных double? Хотя все должно быть правильно так как береться интервал! Но все равно есть подозрения, что она не всегда будет работать правильно!

Про нормализацию я уже говорил. Сначала расскажите, зачем ее применять, а уже потом как и где.

Вот ключевой вопрос, да? Сам думал над этим долго: "вводишь double и получаешь double"  . Что может вроде измениться?
Точного ответа не нашел. Но представляю себе это так

double a = 2.000000000000
double b = 2.000000000001
double c = 1.999999999999

Все эти переменные разные и в памяти они храняться с точностья до последнего знака (цифры)!
В этом случае мы сами определяем знаки (цифры). Все что не определили заполняется нулями.

Если бы мы задовали double a = 2.0, а в памяти это запоминалось уже как 2.0000001 или как 1.9999999, то ясно, что NormalizeDouble() тогда бы не помогла, так как возращала бы уже неточное значение!
Я думаю, что такая ошибка при запоминании значения переменной бывает почти никогда. Тем более я не думаю что число 2.0 специально запоминается как 1.9999999999999, так как за каждый знак (цифру или точку) отвечат определенный бит в битовой строке памяти! Поэтому число 2.0 надежно храниться как 2.00000...00.

Другой случай, когда знаки мы не сами определяем:

a = 4.0;
b = 2.0; 
c = a / b // - операцию "деления" делает процессор, а вернее сопроцессор, и он же заполняет пременную знаками (цифрами).

После операции может быть:
Чаще всего:
с = 2.000...0
с= 1.99999999...
с= 2.00000001...

т.е. результат частенько отличеется от истинного на маленькую величину.

Большие ошибки всчтречаются очень редко:
с = 2.3

Здесь, есть два объяснения:
1) часть битовой строки пострадало в памяти при вызове a или b, т.е. изменились переменные а и b.
2) произошла ошибка при операции "деления".

Я думаю, что чаще всего происходит 2). Почему я не знаю. Думаю, это связано с тем, что работу сопроцессора стараються сильно оптимизировать в ущерб надожности.

Ясно, что при сравнении переменной с с числом 2.000...00 равенство не выполниться. Так как не все биты будут совпадать.

Вот теперь, NormalizeDouble()  призвано помочь!
NormalizeDouble() "исправит" эту маленькую погрешность!
Так как погрешность, чаще всего, очень маленькая, то округление с небольшой точностью будут всегда давать правильный результат.

Выглядеть это будет так:
Округлим число  a = 2.111...11 до второго знака.
для этого NormalizeDouble() запишет в новую переменную сначало 2. 11,  а оставшиеся биты заполнит нулями, а не однерками!
Думаю вуглядеть это будет так:

double MyNormalizeDouble(double value, int digits)
{
    int factor = MathRound( MathPow(10, digits) ); // factor - это множитель,
                                                      с помощью которого мы из VALUE сделаем целое число
    double result = MathRound(factor * value) / factor;
    
    return(result);
}
Вот, постарался объяснить как мог, зачем нужна NormalizeDouble().

До недавнего времени это объяснение меня полностью устраивало. Но недавно сам убедился, что такая схема не всегда работает

NormalizeDouble(a, 2) !OC! NormalizeDouble(b, 2), где !OC! - это оператор сравнения.
Хотя по моим представлениям она должно работать всегда!
Поэтому буду рад Любой аргументированной и понятной критике!
 
gravity001:

Так же в других ветка сами разработчики писали, что даже константы double лучше не сравнивать!!!
Вот это для меня новость! Что называется - вопрос по-существу!
Если можно, то приведите ссылочку, пожалуйста!

Возник вопрос к разработчикам:

Поясните, пожалуйста, какие есть ограничения или возможные проблемы при сравнении даблов с использованием констант:
1.
double a=1.23456789;
double b;

if(a>b) или if(a<b)

И в таком виде:
2.
#define a 1.23456789;

double b;

if(a>b) или if(a<b)
 
gravity001:

Тем более, что в первоначальном варианте вместо константы digits было так b = Point / 2 - здесь уже две из двух ненормализованных переменных?

Вот именно по этой причине я и заменил выражение b = Point / 2 на константу (1.меньше операций - больше скорость 2.передача в явном виде константы-выше надежность)

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

Интересно, что скажут разработчики.
 
VBAG писал (а):
...
Вот это для меня новость! Что называется - вопрос по-существу!
Если можно, то приведите ссылочку, пожалуйста!
...
Да, я искал ссылку, хотел сразу вставить, но не нашел! Помню где-то видел, но таких тем так много было. Еще я на других форумах кучу тем прочитал, еще из книжек читал по этой теме.
Помню, где-то кто-то писал, но не помню где(((((. Поэтому, наверно,  не корректно с моей стороны было написать: "в других ветка сами разработчики писали"!
Извеняюсь.
Но если найду обязательно ссылку выложу.

Мне кажется, это я читал в книжке по С++. Там было описано как надо сравнивать вещественные числа и там было написано, что лучше всего переходить к целым!
 
gravity001:
VBAG писал (а):
...
Вот это для меня новость! Что называется - вопрос по-существу!
Если можно, то приведите ссылочку, пожалуйста!
...
Да, я искал ссылку, хотел сразу вставить, но не нашел! Помню где-то видел, но таких тем так много было. Еще я на других форумах кучу тем прочитал, еще из книжек читал по этой теме.
Помню, где-то кто-то писал, но не помню где(((((. Поэтому, наверно, не корректно с моей стороны было написать: "в других ветка сами разработчики писали"!
Извеняюсь.
Но если найду обязательно ссылку выложу.

Мне кажется, это я читал в книжке по С++. Там было описано как надо сравнивать вещественные числа и там было написано, что лучше всего переходить к целым!
Спасибо Вам за участие и помощь. К сожалению, у меня нет академических знаний в области программирования. Поэтому приходиться больше слушать и запоминать. И надеяться, что разработчики откликнутся и разъяснят мой вопрос.
Возник вопрос к разработчикам:

Поясните, пожалуйста, какие есть ограничения или возможные проблемы при сравнении даблов с использованием констант:
1.
double a=1.23456789;
double b;

if(a>b) или if(a<b)

И в таком виде:
2.
#define a 1.23456789;

double b;

if(a>b) или if(a<b)
 
Такие проблемы - 1.3333+0.0004 != 1.3337
 

Похоже, этот разговор будет продолжаться бесконечно. До тех пор, пока новый юзер обретёт должный опыт и знания, он, как правило, успевает наколоться на нормализации несколько раз.

Пожалуй, в МТ5 имеет смысл принудительно ограничивать точность действительных чисел при исполнении операций сравнения, скажем, до 8 знака после запятой (т.е. принудительно исполнять NormalizeDouble() с digit=8). И только в том случае, если явно указана функция NormalizeDouble(), проводить нормализацию в соответствии с указанными в ней параметрами. В этом случае вопрос будет вознкать значительно реже, а именно только тогда, когда юзеру будет нужна именно заданная точность. По-моему, этот хрен хоть и немного, но всё же слаще редьки.

 
VBAG:
Здравствуйте!
Как известно, от стиля программирования и аккуратности в коде зависит не только правильность расчетов, но и надежность работы написанного кода.
Пишем не игрушки, а потому надежность работы написанной программы является самым первым требованием. Большинство расчетов производится в даблах и корректное сравнение в коде
программы двух вещественных чисел, требует определенного подхода и аккуратности.
Пытаюсь выработать "правильный" стиль программирования. Отсюда вопрос:

Для выражения

double a;
double b;

if(a==b) или if(a!=b)
{......} {.... ..}

разработчики рекомендуют так
//+------------------------------------------------------------------+
//| Функция сранения двух вещественных чисел. |
//+------------------------------------------------------------------+
bool CompareDouble(double Number1, double Number2)
{
bool Compare = NormalizeDouble(Number1 - Number2, 8) == 0;
return(Compare);
}
//+------------------------------------------------------------------+


Корректен ли код?

double a;
double b;

if(a>b) if(a<b)
{......} {......}


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

Ну нагородили... :)

Сравнение плавающих чисел - делается сравнением модуля разности с маленьким порогом.

return (fabs(d1-d2) < 1e-10) к примеру.

Зачем мутить воду... Функция NormalizeDouble(...) - для красивых отчетов нужна, и не более.