Tipos reales (double, float)

Los tipos reales (o tipos de punto flotante) representan valores que contienen la parte fraccionaria. En el lenguaje MQL5 existen dos tipos para los números con punto flotante. El modo de representar los números reales en la memoria del ordenador se rige por el estándar IEEE 754 y no depende de las plataformas, sistemas operativos y lenguajes de programación.

Tipo

Tamaño en bytes

Valor mínimo positivo

Valor máximo

Análogo en el lenguaje C++

float

4

1.175494351e-38

3.402823466e+38

float

double

8

2.2250738585072014e-308

1.7976931348623158e+308

double

 

double

El tipo de número real double ocupa 64 bits (1 bit de signo, 11 bits de exponente y 52 bits de mantisa).

float

El tipo de número real float ocupa 32 bits (1 bit de signo, 8 bits de exponente y 23 bits de mantisa).

vector

Array numérico unidimensional del tipo double. La memoria para los datos se asigna dinámicamente. Las propiedades del vector se pueden recuperar usando métodos, y el tamaño del vector se puede cambiar. En las funciones de plantilla se puede utilizar la notación vector<double>.

vectorf

Array numérico unidimensional del tipo float, puede usarse en lugar de vector, si la pérdida de precisión no tiene importancia. En las funciones de plantilla se puede utilizar la notación vector<float>.

vectorc

Array numérico unidimensional del tipo complex, está diseñado para trabajar con números complejos. En las funciones de plantilla se puede utilizar la notación vector<complex>. Las operaciones sobre vectores de tipo vectorc aún no están implementadas.

matrix

Una matriz es un array numérico bidimensional del tipo double. La memoria para los elementos de la matriz se asigna dinámicamente. Las propiedades de la matriz se pueden obtener usando métodos, y el tamaño del vector se puede cambiar. En las funciones de plantilla se puede utilizar la notación matrix<double>.

matrixf

Array numérico bidimensional del tipo float, puede utilizarse en lugar de matrix si la pérdida de precisión no tiene importancia. En las funciones de plantilla se puede utilizar la entrada matrix<float>.

matrixc

Array numérico bidimensional del tipo complex, está diseñado para trabajar con números complejos. En las funciones de plantilla se puede utilizar la notación matrix<complex>. En estos momentos, las operaciones sobre matrices del tipo matrixc aún no están implementadas.

El nombre double significa que la precisión de estos números es dos veces más que la precisión de los números del tipo float. En mayoría de los casos el tipo double es más cómodo. En muchos casos la precisión limitada de los números float simplemente es insuficiente. La razón de utilizar todavía el tipo float se encuentra en el ahorro de la memoria durante el almacenamiento (es importante para las grandes cantidades de matrices de números reales).

Las constantes de punto flotante se componen de la parte entera, punto (.) y parte fraccionaria. La parte entera y fraccionaria es una sucesión de números decimales.

Ejemplos:

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

Existe el modo científico de escribir las constantes reales. A menudo esta modo de escribir es más compacto en comparación con la forma tradicional.

Ejemplo:

   double c1=1.12123515e-25;
   double c2=0.000000000000000000000000112123515; // 24 ceros despues del punto decimal
   
   Print("1. c1 = ",DoubleToString(c1,16));
   // Resultado: 1. c1 = 0.0000000000000000
   
   Print("2. c1 = ",DoubleToString(c1,-16));
   // Resultado: 2. c1 = 1.1212351499999999e-025
 
   Print("3. c2 = ",DoubleToString(c2,-16));
   // Resultado: 3. c2 = 1.1212351499999999e-025

Hay que recordar que los números reales se almacenan en la memoria del ordenador con una cierta precisión limitada en el sistema binario, mientras que el sistema decimal es de uso general. Por eso muchos números que se escriben en el sistema decimal, en el sistema binario pueden ser escritos sólo en forma de fracción contínua.

Por ejemplo, en el ordenador los números 0.3 y 0.7 están representados por las fracciones contínuas, mientras que el número 0.25 se guarda de forma exacta porque es la potencia de 2.

Por esta razón no se recomienda de ninguna manera comparar la igualdad de dos números reales porque esta comparación no es correcta.

Ejemplo:

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");
// Resultado: 1/3 + 4/3 != 5/3
  }

Si en alguna ocasión es necesario comparar la igualdad de dos números reales, entonces se puede hacerlo de dos maneras distintas. El primer modo consiste en la comparación de diferencia entre dos números con un valor pequeño que marca la precisión de comparación.

Ejemplo:

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));
// Resultado: Different: d_val= 0.7000000000000000   f_val= 0.6999999880790710
  }

