- Абсолютное значение числа
- Максимальное и минимальное из двух чисел
- Функции округления
- Деление чисел по модулю
- Степени и корни
- Показательные и логарифмические функции
- Тригонометрические функции
- Гиперболические функции
- Проверка вещественных чисел на нормальность
- Генерация случайных чисел
- Управление порядком байтов в целых числах
Проверка вещественных чисел на нормальность
Поскольку вычисления с вещественными числами допускают возникновение нештатных ситуаций, таких как выход за пределы области определения функции, получение математической бесконечности, потеря порядка и других, результат может содержать не число, а некое специальное значение, фактически описывающее характер проблемы. Все такие специальные значения имеют обобщающее название "не число" (Not A Number, NaN).
В предыдущих разделах книги мы их уже встречали. В частности, при выводе в журнал (см. раздел Числа в строки и обратно) они отображаются в виде текстовых меток (например, nan(ind), +inf и т.д.). Еще одной особенностью является то, что единственного значения NaN среди операндов какого-либо выражения достаточно, чтобы всё выражение перестало правильно рассчитываться и начало давать результат NaN. Исключение составляют только "не числа", представляющие плюc/минус бесконечности: если на них что-то разделить, получится ноль. Однако и здесь есть ожидаемое исключение: если разделить бесконечность на бесконечность, опять получим NaN.
Поэтому в программах важно определять момент, когда в расчетах появляется NaN, и обрабатывать ситуацию особым образом: сигнализировать об ошибке, подставлять некое приемлемое значение по умолчанию или повторять расчет с другими параметрами (например, уменьшить точность/шаг итеративного алгоритма).
В MQL5 есть 2 функции, которые позволяют проанализировать вещественное число на нормальность: MathIsValidNumber выдает простой ответ — да (true) или нет (false), а MathClassify производит более подробную категоризацию.
На физическом уровне все специальные значения кодируются в числе особым сочетанием битов, которое не используется для представления обычных чисел. Для типов double и float эти кодировки, разумеется, отличаются. Попробуем "заглянуть за кулисы" double (как более востребованного, чем float).
В разделе Вложенные шаблоны мы создали класс Converter, который позволял переключать представление за счет совмещения двух разных типов в объединении. Воспользуемся этим классом, чтобы изучить битовое устройство NaN.
Для удобства перенесем класс в отдельный заголовочный файл ConverterT.mqh. В тестовом скрипте MathInvalid.mq5 подключим этот mqh-файл и создадим экземпляр конвертера для связки типов double/ulong (порядок следования не важен, конвертер способен работать в обе стороны).
static Converter<ulong,double> NaNs; |
Сочетание битов в NaN стандартизовано, поэтому возьмем несколько общеупотребительных значений, представленных константами ulong, и посмотрим, как на них реагируют встроенные функции.
// основные NaN
|
Как и ожидалось, результаты совпали.
Давайте познакомимся с формальным описанием функций MathIsValidNumber и MathClassify, а затем продолжим тесты.
bool MathIsValidNumber(double value)
Функция проверяет корректность действительного числа. Параметр может быть типа double или float. Результат true означает правильное число, а false — "не число" (одна из разновидностей NaN).
ENUM_FP_CLASS MathClassify(double value)
Функция возвращает категорию вещественного числа (типа double или float) — одно из значений перечисления ENUM_FP_CLASS:
- FP_NORMAL — нормальное число;
- FP_SUBNORMAL — число меньше, чем минимально представимое в нормализованном виде (например, для типа double это значения меньше DBL_MIN, 2.2250738585072014e-308); потеря порядка (точности);
- FP_ZERO — ноль (положительный или отрицательный);
- FP_INFINITE — бесконечность (положительная или отрицательная);
- FP_NAN — все прочие виды "не чисел" (подразделяются на семейства "тихих" и "сигнальных" NaN).
"Сигнальные" NaN отсутствуют в MQL5. Они используются в механизме исключений (exceptions), который позволяет перехватывать и реагировать на критические ошибки внутри программы. В MQL5 такого механизма нет, поэтому, если случается, например, деление на 0, MQL-программа просто завершает свою работу (экстренно выгружается с графика).
"Тихих" NaN может быть много, и вы можете их конструировать с помощью конвертера, чтобы дифференцированно обозначать и обрабатывать нестандартные состояния в своих вычислительных алгоритмах.
Выполним несколько вычислений в MathInvalid.mq5, чтобы наглядно увидеть, каким образом могут получиться числа различных категорий.
// вычисления с double
|
Мы можем использовать конвертер в обратную сторону: по значению double получать его битовое представление и тем самым детектировать "не числа":
PrintFormat("%I64X", NaNs[MathSqrt(-1.0)]); // FFF8000000000000
|
Функция PrintFormat аналогична StringFormat, единственное отличие в том, что результат сразу выводится в журнал, а не в строку.
Наконец убедимся, что "не числа" всегда не равны:
// NaN != NaN всегда true
|
Для получения NaN или бесконечности в MQL5 существует способ, основанный на приведении строк "nan" и "inf" к double.
double nan = (double)"nan";
|