Оператор NormalizeDouble работает с ошибками? - страница 3

 
stringo писал(а) >>

Дело не в языках программирования, а в способе представления вещественных чисел в платформе Intel.......

.......Представьте ситуацию, когда программист сравнивает вещественные числа с точностью до 300-го знака после запятой, а мы ему в ответ: "числа равны". А?

PS. Назовите хотя бы один "приличный язык программирования, который не позволяет себе подобной неряшливости" на платформе Intel?

Вы имели ввиду, по-видимому, точность представления вещественных чисел. Я-то сравниваю числа после нормализации с четырьмя знаками после точки, так что разрядной сетки у double хватит с лихвой для корректного сравнения.

По поводу языков программирования я, наверное, не прав. Беспроблемных языков не бывает, не может быть в принципе. У каждого свои заморочки. Вопрос в том, как быстро и эффетивно они устраняются. Именно в этой связи я привёл в пример Microsoft. Достаточно оглянуться назад лет на 5 - 10 и сравнить с тем, что мы имеем сегодня. Или разработка и производство Hardware. Фантастический прогресс.

 

После нормализации получается такое же вещественное число со всеми вытекающими. Не все дроби (а наши вещественные числа являются двоичными дробями) являются конечными, и разница между младшими разрядами может не быть единицей в соответствующей степени. Например, константа 0.7 после помещения в сопроцессор становится 0.6999999999999999. Нормализация вещественного числа производится несколькими операциями. В результате нормализации числа, например, 0.703 мы получим 0.7000000000000001. И всё! Два нормализованных числа уже не равны друг другу!

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

 

Так что с функцией ?

её сделают нормальной ?

или только всё сводится к перепискам .

 
stringo писал(а) >>

После нормализации получается такое же вещественное число со всеми вытекающими. Не все дроби (а наши вещественные числа являются двоичными дробями) являются конечными, и разница между младшими разрядами может не быть единицей в соответствующей степени. Например, константа 0.7 после помещения в сопроцессор становится 0.6999999999999999. Нормализация вещественного числа производится несколькими операциями. В результате нормализации числа, например, 0.703 мы получим 0.7000000000000001. И всё! Два нормализованных числа уже не равны друг другу!

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

Спасибо за внимание к проблеме. Выходит, единственный способ - использовать дельту. Впрочем, я так и делаю. Ещё раз спасибо за разъяснение.

 
satop писал(а) >>

Так что с функцией ?

её сделают нормальной ?

или только всё сводится к перепискам .

Повторяю. В результате всё равно получается число типа double. Вопрос упирается в конечность или бесконечность двоичной дроби. Например, дробь 0.5 - конечна, а 0.7 - бесконечна.

0.0 - конечная дробь. Поэтому можно нормализовать остаток от вычитания двух вещественных чисел и сравнивать нормализованный остаток с нулём.

 
stringo >>:

Повторяю. В результате всё равно получается число типа double. Вопрос упирается в конечность или бесконечность двоичной дроби. Например, дробь 0.5 - конечна, а 0.7 - бесконечна.

0.0 - конечная дробь. Поэтому можно нормализовать остаток от вычитания двух вещественных чисел и сравнивать нормализованный остаток с нулём.

Я сделал советник на отложенных ордерах, выставляются два стоповых ордера, вычисление уровня цены идёт через функцию

так при первом запуске советника, первый ордер устанавливается на уровень равный 1.00000, второй правильно устанавливается, затем если удалить ордер, то последующие ордера становятся правильно. Также если советник удалить и поставить опять на эту вал пару то ордера первые устанавливаются верно.

Также использовал обходной вариант автора ветки, всё работает верно.

 
stringo писал(а) >>

Повторяю. В результате всё равно получается число типа double. Вопрос упирается в конечность или бесконечность двоичной дроби. Например, дробь 0.5 - конечна, а 0.7 - бесконечна.

0.0 - конечная дробь. Поэтому можно нормализовать остаток от вычитания двух вещественных чисел и сравнивать нормализованный остаток с нулём.

