跳至内容

Real Types (double, float)

实数类型(双精度浮点型)

实数类型(或浮点型)表示带有小数部分的数值。在MQL4语言中,有两种浮点数的类型。计算机内存中实数的表示方式由IEEE 754标准定义,与平台、操作系统或编程语言无关。

类型字节大小最小正数值最大数值C++对应类型
float41.175494351e-383.402823466e+38float
double82.2250738585072014e-3081.7976931348623158e+308double

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 zero after the decimal point

   Print("1. c1 =",DoubleToString(c1,16));
   // Result: 1. c1 = 0.0000000000000000

   Print("2. c1 =",DoubleToString(c1,-16));
   // Result: 2. c1 = 1.1212351499999999e-025

   Print("3. c2 =",DoubleToString(c2,-16));
   // Result: 3. c2 = 1.1212351499999999e-025

需要注意的是,实数在内存中以二进制系统的有限精度存储,而通常使用十进制表示法。这就是为什么许多在十进制系统中精确表示的数值在二进制系统中只能表示为无限小数。

例如,0.3和0.7在计算机中表示为无限小数,而0.25则被精确存储,因为它代表2的幂。

在这方面,强烈建议不要比较两个实数是否相等,因为这样的比较是不正确的。

示例:

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

数学协处理器的一些操作可能会导致无效的实数,这些数不能用于数学运算和比较,因为无效实数运算的结果是不确定的。例如,尝试计算反正弦时,结果就是负无穷大。

示例:

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

除了负无穷大还有正无穷大和NaN(非数字)。要确定一个数是无效的,可以使用MathIsValidNumber()。根据IEEE标准,它们有特殊的机器表示方式。例如,double类型的正无穷大以0x7FF0 0000 0000 0000的位表示形式表示。

示例:

struct str1
  {
   double d;
  };
struct str2
  {
   long l;
  };

//--- Start
   str1 s1;
   str2 s2;
//---
   s1.d=MathArcsin(2.0);        // Get the invalid number -1.#IND
   s2=s1;
   printf("1.  %f %I64X",s1.d,s2.l);
//---
   s2.l=0xFFFF000000000000;     // invalid number -1.#QNAN
   s1=s2;
   printf("2.  %f %I64X",s1.d,s2.l);
//---
   s2.l=0x7FF7000000000000;     // greatest non-number SNaN
   s1=s2;
   printf("3.   %f %I64X",s1.d,s2.l);
//---
   s2.l=0x7FF8000000000000;     // smallest non-number QNaN
   s1=s2;
   printf("4.   %f %I64X",s1.d,s2.l);
//---
   s2.l=0x7FFF000000000000;     // greatest non-number QNaN
   s1=s2;
   printf("5.   %f %I64X",s1.d,s2.l);
//---
   s2.l=0x7FF0000000000000;     // Positive infinity 1.#INF and smallest non-number SNaN
   s1=s2;
   printf("6.   %f %I64X",s1.d,s2.l);
//---
   s2.l=0xFFF0000000000000;     // Negative infinity -1.#INF
   s1=s2;
   printf("7.  %f %I64X",s1.d,s2.l);
//---
   s2.l=0x8000000000000000;     // Negative zero -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;     // Greatest normalized number (MAX_DBL)
   s1=s2;
   printf("11.  %.16e %I64X",s1.d,s2.l);
//---
   s2.l=0x0010000000000000;     // Smallest positive normalized (MIN_DBL)
   s1=s2;
   printf("12.  %.16e %.16I64X",s1.d,s2.l);
//---
   s1.d=0.7;                    // Show that the number of 0.7 - endless fraction
   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
*/

另请参阅

DoubleToString, NormalizeDouble, 数值类型常量

最后更新于