Типы данных

Типы данных

Любая программа оперирует данными. Данные могут быть различных типов в зависимости от назначения. Например, для доступа к элементам массива используются данные целочисленного типа. Ценовые данные имеют тип двойной точности с плавающей точкой. Это связано с тем, что в языке MQL5 не предусмотрено специального типа для ценовых данных.

Данные разного типа обрабатываются с разной скоростью. Целочисленные данные обрабатываются быстрее всего. Для обработки данных двойной точности используется специальный сопроцессор. Однако из-за сложности внутреннего представления данных с плавающей точкой, они обрабатывается дольше, чем целочисленные.

Дольше всего обрабатываются строковые данные. Это связано с динамическим распределением-перераспределением оперативной памяти компьютера.

Основные типы данных:

  • целые (char, short, int, long, uchar, ushort, uint, ulong)
  • логические (bool)
  • литералы (ushort)
  • строки (string)
  • с плавающей точкой (double, float)
  • цвет (color)
  • дата и время (datetime)
  • перечисления (enum)

Сложные типы данных:

  • структуры;
  • классы.

В терминах OOП сложные типы данных называются абстрактными типами данных.

Типы color и datetime имеют смысл только для удобства представления и ввода параметров, задаваемых извне — из таблицы свойств советника или пользовательского индикатора (вкладка «Inputs»). Данные типов color и datetime представляются в виде целых чисел. Целые типы вместе с типами с плавающей точкой называются арифметическими (числовыми) типами.

В выражениях используется неявное приведение типов, если не указано явное приведение.

Целые типы

Целые типы представлены в языке MQL5 одиннадцатью видами. Некоторые из типов могут использоваться вместе с другими, если этого требует логика программы, но при этом необходимо иметь ввиду правила преобразования типов.

В таблице приведены характеристики каждого типа. Кроме того, в последнем столбце для каждого типа указан соответствующий тип в языке программирования C++.

Тип

Размер в байтах

Минимальное значение

Максимальное значение

Аналог в языке С++

char

1

-128

127

char

uchar

1

0

255

unsigned char, BYTE

bool

1

0(false)

1(true)

bool

short

2

-32 768

32 767

short, wchar_t

ushort

2

0

65 535

unsigned short, WORD

int

4

— 2 147 483 648

2 147 483 647

int

uint

4

0

4 294 967 295

unsigned int, DWORD

color

4

-1

16 777 215

int, COLORREF

long

8

-9 223 372 036 854 775 808

9 223 372 036 854 775 807

__int64

ulong

8

0

18 446 744 073 709 551 615

unsigned __int64

datetime

8

0 (1970.01.01 0:00:00)

32 535 244 799 (3000.12.31 23:59:59)

__time64_t

Значения целых типов можно также представлять в виде числовых констант, цветовых литералов, литералов даты-времени, символьных констант и перечислений.

Вещественные типы (double, float)

Вещественные типы (или типы с плавающей точкой) представляют значения, имеющие дробную часть. В языке MQL5 есть два типа для чисел с плавающей точкой. Способ представления вещественных чисел в машинной памяти определен стандартом IEEE 754 и не зависит от платформ, операционных систем и языков программирования.

Тип

Размер в байтах

Минимальное положительное значение

Максимальное значение

Аналог в С++

float

4

1.175494351e-38

3.402823466e+38

float

double

8

2.2250738585072014e-308

1.7976931348623158e+308

double

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

Константы с плавающей точкой состоят из целой части, точки (.) и дробной части. Целая и дробная части представляют собой последовательности десятичных цифр.

Примеры:

double a=12.111; 
double b=-956.1007; 
float c =0.0001; 
float d =16;

Существует научный способ записи вещественных констант, зачастую этот способ записи более компактный, чем традиционный.

Пример:

double c1=1.12123515e-25; 
double c2=0.000000000000000000000000112123515; // 24 нуля после десятичной точки 
Print("1. c1 = ",DoubleToString(c1,16));       // Результат: 1. c1 = 0.0000000000000000 
Print("2. c1 = ",DoubleToString(c1,-16));      // Результат: 2. c1 = 1.1212351499999999e-025 
Print("3. c2 = ",DoubleToString(c2,-16));      // Результат: 3. c2 = 1.1212351499999999e-025

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