Вообще назначение функции NormalizeDouble состоит в том, чтобы приближённо вычисленные значения, погрешность которых лежит в последнем разряде двоичной разрядной сетки, округлять с заданным количеством десятичных знаков после точки к ближайшему, заметьте, точному значению, поскольку разрядной сетки для таким образом округлённого значения с гарантией хватает.Так что приближённое число 0.6999999999999999999999 после такого округления должно было бы быть представлено вполне точно в виде, например, 0.7000, если округление было до 4 знаков. Я не вижу проблемы посмотреть ещё раз алгоритм исходника и исправить ошибку, чего Вам и желаю. Можно прожить и без этого, но любая такая "мелочь" приводит к абсолютно транжирскому расходованию мозговых ресурсов, когда, надеясь на правильность основ, ищешь ошибку в своём огороде, а её там нет! Основы, т.е. стандартные, тем более такие простые прграммы, должны работать безукоризненно.

 

Вообще-то, ни один опытный программист ни на одной платформе НИКОГДА не станет писать что-то вида:

if(doubleVal1 == doubleVal2)

{

// ...

}

Это, в общем случае, совершенно непредсказуемый резщультат.

Но что можно сделать (и что нужно делать в таких случаях) - создать функцию-хелпер типа

bool IsDoubleEqual(double dVal1, double dVal2, int nDigits)

которая приводит числа dVal1 и dVal2 к точности nDigits, переводит их в целые числа и уж потом сравнивает.

И это нужно в любом языке программирования а не только в mql4. Инты же везде сравниваются корректно.

 
dokpiknik писал(а) >>

Вообще назначение функции NormalizeDouble состоит в том, чтобы приближённо вычисленные значения, погрешность которых лежит в последнем разряде двоичной разрядной сетки, округлять с заданным количеством десятичных знаков после точки к ближайшему, заметьте, точному значению, поскольку разрядной сетки для таким образом округлённого значения с гарантией хватает.Так что приближённое число 0.6999999999999999999999 после такого округления должно было бы быть представлено вполне точно в виде, например, 0.7000, если округление было до 4 знаков. Я не вижу проблемы посмотреть ещё раз алгоритм исходника и исправить ошибку, чего Вам и желаю. Можно прожить и без этого, но любая такая "мелочь" приводит к абсолютно транжирскому расходованию мозговых ресурсов, когда, надеясь на правильность основ, ищешь ошибку в своём огороде, а её там нет! Основы, т.е. стандартные, тем более такие простые прграммы, должны работать безукоризненно.

Вы, к сожалению, не понимаете. Попробую пояснить (я новичок на этом форуме, но разработчик на разных языках, включая C++ и ранее assembler с 10-летним стажем).

ОС может хранить в памяти число 0.6999999999999999999999999, но не может - 0.7. Зато может, например, с любой точностью хранить 0.0000000000 :)

Это связано с тем, что числа с плавающей точкой в оперативной памяти хранятся лишь _в некотором приближении_, а не в абсолютных своих значениях.

К сожалению, это издержки цифрЫ вообще :) Вещественные числа по сути своей, "континуальны", а их представление в двоичном виде (да еще с ограничением по к-ву байт, необходимых для хранения числа) - "дискретно".

Самая проставя аналогия - фотография на пленку и цифровая фотография :) то же самое.

 
Прошу прощения, что вмешиваюсь. Я новичок в програмировании (стаж создания простых программ около 3 лет). Подскажите я правильно понял? Если взять числа без запятой (7) произвести с ними операцию деления до 1или 2  (или 4) знака  мы все равно полулучим в памяти число типа 0.699999999999999999 и 0.0699999999999999999999 соответственно (далее прербирать не буду) или все таки при использовании округления (норамализации) оно хотя бы после первой операции будет 0.7 и 0.07. Так же возникает вопрос по обходу этой проблемы. Возникает ли этот эффект (т.е. представление числа 0.7 как 0.6999999999999) при  использовании чтения из файла. Поясняю вопрос - если прочитать из текстового файла число 0.7 оно будет использоваться в советнике как 0.7 или как 0.6999999999999.
Причина обращения: