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

 
SK. писал (а):

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

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

Уж от Вас то, я такого никак не ождал. Ни в коем случае нельзя!
Если операция сравнения будет использоваться многократно (в рекурентных расчетах, и т.д.), то при округлении до 8 знаков на входе, погрешность на выходе может быть соизмерима с 1.

У меня был такой опыт с вычислением SmoothedAvarege, вычисляя его в своем приложении год назад. После этого я стараюсь избирать такие методы работы которые не трогают разрядность даблов.
Либо как предложил gravity001 перходить к INTам(что, сами понимаете, очень трудоемко).
 
SK. писал (а):

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


Однако терминал замедляют не только операции, заданные пользователем, но и операции, скрытые от него. Мне кажется предпочтительнее просто ввести в язык фунцию ComparePrice. Кстати, также как и Irtron считаю естественной мерой Point/2 (возможно лучше Point *0.5). Чтобы не делить/умножать каждый раз, эту половинку можно сделать предопределённой переменной. А пока этого нет, можно ввести такую переменную самому и вычислять её один раз при первом запуске start. Хотя в силах разработчиков и сделать функцию сравнения double с заданной точностью, то есть то же, но с digits вместо Point/2.
 
Depfy:

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

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

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

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

Спасибо за пример.
Но Вы не догнали суть вопроса, читать надо внимательнее. Суть вопроса - стиль программирования вообще, и в конкретном случае MT4.
 
VBAG:
Depfy:

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

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

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

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

Спасибо за пример.
Но Вы не догнали суть вопроса, читать надо внимательнее. Суть вопроса - стиль программирования вообще, и в конкретном случае MT4.

А сказали бы в чем суть вопроса... А то намеки - я не!понимаю :)

Если речь о быстродействии, то в совр. процессорах плавающие операции выполняются

почти так же быстро, как и целочисленные. Что касается СТИЛЯ, то, сори, прагматизм рулит...

Когда АШИПКИ кругом, то о каком стиле речь... Лишь бы работало. ..

А то нету других проблем, чем сравнить два числа :))))))))

 
VBAG:
Уж от Вас то, я такого никак не ождал. Ни в коем случае нельзя!
Если операция сравнения будет использоваться многократно (в рекурентных расчетах, и т.д.), то при округлении до 8 знаков на входе, погрешность на выходе может быть соизмерима с 1.

У меня был такой опыт с вычислением SmoothedAvarege, вычисляя его в своем приложении год назад. После этого я стараюсь избирать такие методы работы которые не трогают разрядность даблов.
Либо как предложил gravity001 перходить к INTам(что, сами понимаете, очень трудоемко).


Минуточку. Не нужно скоропостижных выводов.

Во-первых. Я не предлагаю принудительно округлять собственно значения самой действительной переменной. Я предлагаю сделать принудительное округление сравниваемых значений (копий) переменных при вычислении результата опериции сравнения (для умолчательного случая). А собственно значение переменной, разумеется, трогать нельзя. При этом никакие другие вычисляемые значения не пострадают, т.к. исходные значения переменных, используемых в операции сравнения, сохраняют свои значения, и ошибки в циклических расчётах накапливаться не будут.

Во-вторых. Я сказал, что для того, чтобы исключить ошибки с более тяжёлыми последствиями, можно пойти по такому пути. Однако, для того, чтобы обеспечить и более требовательные вычисления, необходимо сохранить возможность штатного использования функции NormalizeDouble() с заданными параметрами.

Таким образом, моё предложение не ограничивает возможности языка, а расширяет их.

Иное дело, что незадачливый юзер, не знающий о подобных преобразованиях, и в этом случае тоже может получить непонятный ему результат. Однако, учитывая, что в операциях сравнения, как правило, используются значения цены (т.е, digit = 4), в подавляющем большинстве случаев эта ошибка просто не возникнет. Таким образом, использование предлагаемой технологии повлечёт снижение количества ошибок, приводящих к непредсказуемым последствиям.

 
lna01:
А пока этого нет, можно ввести такую переменную самому и вычислять её один раз при первом запуске start.

Нельзя.

