411 lines
13 KiB
MQL5
411 lines
13 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| bitconvert.mqh |
| |||
//| Copyright 2003-2022 Sergey Bochkanov (ALGLIB project) |
| |||
//| Copyright 2012-2023, MetaQuotes Ltd. |
| |||
//| https://www.mql5.com |
| |||
//+------------------------------------------------------------------+
| |||
//| Implementation of ALGLIB library in MetaQuotes Language 5 |
| |||
//| |
| |||
//| The features of the library include: |
| |||
//| - Linear algebra (direct algorithms, EVD, SVD) |
| |||
//| - Solving systems of linear and non-linear equations |
| |||
//| - Interpolation |
| |||
//| - Optimization |
| |||
//| - FFT (Fast Fourier Transform) |
| |||
//| - Numerical integration |
| |||
//| - Linear and nonlinear least-squares fitting |
| |||
//| - Ordinary differential equations |
| |||
//| - Computation of special functions |
| |||
//| - Descriptive statistics and hypothesis testing |
| |||
//| - Data analysis - classification, regression |
| |||
//| - Implementing linear algebra algorithms, interpolation, etc. |
| |||
//| in high-precision arithmetic (using MPFR) |
| |||
//| |
| |||
//| This file is free software; you can redistribute it and/or |
| |||
//| modify it under the terms of the GNU General Public License as |
| |||
//| published by the Free Software Foundation (www.fsf.org); either |
| |||
//| version 2 of the License, or (at your option) any later version. |
| |||
//| |
| |||
//| This program is distributed in the hope that it will be useful, |
| |||
//| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |||
//| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |||
//| GNU General Public License for more details. |
| |||
//+------------------------------------------------------------------+
| |||
#include "arrayresize.mqh"
| |||
//+------------------------------------------------------------------+
| |||
//| Converting numbers into an array of bits and vice versa |
| |||
//+------------------------------------------------------------------+
| |||
class BitConverter
| |||
{
| |||
public:
| |||
static void GetBytes(const int d,uchar &bytes[]);
| |||
static void GetBytes(const double d,uchar &bytes[]);
| |||
static int ToInt32(uchar &bytes[]);
| |||
static double ToDouble(uchar &bytes[]);
| |||
static bool IsLittleEndian(void);
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
//| Converting integer to a byte array |
| |||
//+------------------------------------------------------------------+
| |||
void BitConverter::GetBytes(const int d,uchar &bytes[])
| |||
{
| |||
//--- create variables
| |||
int x;
| |||
int q;
| |||
int r;
| |||
int i;
| |||
int div;
| |||
//--- allocation
| |||
ArrayResize(bytes,4);
| |||
for(i=0; i<4; i++)
| |||
{
| |||
//--- check
| |||
if(d>=0)
| |||
bytes[i]=0;
| |||
else
| |||
bytes[i]=255;
| |||
}
| |||
//--- initialization
| |||
q=-1;
| |||
r=-1;
| |||
i=3;
| |||
div=256*256*256;
| |||
//--- check
| |||
if(d<0)
| |||
x=~d;
| |||
else
| |||
x=d;
| |||
//--- converting number
| |||
while(i!=-1)
| |||
{
| |||
//--- quotient
| |||
q=x/div;
| |||
//--- remainder of division
| |||
r=x%div;
| |||
//--- get byte
| |||
if(d>=0)
| |||
bytes[i]+=(uchar)q;
| |||
else
| |||
bytes[i]-=(uchar)q;
| |||
//--- the next iteration is reduced divisor
| |||
x=r;
| |||
div=div/256;
| |||
i--;
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Converting double to a byte array |
| |||
//+------------------------------------------------------------------+
| |||
void BitConverter::GetBytes(const double d,uchar &bytes[])
| |||
{
| |||
//--- module
| |||
double abs_d=MathAbs(d);
| |||
//--- number without its fractional
| |||
double floor_d=MathFloor(abs_d);
| |||
//--- fractional part
| |||
double fractional_d=abs_d-floor_d;
| |||
//--- variable will store the degree
| |||
int power;
| |||
//--- exponent shift
| |||
double exp_shift;
| |||
//--- create variables
| |||
int k;
| |||
int j;
| |||
uchar u;
| |||
double step;
| |||
double f;
| |||
//--- abs_d as bits
| |||
bool abs_d_to_bitArray[];
| |||
//--- d as bits in format IEEE 754
| |||
bool d_to_bitArray[];
| |||
//--- allocation
| |||
ArrayResizeAL(d_to_bitArray,64);
| |||
ArrayResizeAL(bytes,8);
| |||
//--- initialization
| |||
power=0;
| |||
//--- for integer part
| |||
while(1)
| |||
{
| |||
//--- if the number is less than or equal floor_d, we increase the degree
| |||
//--- if 2^power > floor_d, then maximal number < floor_d - it 2^(power-1)
| |||
if(floor_d>=MathPow(2,power))
| |||
power++;
| |||
else
| |||
break;
| |||
}
| |||
//--- get power-1
| |||
power--;
| |||
//--- if power=-1, then floor_d=0
| |||
//--- find a negative power for the fractional part
| |||
if(power==-1)
| |||
{
| |||
power=0;
| |||
while(1)
| |||
{
| |||
//--- the same principle as above
| |||
if(fractional_d<MathPow(2,power))
| |||
power--;
| |||
else
| |||
break;
| |||
}
| |||
}
| |||
//--- convert decimal to binary
| |||
j=0;
| |||
step=power;
| |||
while(abs_d!=0.0)
| |||
{
| |||
f=MathPow(2,step);
| |||
//--- check
| |||
if(f>abs_d)
| |||
{
| |||
//--- if abs_d < f - this bit is zero
| |||
ArrayResize(abs_d_to_bitArray,j+1);
| |||
abs_d_to_bitArray[j]=0;
| |||
j++;
| |||
step-=1;
| |||
}
| |||
else
| |||
{
| |||
//--- if abs_d >= f, then this bit is equal one
| |||
//--- reduction abs_d
| |||
abs_d-=f;
| |||
ArrayResize(abs_d_to_bitArray,j+1);
| |||
abs_d_to_bitArray[j]=1;
| |||
j++;
| |||
step-=1;
| |||
}
| |||
}
| |||
//--- according to IEEE 754,
| |||
//--- zero bit determines sign of the number, 0 -> '+', 1 -> '-'.
| |||
if(d>=0)
| |||
d_to_bitArray[0]=0;
| |||
else
| |||
d_to_bitArray[0]=1;
| |||
//--- offset input
| |||
exp_shift=1023+power;
| |||
//--- bits from the first and 11 are reserved for the shifted exponential
| |||
j=1;
| |||
for(int i=10; i>=0; i--)
| |||
{
| |||
if(MathPow(2,i)>exp_shift)
| |||
d_to_bitArray[j]=0;
| |||
else
| |||
{
| |||
d_to_bitArray[j]=1;
| |||
//--- reduction
| |||
exp_shift-=MathPow(2,i);
| |||
}
| |||
j++;
| |||
}
| |||
//--- Get the length of the array of the binary representation of abs_d
| |||
k=ArraySize(abs_d_to_bitArray);
| |||
j=1;
| |||
//--- Bits from 12 to 63 are filled with binary representation of abs_b
| |||
//--- the first element abs_d_to_bitArray is always 1
| |||
for(int i=12; i<64; i++)
| |||
{
| |||
if(j<k)
| |||
{
| |||
d_to_bitArray[i]=abs_d_to_bitArray[i-11];
| |||
j++;
| |||
}
| |||
else
| |||
d_to_bitArray[i]=0;
| |||
}
| |||
//--- reverse
| |||
ArrayReverse(d_to_bitArray);
| |||
//--- converting bit array to byte array
| |||
for(int i=0; i<8; i++)
| |||
{
| |||
u=0;
| |||
//--- get byte
| |||
for(int t=0; t<8; t++)
| |||
u+=(uchar)(d_to_bitArray[i*8+t]*MathPow(2,t));
| |||
//--- save byte
| |||
bytes[i]=u;
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Converting byte array to a integer |
| |||
//+------------------------------------------------------------------+
| |||
int BitConverter::ToInt32(uchar &bytes[])
| |||
{
| |||
//--- get size
| |||
int size=ArraySize(bytes);
| |||
//--- create variables
| |||
int d=0;
| |||
int mul=256*256*256;
| |||
//--- get number
| |||
for(int i=size-1; i>=0; i--)
| |||
{
| |||
d+=bytes[i]*mul;
| |||
mul=mul/256;
| |||
}
| |||
//--- return result
| |||
return(d);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Converting byte array to a double |
| |||
//+------------------------------------------------------------------+
| |||
double BitConverter::ToDouble(uchar &bytes[])
| |||
{
| |||
//--- create variables
| |||
int s;
| |||
//--- exponent shift
| |||
int e=0;
| |||
//--- mantissa
| |||
double m=0;
| |||
//--- array of bits in IEEE 754
| |||
bool bits[];
| |||
ArrayResize(bits,64);
| |||
//--- get array of bits from array of bytes
| |||
for(int i=0; i<8; i++)
| |||
{
| |||
for(int j=7; j>=0; j--)
| |||
{
| |||
//--- if 2 in power >, bits[i*8+j]=0, else bits[i*8+j]=0
| |||
if(MathPow(2,j)>bytes[i])
| |||
bits[i*8+j]=0;
| |||
else
| |||
{
| |||
bits[i*8+j]=1;
| |||
//--- reduction
| |||
bytes[i]-=(uchar)MathPow(2,j);
| |||
}
| |||
}
| |||
}
| |||
//--- search bits with 1
| |||
bool allzero=true;
| |||
for(int i=0; i<64; i++)
| |||
if(bits[i]==1)
| |||
allzero=false;
| |||
//--- if all bits are 0, then number is 0
| |||
if(allzero==true)
| |||
return(0.0);
| |||
//--- reverse array
| |||
ArrayReverse(bits);
| |||
//--- s-the first bit, determines sign of the number
| |||
s=bits[0];
| |||
//--- calculation exponent shift
| |||
for(int i=10; i>=0; i--)
| |||
e+=(int)(bits[11-i]*MathPow(2,i));
| |||
//--- get mantissa
| |||
for(int i=0; i<52; i++)
| |||
m+=bits[12+i]*MathPow(2,-1-i);
| |||
//--- return result
| |||
return(MathPow(-1,s)*MathPow(2,e-1023)*(1+m));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Byte ordering (forward, backward) |
| |||
//+------------------------------------------------------------------+
| |||
bool BitConverter::IsLittleEndian(void)
| |||
{
| |||
//--- forward
| |||
return(true);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get string from char array |
| |||
//+------------------------------------------------------------------+
| |||
string GetSelectionString(char &buf[],int startIndex,int lenght)
| |||
{
| |||
return(CharArrayToString(buf,startIndex,lenght));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get sign of number |
| |||
//+------------------------------------------------------------------+
| |||
double MathSign(const double x)
| |||
{
| |||
//--- if x>0
| |||
if(x>0)
| |||
return(1);
| |||
//--- if ?==0
| |||
if(x==0)
| |||
return(0);
| |||
//--- ?<0
| |||
return(-1);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Structure stores a variable of type double |
| |||
//+------------------------------------------------------------------+
| |||
union UDoubleValue
| |||
{
| |||
double value;
| |||
long bits;
| |||
| |||
UDoubleValue(double dbl): value(dbl) { }
| |||
UDoubleValue(long bit_value): bits(bit_value) { }
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
//| Work with infinity and NaN |
| |||
//+------------------------------------------------------------------+
| |||
class CInfOrNaN
| |||
{
| |||
public:
| |||
//--- checks
| |||
static bool IsPositiveInfinity(const double x);
| |||
static bool IsNegativeInfinity(const double x);
| |||
static bool IsInfinity(const double x);
| |||
static bool IsNaN(const double x);
| |||
//--- generation values
| |||
static double PositiveInfinity(void);
| |||
static double NegativeInfinity(void);
| |||
static double NaN(void);
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
//| Check for +inf |
| |||
//+------------------------------------------------------------------+
| |||
bool CInfOrNaN::IsPositiveInfinity(const double x)
| |||
{
| |||
UDoubleValue val=x;
| |||
//--- check
| |||
return(val.bits==0x7FF0000000000000);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Check for -inf |
| |||
//+------------------------------------------------------------------+
| |||
bool CInfOrNaN::IsNegativeInfinity(const double x)
| |||
{
| |||
UDoubleValue val=x;
| |||
//--- check
| |||
return(val.bits==0xFFF0000000000000);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Check for +-inf |
| |||
//+------------------------------------------------------------------+
| |||
bool CInfOrNaN::IsInfinity(const double x)
| |||
{
| |||
return(MathClassify(x)==FP_INFINITE);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Check for NaN |
| |||
//+------------------------------------------------------------------+
| |||
bool CInfOrNaN::IsNaN(const double x)
| |||
{
| |||
return(MathClassify(x)==FP_NAN);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Return +inf |
| |||
//+------------------------------------------------------------------+
| |||
double CInfOrNaN::PositiveInfinity(void)
| |||
{
| |||
UDoubleValue val(0x7FF0000000000000);
| |||
return(val.value);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Return -inf |
| |||
//+------------------------------------------------------------------+
| |||
double CInfOrNaN::NegativeInfinity(void)
| |||
{
| |||
UDoubleValue val(0xFFF0000000000000);
| |||
return(val.value);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Return NaN |
| |||
//+------------------------------------------------------------------+
| |||
double CInfOrNaN::NaN(void)
| |||
{
| |||
UDoubleValue val(0x7FFFFFFFFFFFFFFF);
| |||
return(val.value);
| |||
}
| |||
//+------------------------------------------------------------------+
|