Например, числа 0.3 и 0.7 представлены в компьютере бесконечными дробями, в то время как число 0.25 хранится точно, так как представляет из себя степень двойки.

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

Пример:

void OnStart() 
{
  //--- double three=3.0; 
  double x,y,z; 
  x=1/three; 
  y=4/three; 
  z=5/three; 

  if(x+y==z) 
    Print("1/3 + 4/3 == 5/3"); 
  else Print("1/3 + 4/3 != 5/3"); 

  // Результат: 1/3 + 4/3 != 5/3 
}

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

Пример:

bool EqualDoubles(double d1,double d2,double epsilon)
{
   if(epsilon<0) epsilon=-epsilon;  
   //---
   if(d1-d2>epsilon) return false;
   if(d1-d2<-epsilon) return false;
   //---
   return true;
}

void OnStart()
{
   double d_val=0.7;
   float f_val=0.7;
   if(EqualDoubles(d_val,f_val,0.000000000000001)) Print(d_val,"equals",f_val);
   else Print("Different: d_val = ",DoubleToString(d_val,16), " f_val = ",DoubleToString(f_val,16));

   // Результат: Different: d_val= 0.7000000000000000 f_val= 0.6999999880790710
}

Необходимо отметить, что значение параметра epsilon в приведенном примере не может быть меньше предопределенной константы DBL_EPSILON. Значение этой константы  2.2204460492503131e-016. Для типа float соответствующая константа FLT_EPSILON = 1.192092896e-07. Смысл этих значений таков, что это наименьшее значение, удовлетворяющее условию 1.0+DBL_EPSILON != 1.0 (для чисел типа float 1.0+FLT_EPSILON != 1.0).

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

Пример:

bool CompareDoubles(double number1,double number2)
{
   if(NormalizeDouble(number1-number2,8)==0) return(true);
   else return(false);
}

void OnStart()
{
   double d_val=0.3;
   float f_val=0.3;
   if(CompareDoubles(d_val,f_val)) Print(d_val,"equals",f_val);
   else Print("Different: d_val = ",DoubleToString(d_val,16), " f_val = ",DoubleToString(f_val,16));

   // Результат: Different: d_val= 0.3000000000000000 f_val= 0.3000000119209290
}

 

В результате некоторых операций математического сопроцессора может получиться недействительное вещественное число, которое нельзя использовать в математических операциях и операциях сравнения, так как результат выполнения операций над недействительными вещественными числами неопределен. Например, при попытке вычислить арксинус от 2, результатом будет минус бесконечность.

Пример:

 double abnormal = MathArcsin(2.0);
 Print("MathArcsin(2.0) =",abnormal);
 // Результат: MathArcsin(2.0) = -1.#IND

Кроме минус бесконечности существуют плюс бесконечность и NaN (не число). Чтобы определить, что данное число недействительно, можно использовать функцию MathIsValidNumber(). По стандарту IEEE они имеют специальное машинное представление. Например, плюс бесконечность для типа double имеет битовое представление 0x7FF0 0000 0000 0000.

 

Тип string

Тип string предназначен для хранения текстовых строк. Текстовая строка представляет собой последовательность символов в формате Unicode с завершающим нулем на конце. string-переменной может быть назначена строковая константа. Строковая константа представляет собой последовательность символов Unicode, заключенную в двойные кавычки: «Это строковая константа».

Если необходимо ввести в строку двойную кавычку («), то перед ней надо поставить символ обратной косой черты (\). В строку могут быть введены любые специальные символьные константы, перед которыми стоит символ обратной косой черты (\).

Пример:

string svar="This is a character string";
string svar2=StringSubstr(svar,0,4);
Print("Символ копирайта\t\x00A9");
FileWrite(handle,"эта строка содержит символ перевода строки \n");
string MT5path="C:\Program Files\MetaTrader 5";

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

//--- объявим длинную константную строку
 string HTML_head="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""
                  " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
                  "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
                  "<head>\n"
                  "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"
                  "<title>Trade Operations Report</title>\n"
                  "</head>";

 //--- выведем в журнал константную строку
 Print(HTML_head);