| //+------------------------------------------------------------------+
|
| //| 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);
|
| }
|
| //+------------------------------------------------------------------+
|