. ... есть идеи, как это происходит?
Это связано с внутренней работой функции NormalizeDouble(). Например...
double TestValue = 1.57373; if (TestValue != NormalizeDouble(TestValue, 5)) MessageBox("WTF?");
Кстати, те же результаты получаются, если сделать следующее:
double TestValue = StrToDouble("1.57373"); if (TestValue != NormalizeDouble(TestValue, 5)) MessageBox("WTF?");
После первоначального присвоения TestValue = 1.5737300000000001. NormalizeDouble(..., 5) выдает 1.5737299999999999.
Я знаю, что есть другие способы сделать это, кроме NormalizeDouble ... что я не понимаю, так это почему iClose возвращает значение, которое еще не нормализовано ...
Это связано с внутренней работой функции NormalizeDouble(). Например...
Кстати, те же результаты получаются, если сделать следующее:
После первоначального присвоения TestValue = 1.5737300000000001. NormalizeDouble(..., 5) выдает 1.5737299999999999.
Как же мне заставить TestValue быть равным 1.57373 не > или <?
Итак, как сделать так, чтобы TestValue было равно 1,57373, а не > или <?
Если это еще не ясно, то 1,57373 не может быть представлено точно как значение с плавающей точкой. То же самое справедливо и для таких значений, как 0,1. Единственная странность заключается в том, что функция NormalizeDouble() использует другое приближение, чем другие части языка MQ4.
Ах ... нет, это было неясно ... Я не знал этого. Спасибо, я изучу вопрос.
Ах ... нет, это было неясно ... Я не знал этого. Спасибо, я изучу вопрос.
Значения с плавающей точкой и арифметика быстры, потому что их поддержка встроена в процессор компьютера, но с тем компромиссом, что некоторые значения не могут быть точно представлены в переменной с плавающей точкой. (Пример последствий для скорости см. на сайте https://www.mql5.com/en/forum/116228/page2#156859).
По сути, все, что связано с удвоениями, может привести к ошибке округления. Это приводит к разного рода забавным причудам. Например, 0,1 * 10 = 1,0, но 0,1 + 0,1 + 0,1 + 0,1 + 0,1 + 0,1 + 0,1 + 0,1 + 0,1 + 0,1 = 1,0.
В результате получается, что NormalizeDouble(x, y) не совсем синоним Round(x, y). NormalizeDouble() возвращает наиболее близкое к округленному значению приближение с плавающей точкой. Если вы делаете NormalizeDouble(a, n) == NormalizeDouble(b, n), то вы, по сути, говорите: "равны ли a и b с учетом того, что арифметика с плавающей запятой может вносить различия в округление более чем на n десятичных знаков?".
Как уже многие говорили, NormalizeDouble(a, 5) == NormalizeDouble(b, 5) по сути эквивалентно MathAbs(a - b) < 0.00001, и последнее выполняется немного быстрее. Последний вариант также распространен, потому что он широко используется в языках/платформах, которые не предоставляют удобного эквивалента функции NormalizeDouble(). Но разница в производительности настолько ничтожна, что я бы придерживался NormalizeDouble(), если вы чувствуете, что это делает ваш код более читабельным.
Все это совершенно нормально для языков, в которых есть тип данных double. Единственное, что вносит некоторую собственную и типичную для MQ4 причудливость, это то, что 1.57373 != NormalizeDouble(1.57373, 5). Это извращение, что объявление константы 1.57373 и использование NormalizeDouble() выбирают разные наилучшие приближения значения с плавающей точкой.
Спасибо. :-)
Я знал о проблеме, но не совсем понимал причину и, следовательно, не полностью осознавал возможные последствия.
if (a > b) | if (a - b > Point / 2.) |
if (a >= b) | if (a - b > -Point) |
if (a != b) | if (MathAbs(a - b) > Point / 2.) |
кроме как с нулем никогда не сравнивать двойные числа на равенство
У меня чуть больше сотни строк кода, где я делаю именно это ... и я использовал NormalizeDouble почти на всем, что попадалось на глаза, чтобы заставить его работать надежно. Я понимаю идею ваших предложений, спасибо, но я думаю, что они могут негативно повлиять на читабельность моего кода и, следовательно, на легкость модификации в будущем.
В недалеком будущем я буду модифицировать этот блок кода, чтобы заставить его работать с таймфреймами, отличными от таймфрейма графика, на котором он запущен. Когда я приду к этому, я планирую удалить NormalizeDoubles и заменить его чем-то другим... пока не уверен на 100%, возможно, преобразованием в целые числа перед сравнением...
Спасибо за помощь, как обычно :-)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Я пытаюсь понять нечто странное, что я вижу, чтобы в будущем я мог лучше обойти это в коде...
Я заметил, что с одним из моих индикаторов происходит что-то странное, он не делал того, что должен был делать, поэтому я проверил код, и он выглядел правильным. Поэтому я провел небольшое расследование и в итоге создал небольшой тестовый индикатор.
По сути, это похоже на правду...
... есть идеи, как это происходит?