Przy konwersji jawnej programista w kontrolowany sposób dokonuje przemiany typu zmiennej. Schemat takiej konwersji wygląda w następujący sposób (kod 1).
variable_1 = (nowy_typ)variable_2;
Dopuszczalny jest rownież następujący zapis konwersji jawnej (kod 2).
variable_1 = nowy_typ(variable_2);
Jako variable_2 może występować zmienna lub np. wynik obliczenia matematycznego lub działania funkcji (kod 3).
#property strict
void OnStart()
{
int Int_value;
long Long_value;
short Short_value = 5555;
Int_value = (int)Short_value; /* konwersja jawna zmiennej Short_value do typu int
i przypisanie wartości innej zmiennej Int_value */
Long_value = (long)MathMax(1, 33); /* funkcja MathMax znajduje maksymalną wartość
z dwóch liczb (1 i 33), następnie ta liczba
w jawny sposób zostaje przekonwertowana na typ long */
Print("Int_value = ", Int_value);
Print("Long_value = ", Long_value);
}
W poprzednim rozdziale zaznaczyłem, że w niektórych przypadkach konwersji możliwa jest utrata informacji. Chodzi tu przede wszystkim o to, że jeśli spróbujemy "zapakować" liczbę do typu, który nie służy do przechowywania tej liczby w pamięci RAM, to komputer przypisze zmiennej niepoprawną wartość (kod 4).
#property strict
void OnStart()
{
char Char_value_1 = -111; // liczba -111 mieści się w granicach typu char (od -128 do 127)
char Char_value_2 = 222; // 222 nie mieści się w granicach typu char
ushort Ushort_value_1 = -111; // -111 nie mieści się w granicach typu ushort (od 0 do 65535)
ushort Ushort_value_2 = 50000; // 50000 mieści się w granicach typu ushort
Print("Char_value_1 = ", Char_value_1);
Print("Char_value_2 = ", Char_value_2);
Print("Ushort_value_1 = ", Ushort_value_1);
Print("Ushort_value_2 = ", Ushort_value_2);
}
Po uruchomieniu tego skryptu w MetaTrader4 w logach terminala zobaczymy następujące komunikaty (rys 1).
Rys. 1. Konwersja liczb typów całkowitych.
Tutaj w przypadku zmiennych Char_value_2 i Ushort_value_1 widzimy efekt utraty informacji. W kodzie źródłowym Char_value_2 spróbowaliśmy przypisać liczbę 222, która nie mieści się w granicach typu char (od -128 do 127) i program wyświetlił wartość (minus) -34. Z kolei zmiennej Ushort_value_1 spróbowaliśmy przypisać liczbę -111, też spoza zakresu obsługiwanego przez typ ushort (od 0 do 65535), w skutek czego utracono prawidłową wartość i program wyświetlił inną wartość 65425.
Taki samy efekt utraty informacji można otrzymać w procesie konwersji liczby do innego typu o niewłaściwym zakresie (kod 5).
#property strict
void OnStart()
{
char Char_value = -111;
ushort Ushort_value = (ushort)Char_value; // konwersja jawna liczby typu char do typu ushort
short Short_value = (short)Char_value; // konwersja jawna liczby typu char do typu short
Print("Char_value = ", Char_value);
Print("Ushort_value = ", Ushort_value);
Print("Short_value = ", Short_value);
}
W powyższym skrypcie podjęto próbę konwersji liczby -111 typu char do typów ushort i short. Wiemy już, że typ ushort nie służy do przechowywania liczb ujemnych, dlatego po uruchomieniu tego skryptu w MT4 w logach terminala znowu zobaczymy nieprawidłową liczbę 65425 (rys. 2). Z kolei konwersja do typu short przebiegnie prawidłowo i zobaczymy liczbę -111.
Rys. 2. Konwersja liczb typów całkowitych.
Nie zawsze konwersja liczby z jednego typu do innego typu o mniejszym zakresie musi się skończyć utratą informacji. W kolejnym przykładzie (kod 6) liczbę 50000 typu ulong przemienimy na pozostałe typy liczb całkowitych.
#property strict
void OnStart()
{
ulong Ulong_value = 50000;
long Long_value = (long)Ulong_value; // ok
uint Uint_value = (uint)Ulong_value; // ok
int Int_value = (int)Ulong_value; // ok
ushort Ushort_value = (ushort)Ulong_value; // ok
short Short_value = (short)Ulong_value; /* 50000 nie mieści się w granicach
typu short (od -32768 do 32767) */
uchar Uchar_value = (uchar)Ulong_value; /* 50000 nie mieści się w granicach
typu uchar (od 0 do 255) */
char Char_value = (char)Ulong_value; /* 50000 nie mieści się w granicach
typu char (od -128 do 127) */
Print("Ulong_value = ", Ulong_value);
Print("Long_value = ", Long_value);
Print("Uint_value = ", Uint_value);
Print("Int_value = ", Int_value);
Print("Ushort_value = ", Ushort_value);
Print("Short_value = ", Short_value);
Print("Uchar_value = ", Uchar_value);
Print("Char_value = ", Char_value);
}
Na rysunku 3 widzimy wynik działania tych konwersji.
Rys. 3. Konwersja liczb typów całkowitych.
Widzimy, że problem z utratą informacji pojawia się tylko wtedy, gdy próbujemy "zapakować" liczbę do typu, który nie służy do przechowywania tej liczby. W powyższym przykładzie liczba 50000 nie pasuje do typów short, uchar i char.
Jeśli zaistnieje potrzeba konwersji liczby typu całkowitego do typu zmiennoprzecinkowego, to proponuję robić to do typu double (kod 7).
#property strict
void OnStart()
{
int Int_value = 123456789;
float Float_value = (float)Int_value; // konwersja jawna int do float
double Double_value = (double)Int_value; // konwersja jawna int do double
Print("Int_value = ", Int_value);
Print("Float_value = ", Float_value);
Print("Double_value = ", Double_value);
}
Tutaj typ float nie poradził sobie dobrze z obróbką liczby 123456789, a double prawidłowo wykonał to zadanie (rys 4).
Rys. 4. Konwersja liczby typu całkowitego do typy liczby zmiennoprzecinkowej.
W przypadku konwersji liczby zmiennoprzecinkowej do liczby całkowitej, część dziesiętna zawsze jest odrzucana. Jeśli trzeba zaokrąglić liczbę zmiennoprzecinkową do najbliższej liczby całkowitej wtedy należy użyć funkcji MathRound() (kod 8).
#property strict
void OnStart()
{
double A = 1.99999;
double B = -543.21;
int CC = (int)A;
int DD = (int)B;
int EE = (int)MathRound(A);
int GG = (int)MathRound(B);
Print("Konwersja: CC = ", CC);
Print("Konwersja: DD = ", DD);
Print("Zaokrąglenie i konwersja: EE = ", EE);
Print("Zaokrąglenie i konwersja: GG = ", GG);
}
W powyższym skrypcie podczas konwersji liczb 1.99999 oraz -543.21 z typu double do typu int część dziesiętna zostanie odrzucona i nowym zmiennym zostanie przypisana tylko część całkowita tych liczb (CC = 1, DD = -543). Z kolei funkcja MathRound() zaokrągli 1.99999 do 2.0, a potem podczas jawnej konwersji do int liczba 2.0 zostanie przerobione na 2 (EE = 2). W przypadku -543.21 funkcja zaokrągli tę liczbę do -543.0, która następnie zostanie przerobiona na -543 (GG = -543) (rys 5).
Rys. 5. Konwersja liczby typu zmiennoprzecinkowego do typy liczby całkowitej.