Cabe mencionar que el valor del parámetro epsilon en el ejemplo de arriba, no puede ser menos que la constante predeterminada DBL_EPSILON. El valor de esta constante es 2.2204460492503131e-016. Para el tipo float la constante correspondiente es FLT_EPSILON = 1.192092896e-07. El sentido de estos valores es siguiente: se trata del valor mínimo que satisface la condición 1.0+DBL_EPSILON != 1.0 (para los números del tipo float 1.0+FLT_EPSILON != 1.0).

El segundo modo supone la comparación de la diferencia normalizada de dos números reales con el valor cero. Es inutil comparar la diferencia de los números normalizados con el cero porque el resultado de cualquier operación matemática con los números normalizados no va a ser normalizado.

Ejemplo:

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));
// Resultado: Different: d_val= 0.3000000000000000   f_val= 0.3000000119209290
  }

Como resultado de algunas operaciones matemáticas del coprocesador se puede obtener un número real extendido, el que no se puede utilizar en las operaciones matemáticas y operaciones de comparación porque el resultado de ejecución de las operaciones con números reales extendidos no está definido. Por ejemplo, tratando de calcular el arcseno de 2 se obtiene el infinito negativo.

Ejemplo:

   double abnormal = MathArcsin(2.0);
   Print("MathArcsin(2.0) =",abnormal);
// Resultado:  MathArcsin(2.0) = -1.#IND

A parte del infinito negativo existe el infinito positivo y NaN (no es un número). Para determinar que el número es extendido se puede utilizar la función MathIsValidNumber(). Según el estándar IEEE ellos tienen una representación informática especial. Por ejemplo, el infinito positivo para el tipo double tiene la representación de bit 0x7FF0 0000 0000 0000.

Ejemplos:

struct str1
  {
   double d;
  };
struct str2
  {
   long l;
  };
 
//--- empecemos 
   str1 s1;
   str2 s2;
//---
   s1.d=MathArcsin(2.0);        // obtenemos número extendido -1.#IND
   s2=s1;
   printf("1.  %f %I64X",s1.d,s2.l);
//---
   s2.l=0xFFFF000000000000;     // número extendido -1.#QNAN
   s1=s2;
   printf("2.  %f %I64X",s1.d,s2.l);
//---
   s2.l=0x7FF7000000000000;     // nonúmero máximo SNaN
   s1=s2;
   printf("3.   %f %I64X",s1.d,s2.l);
//---
   s2.l=0x7FF8000000000000;     // nonúmero mínimo QNaN
   s1=s2;
   printf("4.   %f %I64X",s1.d,s2.l);
//---
   s2.l=0x7FFF000000000000;     // nonúmero máximo QNaN
   s1=s2;
   printf("5.   %f %I64X",s1.d,s2.l);
//---
   s2.l=0x7FF0000000000000;     // infinito positivo 1.#INF y nonúmero mínimo SNaN
   s1=s2;
   printf("6.   %f %I64X",s1.d,s2.l);
//---
   s2.l=0xFFF0000000000000;     // infinito negativo -1.#INF
   s1=s2;
   printf("7.  %f %I64X",s1.d,s2.l);
//---
   s2.l=0x8000000000000000;     // cero negativo -0.0
   s1=s2;
   printf("8.  %f %I64X",s1.d,s2.l);
//---
   s2.l=0x3FE0000000000000;     // 0.5
   s1=s2;
   printf("9.   %f %I64X",s1.d,s2.l);
//---
   s2.l=0x3FF0000000000000;     // 1.0
   s1=s2;
   printf("10.  %f %I64X",s1.d,s2.l);
//---
   s2.l=0x7FEFFFFFFFFFFFFF;     // número máximo normalizado (MAX_DBL)
   s1=s2;
   printf("11.  %.16e %I64X",s1.d,s2.l);
//---
   s2.l=0x0010000000000000;     // mínimo normalizado positivo (MIN_DBL)
   s1=s2;
   printf("12.  %.16e %.16I64X",s1.d,s2.l);
//---
   s1.d=0.7;                    // indicamos que el número 0.7 — es una fracción contínua
   s2=s1;
   printf("13.  %.16e %.16I64X",s1.d,s2.l);
/*
1.  -1.#IND00 FFF8000000000000
2.  -1.#QNAN0 FFFF000000000000
3.   1.#SNAN0 7FF7000000000000
4.   1.#QNAN0 7FF8000000000000
5.   1.#QNAN0 7FFF000000000000
6.   1.#INF00 7FF0000000000000
7.  -1.#INF00 FFF0000000000000
8.  -0.000000 8000000000000000
9.   0.500000 3FE0000000000000
10.  1.000000 3FF0000000000000
11.  1.7976931348623157e+308 7FEFFFFFFFFFFFFF
12.  2.2250738585072014e-308 0010000000000000
13.  6.9999999999999996e-001 3FE6666666666666 
*/

Véase también

DoubleToString, NormalizeDouble, Constantes de tipos numéricos