Вернее, написать программные строки можно, однако никто ( в т. ч. и разработчики) не даст гарантии, что значение этой переменной будет строго неизменным в течение всего срока работы советника. Дело здесь не в точности программного кода, а в технологических особенностях вычислений и в технологических правилах хранения значений переменных. Если бы не это, то и вопрос не возник бы.

А при существующем положении дел исходное значение переменной 123.00000000000 к моменту её использования в вычислениях может оказаться 122.999999999999. И это при том, что с момента открытия переменной её значение ни разу не изменялось, а только запрашивалось программой для участия в других вычислениях.

Собственно, потому и весь сыр-бор. Потому и возникла необходимость использования NormalizeDouble() как можно ближе к собственно вычислению, желательно прямо в Условии оператора if, for, while.

 
SK. писал (а):
lna01:
А пока этого нет, можно ввести такую переменную самому и вычислять её один раз при первом запуске start.

Нельзя.

Вернее, написать программные строки можно, однако никто ( в т. ч. и разработчики) не даст гарантии, что значение этой переменной будет строго неизменным в течение всего срока работы советника. Дело здесь не в точности программного кода, а в технологических особенностях вычислений и в технологических правилах хранения значений переменных. Если бы не это, то и вопрос не возник бы.

А при существующем положении дел исходное значение переменной 123.00000000000 к моменту её использования в вычислениях может оказаться 122.999999999999. И это при том, что с момента открытия переменной её значение ни разу не изменялось, а только запрашивалось программой для участия в других вычислениях.

Собственно, потому и весь сыр-бор. Потому и возникла необходимость использования NormalizeDouble() как можно ближе к собственно вычислению, желательно прямо в Условии оператора if, for, while.

Елы-палы, какжется начинаю понимать, к чему весь базар...

В общем и целом, полагаю, НИЧЧЕЕГГО не надо придумывать. Ибо все зависит от КОНКРЕТНОЙ ситуевины. Какая цель? Если два числа отличаться могут мантиссой в 0.1, и если это КРИТИЧНО, - один коленкор. если не важно - другой. Смотря что сравнивать друг с другом. Но ГИБКОСТЬ, которую дает ОБЫЧНЫЙ компилятор без выкрутасов, - ДОСТАТОЧНАЯ и необходимая вещь, ИМХО.

:)

 
SK. писал (а):
Дело здесь не в точности программного кода, а в технологических особенностях вычислений и в технологических правилах хранения значений переменных. Если бы не это, то и вопрос не возник бы.
С вычислениями это так, а вот с хранением, мне казалось, дело должно обстоять лучше. Да и при digits = 4 отличие в 15-м знаке роли играть не должно.
 
Depfy:

Елы-палы, какжется начинаю понимать, к чему весь базар...

В общем и целом, полагаю, НИЧЧЕЕГГО не надо придумывать. Ибо все зависит от КОНКРЕТНОЙ ситуевины. Какая цель? Если два числа отличаться могут мантиссой в 0.1, и если это КРИТИЧНО, - один коленкор. если не важно - другой. Смотря что сравнивать друг с другом. Но ГИБКОСТЬ, которую дает ОБЫЧНЫЙ компилятор без выкрутасов, - ДОСТАТОЧНАЯ и необходимая вещь, ИМХО.

:)


Насчёт "придумывать" не могу ответить. Видимо, это зависит от того, о чём думать:)

Например, придумывания типа Point/2 действительно в ряде случаев позволяют вести вычисления с некоторой заданной точностью. Однако, лучше воспользоваться рекомендацией разработчиков, а именно раз и навсегда (вплоть до новой документации) взять за правило использовать при вычислении операций сравнения штатную функцию NormalizeDouble().

 
lna01:
SK. писал (а):
Дело здесь не в точности программного кода, а в технологических особенностях вычислений и в технологических правилах хранения значений переменных. Если бы не это, то и вопрос не возник бы.
С вычислениями это так, а вот с хранением, мне казалось, дело должно обстоять лучше. Да и при digits = 4 отличие в 15-м знаке роли играть не должно.

Оно и не играет, если использовать NormalizeDouble(). А если не использовать, то как повезёт.