Typenreduzierung

Reduzierung der Zahlentypen  

Oft muss man einen Zahlentyp in den anderen umwandeln. Nicht jeden numerischen Typ kann man in einen anderen umwandeln, zulaessige Reduzierungen in MQL5 werden auf dem Schema gezeigt:

Schema der zugaenglichen Typenreduzierungen

Volllinien mit Richtungszeichen bezeichnen Umwandlungen, die ohne Informationsverlust durchgeführt werden. Anstatt des Typs char kann der Typ bool auftreten(die beiden nehmen 1 Byte des Speicherplatzes ein), anstatt des Typs int kann der Typ color verwendet werden (jeder 4 Byte), anstatt des Typs long ist der Typ datetime zulaessig (jeder 8 Byte). Vier graue Strichlinien auch mit Richtungszeichen bezeichnen Umwandlungen, bei denen der Genauigkeitsverlust entstehen kann. ZB. Zifferzahl in der Ganzzahl 123456789  (int) ist mehr als es vom Typ float vertreten werden kann.

   int n=123456789;
   float f=n;    // Inhalt f ist 1.234567892E8
   Print("n = ",n,"   f = ",f);
   // Ergebnis n= 123456789    f= 123456792.00000

Die Zahl, die in Typ float umgewandelt ist, hat dieselbe Ordnung, aber kleinere Genauigkeit. Die den schwarzen Richtungszeichen entgegengesetzte Umwandlungen können mit Informationsverlust durchgeführt werden. Umwandlungen unter char und uchar, short und ushort, int und uint, long und ulong (gemeint werden gegenseitige Umwandlungen), können zum Informationsverlust führen.

Im Ergebnis der Reduzierung des Fliesspunktwertes zum Bruchwert wird der Bruchteil immer weggelassen. Wen man Fliesspunktzahl zur naechstliegenden Ganzzahl runden muss ( in den meisten Faellen ist es nuetzlicher), muss man die Funktion MathRound() verwenden.

Beispiel:

//--- Fallbeschleunigung 
   double g=9.8;
   double round_g=(int)g;
   double math_round_g=MathRound(g);
   Print("round_g = ",round_g);
   Print("math_round_g = ",math_round_g);
//   Ergebnis:
//   round_g = 9
//   math_round_g = 10

Wenn zwei Werte durch Binaeroperator verbunden werden, wird der Operand des jungeren Typ in den Operand des aelteren Typs umgewandelt laut Prioritaet dezeigt auf dem Schema:

Umwandlungen bei Verbindung durch die binaere Operation

Datentypen char, uchar, short und ushort werden zum Typ int reduziert.

Beispiele:

   char   c1=3;
//--- erstes Beispiel 
   double d2=c1/2+0.3;
   Print("c1/2+0.3 =",d2);
// Ergebnis:   c1/2+0.3 = 1.3
 
//--- zweites Beispiel
   d2=c1/2.0+0.3;
   Print("c1/2.0+0.3 =",d2);
// Ergebnis:   c1/2.0+0.3 = 1.8

Berechnetre Ausdruck besteht aus zwei Operationen. Im ersten Beispiel wird die Variable vom ersten Typ char in die zeitweilige Variable des Typs int  umgewandelt, denn der zweite Operand in Division, Konstante 2, hat einen aelteren Typ int. Im Ergebnis der ganzzahliger Division 3/2 wird der Wert 1, den der Typ int hat.

In zweiter Operation des ersten Beispiels tritt als zweiter Operand Konstante 0.3 auf, die zum Typ double gehört, darum wird das Ergebnis nach der ersten Operation in die zeitweilige Variable des Typs double mit dem Wert 1.0 umgewandelt.

Im zweiten Beispiel wird die Variable vom ersten Typ char in die zitweilige Variable des Typs double umgewandelt, denn der zweite Operand in Division, Konstante 2.0 gehört zum Typ double; weitere Umwandlungen werden nicht durchgeführt.

 

Reduzierung der Zahlentypen

In Ausdrücken der Sprache MQL5 kann explizite und implizite Typenreduzierung verwendet werden. Explizite Typenreduzierung wird auf der Weise geschrieben:

var_1 = (Typ)var_2;

Als Variable var_2 kann Ausdruck oder Ergebnis der Funktion sein. Zulaessig ist auch Funktionsaufschreibung der expliziten Typenreduzierung:

var_1 = Typ(var_2);

Betrachten wir explizite Reduzierung am ersten Beispiel:

//--- drittes Beispiel
   double d2=(double)c1/2+0.3;
   Print("(double)c1/2+0.3 =",d2);
// Ergebnis:   (double)c1/2+0.3 = 1.80000000

Vor Division wird die Variable c1 explizit in den Typ double umgewandelt.  Die derzeit ganzzahlige Konstante 2 wird zum Wert 2.0 des Typs double reduziert, denn während der Umwandlungen bekam der erste Operand den Typ double. Tatsaechlich ist die explizite Typenumwandlung einstellige Operation.

Außerdem kann das Ergebnis bei der Typenreduzierung ausserhalb der zulaessigen Stellenzahl sein. In diesem Fall entsteht Abbruch. ZB.:

   char c;
   uchar u;
   c=400;
   u=400;
   Print("c=",c); // Ergebnis c=-112
   Print("u=",u); // Ergebnis u=144

Vor den Operationen ( ausser Zuordungsoperationen) wird die Umwandlung in den Typ durchgeführt, der die groesste Prioriraet hat, und vor den Zuordnungsoperationen - in den Zieltyp.

Beispiele:

   int    i=1/2;        // keine Typenreduzierung, Ergebnis: 0
   Print("i=1/2  ",i);
 
   int k=1/2.0;         // Ausdruck wird zum Typ double reduziert,
   Print("k=1/2  ",k);  // dann zum Zieltyp int reduziert, Ergebnis: 0
 
   double d=1.0/2.0;    // keine Typenreduzierung, Ergebnis: 0.5
   Print("d=1/2.0; ",d);
 
   double e=1/2.0;      // Ausdruck wird zum Typ double reduziert, 
   Print("e=1/2.0; ",e);// der mit dem Zieltyp zusammenfaellt, Ergebnis: 0.5
 
   double x=1/2;        // Ausdruck des Typs int wird zum Zieltyp double reduziert,
   Print("x=1/2; ",x);  // Ergebnis: 0.0

Wenn Sie Typ long/ulong in double konvertieren, kann Genauigkeit verloren gehen: wenn das Ganze ist größer als 9223372036854774784 oder kleiner als -9223372036854774784.

void OnStart()
  {
   long l_max=LONG_MAX;
   long l_min=LONG_MIN+1;
//--- Finden wir die maximale ganze Zahl, die Genauigkeit beim Gießen zu double nicht verliert
   while(l_max!=long((double)l_max))
      l_max--;
//--- Finden wir die kleinste ganze Zahl, die Genauigkeit beim Gießen zu double nicht verliert
   while(l_min!=long((double)l_min))
      l_min++;
//--- Jetzt zeigen wir das gefundenen Intervall für den ganzen Zahlen  
   PrintFormat("Beim Gießen einer ganzen Zahl zu double sollte es "
               "im folgenden Intervall sein [%I64d, %I64d]",l_min,l_max);
//--- Nun wollen wir sehen, was passiert, wenn die Zahl außerhalb dieses Intervalls ist
   PrintFormat("l_max+1=%I64d, double(l_max+1)=%.f, ulong(double(l_max+1))=%I64d",
               l_max+1,double(l_max+1),long(double(l_max+1)));
   PrintFormat("l_min-1=%I64d, double(l_min-1)=%.f, ulong(double(l_min-1))=%I64d",
               l_min-1,double(l_min-1),long(double(l_min-1)));
//--- erhalten eine solche Schlussfolgerung
// Beim Gießen einer ganzen Zahl zu double sollte es im Intervall [-9223372036854774784, 9223372036854774784] sein
// l_max+1=9223372036854774785, double(l_max+1)=9223372036854774800, ulong(double(l_max+1))=9223372036854774784
// l_min-1=-9223372036854774785, double(l_min-1)=-9223372036854774800, ulong(double(l_min-1))=-9223372036854774784
  }

 
Reduzierung für Typ  string

Typ string hat die hoechste Prioritaet unter einfachen Typen. Darum wenn einer der Operanden den Typ string hat, wird der andere operand zum Typ string authomatisch reduziert. Man muss in Vormerkung behalten, dass es für den Typ string nur einzige zweistellige Operation zulaessig ist. Explizite Reduzierung der Variable des Typs string zum jeden Zahlentyp ist zulaessig.

Beispiele:

   string s1=1.0/8;            // Ausdruck wird zum Typ double reduziert, 
   Print("s1=1.0/8; ",s1);     // dann zum Zieltyp string, 
// Ergebnis:"0.12500000"(Zeile mit 10 Zeichen)
 
   string s2=NULL;             // Deinitialisierung der Zeile 
   Print("s2=NULL; ",s2);      // Ergebnis: Leerzeile
   string s3="Ticket N"+12345; // Ausdruck wird zum Typ string reduziert 
   Print("s=\"Ticket N"+12345,s3);
 
   string str1="true";
   string str2="0,255,0";
   string str3="2009.06.01";
   string str4="1.2345e2";
   Print(bool(str1));
   Print(color(str2));
   Print(datetime(str3));
   Print(double(str4));

 

Reduzierung der Typen von Anzeigern der Basisklassen zu Anzeigern der sekundaeren Klassen

Objekte der sekundaeren Klasse können auch als Objekte der ihr entsprechenden Basisklasse betrachtet werden. Das führt zu einigen interessanten Folgen. ZB. Gegen die Tatsache, dass Objekte verschiedener Klassen, die von einer Basisklasse entstanden, können sich  voneinander unterscheiden, können wir Ihre verbundene Liste erzeugen (List), denn wir betrachten sie als Objekte der Basisklasse. Aber das Gegenteil stimmt nicht: Objekte der Basisklasse sind nicht automatisch Objekte der sekundaeren Klasse.  

Man kann explizite Typenreduzierung verwenden, um die Anzeiger der Basisklasse in die Anzeiger der sekundaeren Klasse umwandeln. Man muss aber ganz sicher sein, dass diese Umwandlung zulaessig ist, sonst entsteht ein kritischer Fehler der Ausführungszeit und das mql5-Programm wird gestoppt.

Dynamische Typumwandlung mithilfe von dynamic_cast #

Es besteht die Möglichkeit einer dynamischen Typumwandlung mithilfe der Anweisung dynamic_cast, die nur an Pointer von Klassen angewendet werden kann. Dabei wird die Korrektheit von Typen während der Ausführung des Programms überprüft. Dies bedeutet, der Compiler überprüft nicht den Datentyp für die Umwandlung, wenn dynamic_cast verwendet wird. Wenn der Pointer in den Typ umgewandelt wird, der kein tatsächlicher Objekttyp ist, hat das Ergebnis den Wert NULL.

dynamic_cast <type-id> ( expression )

Der Parameter type-id in spitzen Klammern muss Pointer auf einen früher definierten Typ der Klasse sein. Der expression Operand kann von jedem Typ sein (im Vergleich zu C++) außer void.

Beispiel:

class CBar { };
class CFoo : public CBar { };
 
void OnStart()
  {
   CBar bar;    
//--- dynamische Typumwandlung des Pointers *bar zum *foo erlaubt
   CFoo *foo = dynamic_cast<CFoo *>(&bar); // kein kritischer Fehler der Ausführung   
   Print(foo);                             // foo=NULL      
//--- Versuch verboten, die Referenz des Objekttyps Bar in den Objekttyp Foo umzuwandeln
   foo=(CFoo *)&bar;                       // kritischer Fehler der Ausführung
   Print(foo);                             // diese Zeile wird nicht ausgeführt
  }

Sehen Sie auch

Datentypen