2549 lines
88 KiB
MQL5
2549 lines
88 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| ap.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 <Object.mqh>
| |||
#include "matrix.mqh"
| |||
#include "bitconvert.mqh"
| |||
//---
| |||
#define IsPosInf(value) (AL_POSINF==value)
| |||
#define IsNegInf(value) (AL_NEGINF==value)
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
double AL_NaN =CInfOrNaN::NaN(); //---AL_NaN
| |||
double AL_POSINF=CInfOrNaN::PositiveInfinity(); //---+infinity 1.#INF
| |||
double AL_NEGINF=CInfOrNaN::NegativeInfinity(); //----infinity -1.#INF
| |||
//+------------------------------------------------------------------+
| |||
//| Reverse communication structure |
| |||
//+------------------------------------------------------------------+
| |||
struct RCommState
| |||
{
| |||
public:
| |||
int stage;
| |||
CRowInt ia;
| |||
bool ba[];
| |||
CRowDouble ra;
| |||
CRowComplex ca;
| |||
| |||
RCommState(void) { stage=-1; }
| |||
~RCommState(void) {}
| |||
void Copy(const RCommState &obj);
| |||
//--- overloading
| |||
void operator=(const RCommState &obj) { Copy(obj); }
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
//| Create a copy |
| |||
//+------------------------------------------------------------------+
| |||
void RCommState::Copy(const RCommState &obj)
| |||
{
| |||
//--- copy a variable
| |||
stage=obj.stage;
| |||
//--- copy arrays
| |||
ia=obj.ia;
| |||
ArrayCopy(ba,obj.ba);
| |||
ra=obj.ra;
| |||
ca=obj.ca;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Internal functions |
| |||
//+------------------------------------------------------------------+
| |||
enum TRACE_MODE { TRACE_NONE,TRACE_FILE };
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
class CAp
| |||
{
| |||
public:
| |||
//--- variable that determines whether an exception happened
| |||
static bool exception_happened;
| |||
//--- len
| |||
template <typename T>
| |||
static int Len(const T &a[]);
| |||
static int Len(const CRowInt &a);
| |||
static int Len(const CRowDouble &a);
| |||
static int Len(const CRowComplex &a);
| |||
//--- rows count
| |||
static int Rows(const CMatrixInt &a);
| |||
static int Rows(const CMatrixDouble &a);
| |||
static int Rows(const CMatrixComplex &a);
| |||
//--- cols count
| |||
static int Cols(const CMatrixInt &a);
| |||
static int Cols(const CMatrixDouble &a);
| |||
static int Cols(const CMatrixComplex &a);
| |||
//--- swap
| |||
template <typename T>
| |||
static void Swap(T &a,T &b);
| |||
template <typename T>
| |||
static void Swap(T &a[],T &b[]);
| |||
static void Swap(vector<double> &a,vector<double> &b);
| |||
static void Swap(vector<float> &a,vector<float> &b);
| |||
static void Swap(vector<complex> &a,vector<complex> &b);
| |||
static void Swap(CMatrixInt &a,CMatrixInt &b);
| |||
static void Swap(CMatrixDouble &a,CMatrixDouble &b);
| |||
static void Swap(CMatrixComplex &a,CMatrixComplex &b);
| |||
//--- check assertions
| |||
static bool Assert(const bool cond);
| |||
static bool Assert(const bool cond,const string s);
| |||
static bool SetErrorFlag(bool &flag,bool cond,string xdesc);
| |||
static void SetErrorFlagDiff(bool &flag,double val,double refval,double tol,double s);
| |||
//--- determination of accuracy
| |||
static int ThresHoldToDPS(const double threshold);
| |||
//--- join string
| |||
static string StringJoin(const string sep,const string &a[]);
| |||
//--- convert to string
| |||
static string Format(const complex &a,const int dps);
| |||
static string Format(const bool &a[]);
| |||
static string Format(const int &a[]);
| |||
static string Format(const double &a[],const int dps);
| |||
static string Format(const vector<double> &a,const int dps);
| |||
static string Format(const complex &a[],const int dps);
| |||
static string Format(const vector<complex> &a,const int dps);
| |||
static string FormatB(CMatrixInt &a);
| |||
static string Format(CMatrixInt &a);
| |||
static string Format(CMatrixDouble &a,const int dps);
| |||
static string Format(CMatrixComplex &a,const int dps);
| |||
//--- work with matrix
| |||
static bool IsSymmetric(const CMatrixDouble &a);
| |||
static bool IsHermitian(const CMatrixComplex &a);
| |||
static bool ForceSymmetric(CMatrixDouble &a);
| |||
static bool ForceHermitian(CMatrixComplex &a);
| |||
//--- trace
| |||
static void TraceFile(string tags,string filename);
| |||
static void TraceDisable(void);
| |||
static bool IsTraceEnabled(string tag);
| |||
static void Trace(string s);
| |||
| |||
private:
| |||
static TRACE_MODE m_TraceMode;
| |||
static string m_TraceTags;
| |||
static string m_TraceFilename;
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
TRACE_MODE CAp::m_TraceMode=TRACE_NONE;
| |||
string CAp::m_TraceTags="";
| |||
string CAp::m_TraceFilename="";
| |||
//+------------------------------------------------------------------+
| |||
//| Initialize variable |
| |||
//+------------------------------------------------------------------+
| |||
bool CAp::exception_happened=false;
| |||
//+------------------------------------------------------------------+
| |||
//| Get array lenght |
| |||
//+------------------------------------------------------------------+
| |||
template <typename T>
| |||
int CAp::Len(const T &a[])
| |||
{
| |||
return(ArraySize(a));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get array lenght |
| |||
//+------------------------------------------------------------------+
| |||
int CAp::Len(const CRowInt &a)
| |||
{
| |||
return((int)a.Size());
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get array lenght |
| |||
//+------------------------------------------------------------------+
| |||
int CAp::Len(const CRowDouble &a)
| |||
{
| |||
return((int)a.Size());
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get array lenght |
| |||
//+------------------------------------------------------------------+
| |||
int CAp::Len(const CRowComplex &a)
| |||
{
| |||
return((int)a.Size());
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get rows count |
| |||
//+------------------------------------------------------------------+
| |||
int CAp::Rows(const CMatrixInt &a)
| |||
{
| |||
return(a.Size());
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get rows count |
| |||
//+------------------------------------------------------------------+
| |||
int CAp::Rows(const CMatrixDouble &a)
| |||
{
| |||
return(a.Size());
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get rows count |
| |||
//+------------------------------------------------------------------+
| |||
int CAp::Rows(const CMatrixComplex &a)
| |||
{
| |||
return(a.Size());
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get cols count |
| |||
//+------------------------------------------------------------------+
| |||
int CAp::Cols(const CMatrixInt &a)
| |||
{
| |||
//--- check
| |||
if(a.Size()==0)
| |||
return(0);
| |||
//--- return result
| |||
return(a[0].Size());
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get rows count |
| |||
//+------------------------------------------------------------------+
| |||
int CAp::Cols(const CMatrixDouble &a)
| |||
{
| |||
return(a.Cols());
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get rows count |
| |||
//+------------------------------------------------------------------+
| |||
int CAp::Cols(const CMatrixComplex &a)
| |||
{
| |||
return(a.Cols());
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Swap |
| |||
//+------------------------------------------------------------------+
| |||
template <typename T>
| |||
void CAp::Swap(T &a,T &b)
| |||
{
| |||
T t=a;
| |||
a=b;
| |||
b=t;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Swap |
| |||
//+------------------------------------------------------------------+
| |||
template <typename T>
| |||
void CAp::Swap(T &a[],T &b[])
| |||
{
| |||
ArraySwap(a,b);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Swap |
| |||
//+------------------------------------------------------------------+
| |||
void CAp::Swap(vector<double> &a,vector<double> &b)
| |||
{
| |||
a.Swap(b);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Swap |
| |||
//+------------------------------------------------------------------+
| |||
void CAp::Swap(vector<float> &a,vector<float> &b)
| |||
{
| |||
a.Swap(b);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Swap |
| |||
//+------------------------------------------------------------------+
| |||
void CAp::Swap(vector<complex> &a,vector<complex> &b)
| |||
{
| |||
a.Swap(b);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Swap |
| |||
//+------------------------------------------------------------------+
| |||
void CAp::Swap(CMatrixInt &a,CMatrixInt &b)
| |||
{
| |||
//--- create matrix
| |||
CMatrixInt t;
| |||
//--- swap
| |||
t=a;
| |||
a=b;
| |||
b=t;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Swap |
| |||
//+------------------------------------------------------------------+
| |||
void CAp::Swap(CMatrixDouble &a,CMatrixDouble &b)
| |||
{
| |||
//--- create matrix
| |||
CMatrixDouble t;
| |||
//--- swap
| |||
t=a;
| |||
a=b;
| |||
b=t;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Swap |
| |||
//+------------------------------------------------------------------+
| |||
void CAp::Swap(CMatrixComplex &a,CMatrixComplex &b)
| |||
{
| |||
//--- create matrix
| |||
CMatrixComplex t;
| |||
//--- swap
| |||
t=a;
| |||
a=b;
| |||
b=t;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Check assertions |
| |||
//+------------------------------------------------------------------+
| |||
bool CAp::Assert(const bool cond)
| |||
{
| |||
return(Assert(cond,"ALGLIB: assertion failed"));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Check assertions |
| |||
//+------------------------------------------------------------------+
| |||
bool CAp::Assert(const bool cond,const string s)
| |||
{
| |||
//--- check
| |||
if(!cond)
| |||
{
| |||
Print(__FUNCTION__+" " + s);
| |||
exception_happened=true;
| |||
return(false);
| |||
}
| |||
//--- the assertion is true
| |||
return(true);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
bool CAp::SetErrorFlag(bool &flag,bool cond,string xdesc)
| |||
{
| |||
if(cond)
| |||
{
| |||
flag=true;
| |||
Print(xdesc);
| |||
}
| |||
//---
| |||
return(flag);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Internally calls SetErrorFlag() with condition: |
| |||
//| Abs(Val-RefVal)>Tol*Max(Abs(RefVal),S) |
| |||
//| This function is used to test relative error in Val against |
| |||
//| RefVal, with relative error being replaced by absolute when scale|
| |||
//| of RefVal is less than S. |
| |||
//| This function returns value of COND. |
| |||
//+------------------------------------------------------------------+
| |||
void CAp::SetErrorFlagDiff(bool &flag,double val,double refval,
| |||
double tol,double s)
| |||
{
| |||
CAp::SetErrorFlag(flag,MathAbs(val-refval)>(tol*MathMax(MathAbs(refval),s)),"apserv.ap:162");
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| returns dps (digits-of-precision) value corresponding to |
| |||
//| threshold. |
| |||
//| dps(0.9) = dps(0.5) = dps(0.1) = 0 |
| |||
//| dps(0.09) = dps(0.05) = dps(0.01) = 1 |
| |||
//| and so on |
| |||
//+------------------------------------------------------------------+
| |||
int CAp::ThresHoldToDPS(const double threshold)
| |||
{
| |||
//--- initialization
| |||
int res=0;
| |||
double t=1.0;
| |||
for(res=0; t/10>threshold*(1+1E-10); res++)
| |||
t/=10;
| |||
//--- return result
| |||
return(res);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Concatenation |
| |||
//+------------------------------------------------------------------+
| |||
string CAp::StringJoin(const string sep,const string &a[])
| |||
{
| |||
int size=ArraySize(a);
| |||
//--- check
| |||
if(size==0)
| |||
{
| |||
Print(__FUNCTION__+": array size error");
| |||
return(NULL);
| |||
}
| |||
//--- concatenation
| |||
string res="";
| |||
for(int i=0; i<size; i++)
| |||
{
| |||
StringAdd(res,a[i]);
| |||
if(i!=size-1)
| |||
StringAdd(res,sep);
| |||
}
| |||
//--- return result
| |||
return(res);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Prints formatted complex |
| |||
//+------------------------------------------------------------------+
| |||
string CAp::Format(const complex &a,const int dps)
| |||
{
| |||
//--- definition of output style
| |||
string fmt;
| |||
if(dps>=0)
| |||
fmt="f";
| |||
else
| |||
fmt="e";
| |||
//--- get sign of the imaginary part
| |||
string sign;
| |||
if(a.imag>=0)
| |||
sign="+";
| |||
else
| |||
sign="-";
| |||
//--- converting
| |||
int d=(int)MathAbs(dps);
| |||
string fmtx=StringFormat(".%d" + fmt,d);
| |||
string fmty=StringFormat(".%d" + fmt,d);
| |||
//--- get result
| |||
string res=StringFormat("%" + fmtx,a.real) + sign +
| |||
StringFormat("%" + fmty,MathAbs(a.imag)) + "i";
| |||
StringReplace(res,",",".");
| |||
//--- return result
| |||
return(res);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Prints formatted array |
| |||
//+------------------------------------------------------------------+
| |||
string CAp::Format(const bool &a[])
| |||
{
| |||
int size=ArraySize(a);
| |||
//--- check
| |||
if(size==0)
| |||
{
| |||
Print(__FUNCTION__+": array size error");
| |||
return(NULL);
| |||
}
| |||
//--- converting
| |||
string result[];
| |||
ArrayResizeAL(result,size);
| |||
for(int i=0; i<size; i++)
| |||
{
| |||
if(a[i]==0)
| |||
result[i]="true";
| |||
else
| |||
result[i]="false";
| |||
}
| |||
//--- return result
| |||
return("{" + StringJoin(",",result) + "}");
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Prints formatted array |
| |||
//+------------------------------------------------------------------+
| |||
string CAp::Format(const int &a[])
| |||
{
| |||
int size=ArraySize(a);
| |||
//--- check
| |||
if(size==0)
| |||
{
| |||
Print(__FUNCTION__+": array size error");
| |||
return(NULL);
| |||
}
| |||
//--- converting
| |||
string result[];
| |||
ArrayResizeAL(result,size);
| |||
for(int i=0; i<size; i++)
| |||
result[i]=IntegerToString(a[i]);
| |||
//--- return result
| |||
return("{" + StringJoin(",",result) + "}");
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Prints formatted array |
| |||
//+------------------------------------------------------------------+
| |||
string CAp::Format(const double &a[],const int dps)
| |||
{
| |||
int size=ArraySize(a);
| |||
//--- check
| |||
if(size==0)
| |||
{
| |||
Print(__FUNCTION__+": array size error");
| |||
return(NULL);
| |||
}
| |||
string result[];
| |||
ArrayResizeAL(result,size);
| |||
//--- definition of output style
| |||
string sfmt;
| |||
if(dps>=0)
| |||
sfmt="f";
| |||
else
| |||
sfmt="e";
| |||
//--- converting
| |||
int d=(int)MathAbs(dps);
| |||
string fmt=StringFormat(".%d" + sfmt,d);
| |||
for(int i=0; i<size; i++)
| |||
{
| |||
result[i]=StringFormat("%" + fmt,a[i]);
| |||
StringReplace(result[i],",",".");
| |||
}
| |||
//--- return result
| |||
return("{" + StringJoin(",",result) + "}");
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Prints formatted array |
| |||
//+------------------------------------------------------------------+
| |||
string CAp::Format(const vector<double> &a,const int dps)
| |||
{
| |||
ulong size=a.Size();
| |||
//--- check
| |||
if(size==0)
| |||
{
| |||
Print(__FUNCTION__+": vector size error");
| |||
return(NULL);
| |||
}
| |||
string result[];
| |||
ArrayResizeAL(result,(int)size);
| |||
//--- definition of output style
| |||
string sfmt;
| |||
if(dps>=0)
| |||
sfmt="f";
| |||
else
| |||
sfmt="e";
| |||
//--- converting
| |||
int d=(int)MathAbs(dps);
| |||
string fmt=StringFormat(".%d" + sfmt,d);
| |||
for(ulong i=0; i<size; i++)
| |||
{
| |||
result[i]=StringFormat("%" + fmt,a[i]);
| |||
StringReplace(result[i],",",".");
| |||
}
| |||
//--- return result
| |||
return("{" + StringJoin(",",result) + "}");
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Prints formatted array |
| |||
//+------------------------------------------------------------------+
| |||
string CAp::Format(const complex &a[],const int dps)
| |||
{
| |||
int size=ArraySize(a);
| |||
//--- check
| |||
if(size==0)
| |||
{
| |||
Print(__FUNCTION__+": array size error");
| |||
return(NULL);
| |||
}
| |||
string result[];
| |||
ArrayResizeAL(result,size);
| |||
//--- definition of output style
| |||
string fmt;
| |||
if(dps>=0)
| |||
fmt="f";
| |||
else
| |||
fmt="e";
| |||
//--- converting
| |||
int d=(int)MathAbs(dps);
| |||
string fmtx=StringFormat(".%d" + fmt,d);
| |||
string fmty=StringFormat(".%d" + fmt,d);
| |||
string sign;
| |||
for(int i=0; i<size; i++)
| |||
{
| |||
//--- definition of the sign
| |||
if(a[i].imag>=0)
| |||
sign="+";
| |||
else
| |||
sign="-";
| |||
//--- fill result
| |||
result[i]=StringFormat("%" + fmtx,a[i].real) + sign +
| |||
StringFormat("%" + fmty,MathAbs(a[i].imag)) + "i";
| |||
StringReplace(result[i],",",".");
| |||
}
| |||
//--- return result
| |||
return("{" + StringJoin(",",result) + "}");
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Prints formatted matrix |
| |||
//+------------------------------------------------------------------+
| |||
string CAp::FormatB(CMatrixInt &a)
| |||
{
| |||
int m=a.Rows();
| |||
//--- check
| |||
if(m==0)
| |||
{
| |||
Print(__FUNCTION__+": array size error");
| |||
return(NULL);
| |||
}
| |||
int n=a.Cols();
| |||
//--- check
| |||
if(n==0)
| |||
{
| |||
Print(__FUNCTION__+": array size error");
| |||
return(NULL);
| |||
}
| |||
//--- prepare arrays
| |||
bool line[];
| |||
string result[];
| |||
ArrayResizeAL(line,n);
| |||
ArrayResizeAL(result,m);
| |||
//--- converting
| |||
for(int i=0; i<m; i++)
| |||
{
| |||
for(int j=0; j<n; j++)
| |||
line[j]=(bool)(a.Get(i,j));
| |||
result[i]=Format(line);
| |||
}
| |||
//--- return result
| |||
return("{" + StringJoin(",",result) + "}");
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Prints formatted matrix |
| |||
//+------------------------------------------------------------------+
| |||
string CAp::Format(CMatrixInt &a)
| |||
{
| |||
int m=a.Rows();
| |||
//--- check
| |||
if(m==0)
| |||
{
| |||
Print(__FUNCTION__+": array size error");
| |||
return(NULL);
| |||
}
| |||
int n=a.Cols();
| |||
//--- check
| |||
if(n==0)
| |||
{
| |||
Print(__FUNCTION__+": array size error");
| |||
return(NULL);
| |||
}
| |||
//--- prepare arrays
| |||
int line[];
| |||
string result[];
| |||
ArrayResizeAL(line,n);
| |||
ArrayResizeAL(result,m);
| |||
//--- converting
| |||
for(int i=0; i<m; i++)
| |||
{
| |||
for(int j=0; j<n; j++)
| |||
line[j]=a.Get(i,j);
| |||
result[i]=Format(line);
| |||
}
| |||
//--- return result
| |||
return("{" + StringJoin(",",result) + "}");
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Prints formatted matrix |
| |||
//+------------------------------------------------------------------+
| |||
string CAp::Format(CMatrixDouble &a,const int dps)
| |||
{
| |||
ulong m=a.Rows();
| |||
//--- check
| |||
if(m==0)
| |||
{
| |||
Print(__FUNCTION__+": array size error");
| |||
return(NULL);
| |||
}
| |||
ulong n=a.Cols();
| |||
//--- check
| |||
if(n==0)
| |||
{
| |||
Print(__FUNCTION__+": array size error");
| |||
return(NULL);
| |||
}
| |||
//--- prepare arrays
| |||
string result[];
| |||
ArrayResizeAL(result,(int)m);
| |||
//--- converting
| |||
for(ulong i=0; i<m; i++)
| |||
{
| |||
vector<double> v=a[i];
| |||
result[i]=Format(v,dps);
| |||
}
| |||
//--- return result
| |||
return("{" + StringJoin(",",result) + "}");
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Prints formatted matrix |
| |||
//+------------------------------------------------------------------+
| |||
string CAp::Format(CMatrixComplex &a,const int dps)
| |||
{
| |||
ulong m=a.Rows();
| |||
//--- check
| |||
if(m==0)
| |||
{
| |||
Print(__FUNCTION__+": matrix size error");
| |||
return(NULL);
| |||
}
| |||
ulong n=a.Cols();
| |||
//--- check
| |||
if(n==0)
| |||
{
| |||
Print(__FUNCTION__+": matrix size error");
| |||
return(NULL);
| |||
}
| |||
//--- prepare arrays
| |||
string result[];
| |||
ArrayResizeAL(result,(int)m);
| |||
//--- converting
| |||
for(ulong i=0; i<m; i++)
| |||
{
| |||
vector<complex> v=a[i];
| |||
result[i]=Format(v,dps);
| |||
}
| |||
//--- return result
| |||
return("{" + StringJoin(",",result) + "}");
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| checks that matrix is symmetric. |
| |||
//| max|A-A^T| is calculated; if it is within 1.0E-14 of max|A|, |
| |||
//| matrix is considered symmetric |
| |||
//+------------------------------------------------------------------+
| |||
bool CAp::IsSymmetric(const CMatrixDouble &a)
| |||
{
| |||
ulong n=a.Rows();
| |||
//--- check
| |||
if(n!=a.Cols())
| |||
return(false);
| |||
//--- check
| |||
if(n==0)
| |||
return(true);
| |||
//--- check for symmetry
| |||
double mx=0;
| |||
double err=0;
| |||
for(ulong i=0; i<n; i++)
| |||
{
| |||
for(ulong j=i+1; j<n; j++)
| |||
{
| |||
double v1=a.Get(i,j);
| |||
double v2=a.Get(j,i);
| |||
if(!MathIsValidNumber(v1))
| |||
return(false);
| |||
if(!MathIsValidNumber(v2))
| |||
return(false);
| |||
err=MathMax(err,MathAbs(v1-v2));
| |||
mx =MathMax(mx,MathAbs(v1));
| |||
mx =MathMax(mx,MathAbs(v2));
| |||
}
| |||
double v=a.Get(i,i);
| |||
if(!MathIsValidNumber(v))
| |||
return(false);
| |||
mx=MathMax(mx,MathAbs(v));
| |||
}
| |||
//--- check
| |||
if(mx==0)
| |||
return(true);
| |||
//--- check
| |||
if(err/mx<=1.0E-14)
| |||
return(true);
| |||
//--- return result
| |||
return(false);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| checks that matrix is Hermitian. |
| |||
//| max|A-A^H| is calculated; if it is within 1.0E-14 of max|A|, |
| |||
//| matrix is considered Hermitian |
| |||
//+------------------------------------------------------------------+
| |||
bool CAp::IsHermitian(const CMatrixComplex &a)
| |||
{
| |||
ulong n=a.Rows();
| |||
//--- check
| |||
if(n!=a.Cols())
| |||
return(false);
| |||
//--- check
| |||
if(n==0)
| |||
return(true);
| |||
//--- initialization
| |||
double mx=0;
| |||
double err=0;
| |||
complex v1,v2,vt;
| |||
//--- check for Hermitian
| |||
for(ulong i=0; i<n; i++)
| |||
{
| |||
for(ulong j=i+1; j<n; j++)
| |||
{
| |||
v1=a.Get(i,j);
| |||
v2=a.Get(j,i);
| |||
//--- checks
| |||
if(!CMath::IsFinite(v1.real))
| |||
return(false);
| |||
if(!CMath::IsFinite(v1.imag))
| |||
return(false);
| |||
if(!CMath::IsFinite(v2.real))
| |||
return(false);
| |||
if(!CMath::IsFinite(v2.imag))
| |||
return(false);
| |||
//--- change values
| |||
vt.real=v1.real-v2.real;
| |||
vt.imag=v1.imag+v2.imag;
| |||
err=MathMax(err,CMath::AbsComplex(vt));
| |||
mx=MathMax(mx,CMath::AbsComplex(v1));
| |||
mx=MathMax(mx,CMath::AbsComplex(v2));
| |||
}
| |||
v1=a.Get(i,i);
| |||
//--- checks
| |||
if(!CMath::IsFinite(v1.real))
| |||
return(false);
| |||
if(!CMath::IsFinite(v1.imag))
| |||
return(false);
| |||
//--- change values
| |||
err=MathMax(err,MathAbs(v1.imag));
| |||
mx=MathMax(mx,CMath::AbsComplex(v1));
| |||
}
| |||
//--- check
| |||
if(mx==0)
| |||
return(true);
| |||
//--- check
| |||
if(err/mx<=1.0E-14)
| |||
return(true);
| |||
//--- return result
| |||
return(false);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Forces symmetricity by copying upper half of A to the lower one |
| |||
//+------------------------------------------------------------------+
| |||
bool CAp::ForceSymmetric(CMatrixDouble &a)
| |||
{
| |||
ulong n=a.Rows();
| |||
//--- check
| |||
if(n!=a.Cols())
| |||
return(false);
| |||
//--- check
| |||
if(n==0)
| |||
return(true);
| |||
//--- change matrix
| |||
matrix<double> m=a.Transpose();
| |||
a=a.TriL()+m.TriU(1);
| |||
//--- return result
| |||
return(true);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Forces Hermiticity by copying upper half of A to the lower one |
| |||
//+------------------------------------------------------------------+
| |||
bool CAp::ForceHermitian(CMatrixComplex &a)
| |||
{
| |||
ulong n=a.Rows();
| |||
//--- check
| |||
if(n!=a.Cols())
| |||
return(false);
| |||
//--- check
| |||
if(n==0)
| |||
return(true);
| |||
//--- change matrix
| |||
complex c;
| |||
for(ulong i=0; i<n; i++)
| |||
for(ulong j=i+1; j<n; j++)
| |||
{
| |||
c=a.Get(j,i);
| |||
c.imag=-c.imag;
| |||
a.Set(i,j,c);
| |||
}
| |||
//--- return result
| |||
return(true);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Start trace |
| |||
//+------------------------------------------------------------------+
| |||
void CAp::TraceFile(string tags,string filename)
| |||
{
| |||
m_TraceMode =TRACE_FILE;
| |||
StringToLower(tags);
| |||
m_TraceTags ="," + tags + ",";
| |||
m_TraceFilename=filename;
| |||
Trace("####################################################################################################\r\n");
| |||
Trace("# TRACING ENABLED: " + TimeToString(TimeCurrent(),TIME_DATE | TIME_SECONDS) + "\r\n");
| |||
Trace("# TRACE TAGS: '" + tags + "'\r\n");
| |||
Trace("####################################################################################################\r\n");
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Stop trace |
| |||
//+------------------------------------------------------------------+
| |||
void CAp::TraceDisable(void)
| |||
{
| |||
m_TraceMode =TRACE_NONE;
| |||
m_TraceTags ="";
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Check trace enabled |
| |||
//+------------------------------------------------------------------+
| |||
bool CAp::IsTraceEnabled(string tag)
| |||
{
| |||
//--- trace disabled
| |||
if(m_TraceMode==TRACE_NONE)
| |||
return(false);
| |||
//--- contains tag (followed by comma, which means exact match)
| |||
StringToLower(tag);
| |||
if(StringFind(m_TraceTags,("," + tag + ",")) >= 0)
| |||
return(true);
| |||
//--- contains tag (followed by dot, which means match with child)
| |||
if(StringFind(m_TraceTags,("," + tag + ".")) >= 0)
| |||
return(true);
| |||
//---nothing
| |||
return(false);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Trace |
| |||
//+------------------------------------------------------------------+
| |||
void CAp::Trace(string s)
| |||
{
| |||
if(m_TraceMode==TRACE_FILE)
| |||
{
| |||
int handle=FileOpen(m_TraceFilename,FILE_READ|FILE_WRITE|FILE_TXT|FILE_ANSI);
| |||
if(handle<=0 || !FileSeek(handle,0,SEEK_END))
| |||
return;
| |||
FileWriteString(handle,s);
| |||
FileClose(handle);
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Portable high quality random number generator state. |
| |||
//| Initialized with HQRNDRandomize() or HQRNDSeed(). |
| |||
//| Fields: |
| |||
//| S1, S2 - seed values |
| |||
//| V - precomputed value |
| |||
//| MagicV - 'magic' value used to determine whether State|
| |||
//| structure was correctly initialized. |
| |||
//+------------------------------------------------------------------+
| |||
class CHighQualityRandState
| |||
{
| |||
public:
| |||
//--- variables
| |||
int m_s1;
| |||
int m_s2;
| |||
double m_v;
| |||
int m_magicv;
| |||
//--- constructor, destructor
| |||
CHighQualityRandState(void) { ZeroMemory(this); }
| |||
~CHighQualityRandState(void) {}
| |||
//---
| |||
void Copy(const CHighQualityRandState &obj);
| |||
//--- overloading
| |||
void operator=(const CHighQualityRandState &obj) { Copy(obj); }
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
void CHighQualityRandState::Copy(const CHighQualityRandState &obj)
| |||
{
| |||
m_s1=obj.m_s1;
| |||
m_s2=obj.m_s2;
| |||
m_magicv=obj.m_magicv;
| |||
m_v=obj.m_v;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Portable high quality random number generator state. |
| |||
//| Initialized with HQRNDRandomize() or HQRNDSeed(). |
| |||
//| Fields: |
| |||
//| S1, S2 - seed values |
| |||
//| V - precomputed value |
| |||
//| MagicV - 'magic' value used to determine whether State|
| |||
//| structure was correctly initialized. |
| |||
//+------------------------------------------------------------------+
| |||
class CHighQualityRandStateShell
| |||
{
| |||
private:
| |||
CHighQualityRandState m_innerobj;
| |||
| |||
public:
| |||
//--- constructors, destructor
| |||
CHighQualityRandStateShell(void) {}
| |||
CHighQualityRandStateShell(CHighQualityRandState &obj);
| |||
~CHighQualityRandStateShell(void) {}
| |||
//--- method
| |||
CHighQualityRandState *GetInnerObj(void) { return(GetPointer(m_innerobj)); }
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
//| Copy |
| |||
//+------------------------------------------------------------------+
| |||
CHighQualityRandStateShell::CHighQualityRandStateShell(CHighQualityRandState &obj)
| |||
{
| |||
//--- copy
| |||
m_innerobj.m_s1=obj.m_s1;
| |||
m_innerobj.m_s2=obj.m_s2;
| |||
m_innerobj.m_v=obj.m_v;
| |||
m_innerobj.m_magicv=obj.m_magicv;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Portable high quality random number generator |
| |||
//+------------------------------------------------------------------+
| |||
class CHighQualityRand
| |||
{
| |||
public:
| |||
//--- static class members
| |||
static const int m_HQRndMax;
| |||
static const int m_HQRndM1;
| |||
static const int m_HQRndM2;
| |||
static const int m_HQRndMagic;
| |||
//--- public methods
| |||
static void HQRndRandomize(CHighQualityRandState &state);
| |||
static void HQRndSeed(const int s1,const int s2,CHighQualityRandState &state);
| |||
static double HQRndUniformR(CHighQualityRandState &state);
| |||
static int HQRndUniformI(CHighQualityRandState &state,const int n);
| |||
static double HQRndNormal(CHighQualityRandState &state);
| |||
static void HQRndNormalV(CHighQualityRandState &state,int n,CRowDouble &x);
| |||
static void HQRndNormalM(CHighQualityRandState &state,int m,int n,CMatrixDouble &x);
| |||
static void HQRndUnit2(CHighQualityRandState &state,double &x,double &y);
| |||
static void HQRndNormal2(CHighQualityRandState &state,double &x1,double &x2);
| |||
static double HQRndExponential(CHighQualityRandState &state,const double lambdav);
| |||
static double HQRndDiscrete(CHighQualityRandState &state,int n,CRowDouble &x);
| |||
template <typename T>
| |||
static T HQRndDiscrete(CHighQualityRandState &state,int n,vector<T> &x);
| |||
static double HQRndContinuous(CHighQualityRandState &state,int n,CRowDouble &x);
| |||
template <typename T>
| |||
static T HQRndContinuous(CHighQualityRandState &state,int n,vector<T> &x);
| |||
| |||
private:
| |||
static int HQRndIntegerBase(CHighQualityRandState &state);
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
//| Initialize constants |
| |||
//+------------------------------------------------------------------+
| |||
const int CHighQualityRand::m_HQRndMax=2147483561;
| |||
const int CHighQualityRand::m_HQRndM1 =2147483563;
| |||
const int CHighQualityRand::m_HQRndM2 =2147483399;
| |||
const int CHighQualityRand::m_HQRndMagic=1634357784;
| |||
//+------------------------------------------------------------------+
| |||
//| HQRNDState initialization with random values which come from |
| |||
//| standard RNG. |
| |||
//+------------------------------------------------------------------+
| |||
void CHighQualityRand::HQRndRandomize(CHighQualityRandState &state)
| |||
{
| |||
//--- get result
| |||
HQRndSeed(CMath::RandomInteger(m_HQRndM1),CMath::RandomInteger(m_HQRndM2),state);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| HQRNDState initialization with seed values |
| |||
//+------------------------------------------------------------------+
| |||
void CHighQualityRand::HQRndSeed(const int s1,const int s2,
| |||
CHighQualityRandState &state)
| |||
{
| |||
//--- calculation parameters
| |||
state.m_s1=s1%(m_HQRndM1-1)+1;
| |||
state.m_s2=s2%(m_HQRndM2-1)+1;
| |||
state.m_v=1.0/(double)m_HQRndMax;
| |||
state.m_magicv=m_HQRndMagic;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function generates random real number in [0,1). |
| |||
//| State structure must be initialized with HQRNDRandomize() or |
| |||
//| HQRNDSeed(). |
| |||
//+------------------------------------------------------------------+
| |||
double CHighQualityRand::HQRndUniformR(CHighQualityRandState &state)
| |||
{
| |||
return(state.m_v*(HQRndIntegerBase(state)-1));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function generates random integer number in [0, N) |
| |||
//| 1. N must be less than HQRNDMax-1. |
| |||
//| 2. State structure must be initialized with HQRNDRandomize() or |
| |||
//| HQRNDSeed() |
| |||
//+------------------------------------------------------------------+
| |||
int CHighQualityRand::HQRndUniformI(CHighQualityRandState &state,const int n)
| |||
{
| |||
//--- create variables
| |||
int result=0;
| |||
int maxcnt=0;
| |||
int mx=0;
| |||
int a=0;
| |||
int b=0;
| |||
//--- check
| |||
if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!"))
| |||
return(INT_MAX);
| |||
//---
| |||
maxcnt=m_HQRndMax+1;
| |||
//---Two branches: one for N<=MaxCnt, another for N>MaxCnt.
| |||
if(n>maxcnt)
| |||
{
| |||
//---N>=MaxCnt.
| |||
//---We have two options here:
| |||
//---a) N is exactly divisible by MaxCnt
| |||
//---b) N is not divisible by MaxCnt
| |||
//---In both cases we reduce problem on interval spanning [0,N)
| |||
//---to several subproblems on intervals spanning [0,MaxCnt).
| |||
if(n%maxcnt==0)
| |||
{
| |||
//---N is exactly divisible by MaxCnt.
| |||
//---[0,N) range is dividided into N/MaxCnt bins,
| |||
//---each of them having length equal to MaxCnt.
| |||
//---We generate:
| |||
//---* random bin number B
| |||
//---* random offset within bin A
| |||
//---Both random numbers are generated by recursively
| |||
//---calling HQRNDUniformI().
| |||
//---Result is equal to A+MaxCnt*B.
| |||
//--- check
| |||
if(!CAp::Assert(n/maxcnt<=maxcnt,__FUNCTION__+": N is too large"))
| |||
return(INT_MAX);
| |||
a=HQRndUniformI(state,maxcnt);
| |||
b=HQRndUniformI(state,n/maxcnt);
| |||
result=a+maxcnt*b;
| |||
}
| |||
else
| |||
{
| |||
//---N is NOT exactly divisible by MaxCnt.
| |||
//---[0,N) range is dividided into Ceil(N/MaxCnt) bins,
| |||
//---each of them having length equal to MaxCnt.
| |||
//---We generate:
| |||
//---* random bin number B in [0, Ceil(N/MaxCnt)-1]
| |||
//---* random offset within bin A
| |||
//---* if both of what is below is true
| |||
//--- 1) bin number B is that of the last bin
| |||
//--- 2) A >= N mod MaxCnt
| |||
//--- then we repeat generation of A/B.
| |||
//--- This stage is essential in order to avoid bias in the result.
| |||
//---* otherwise, we return A*MaxCnt+N
| |||
//--- check
| |||
if(!CAp::Assert(n/maxcnt+1<=maxcnt,__FUNCTION__+": N is too large"))
| |||
return(INT_MAX);
| |||
result=-1;
| |||
do
| |||
{
| |||
a=HQRndUniformI(state,maxcnt);
| |||
b=HQRndUniformI(state,n/maxcnt+1);
| |||
if(b==n/maxcnt && a>=n%maxcnt)
| |||
continue;
| |||
result=a+maxcnt*b;
| |||
}
| |||
while(result<0);
| |||
}
| |||
}
| |||
else
| |||
{
| |||
//---N<=MaxCnt
| |||
//---Code below is a bit complicated because we can not simply
| |||
//---return "HQRNDIntegerBase() mod N" - it will be skewed for
| |||
//---large N's in [0.1*HQRNDMax...HQRNDMax].
| |||
mx=maxcnt-maxcnt%n;
| |||
do
| |||
{
| |||
result=HQRndIntegerBase(state);
| |||
}
| |||
while(result>=mx);
| |||
result=result%n;
| |||
}
| |||
//--- return result
| |||
return(result);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Random number generator: normal numbers |
| |||
//| This function generates one random number from normal |
| |||
//| distribution. |
| |||
//| Its performance is equal to that of HQRNDNormal2() |
| |||
//| State structure must be initialized with HQRNDRandomize() or |
| |||
//| HQRNDSeed(). |
| |||
//+------------------------------------------------------------------+
| |||
double CHighQualityRand::HQRndNormal(CHighQualityRandState &state)
| |||
{
| |||
//--- create variables
| |||
double v1=0;
| |||
double v2=0;
| |||
//--- function call
| |||
HQRndNormal2(state,v1,v2);
| |||
//--- return result
| |||
return(v1);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Random number generator: vector with random entries (normal |
| |||
//| distribution) |
| |||
//| This function generates N random numbers from normal |
| |||
//| distribution. |
| |||
//| State structure must be initialized with HQRNDRandomize() or |
| |||
//| HQRNDSeed(). |
| |||
//+------------------------------------------------------------------+
| |||
void CHighQualityRand::HQRndNormalV(CHighQualityRandState &state,
| |||
int n,CRowDouble &x)
| |||
{
| |||
//--- create variables
| |||
int n2=0;
| |||
double v1=0;
| |||
double v2=0;
| |||
//--- function call
| |||
if(n<0)
| |||
{
| |||
n=(int)x.Size();
| |||
}
| |||
else
| |||
{
| |||
if((int)x.Size()<n)
| |||
x.Resize(n);
| |||
}
| |||
n2=n/2;
| |||
for(int i=0; i<n2; i++)
| |||
{
| |||
HQRndNormal2(state,v1,v2);
| |||
x.Set(2*i,v1);
| |||
x.Set(2*i+1,v2);
| |||
}
| |||
if(n%2!=0)
| |||
{
| |||
HQRndNormal2(state,v1,v2);
| |||
x.Set(n-1,v1);
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Random number generator: matrix with random entries (normal |
| |||
//| distribution) |
| |||
//| This function generates MxN random matrix. |
| |||
//| State structure must be initialized with HQRNDRandomize() or |
| |||
//| HQRNDSeed(). |
| |||
//+------------------------------------------------------------------+
| |||
void CHighQualityRand::HQRndNormalM(CHighQualityRandState &state,
| |||
int m,int n,CMatrixDouble &x)
| |||
{
| |||
//--- create variables
| |||
int n2=0;
| |||
double v1=0;
| |||
double v2=0;
| |||
//--- function call
| |||
if(n<0)
| |||
{
| |||
n=(int)x.Cols();
| |||
}
| |||
else
| |||
{
| |||
if((int)x.Cols()<n)
| |||
x.Resize(x.Rows(),n);
| |||
}
| |||
if(m<0)
| |||
{
| |||
m=(int)x.Rows();
| |||
}
| |||
else
| |||
{
| |||
if((int)x.Rows()<m)
| |||
x.Resize(m,x.Cols());
| |||
}
| |||
n2=n/2;
| |||
for(int i=0; i<m; i++)
| |||
{
| |||
for(int j=0; j<n2; j++)
| |||
{
| |||
HQRndNormal2(state,v1,v2);
| |||
x.Set(i,2*j,v1);
| |||
x.Set(i,2*j+1,v2);
| |||
}
| |||
if(n%2!=0)
| |||
{
| |||
HQRndNormal2(state,v1,v2);
| |||
x.Set(i,n-1,v1);
| |||
}
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Random number generator: random X and Y such that X^2+Y^2=1 |
| |||
//| State structure must be initialized with HQRNDRandomize() or |
| |||
//| HQRNDSeed(). |
| |||
//+------------------------------------------------------------------+
| |||
void CHighQualityRand::HQRndUnit2(CHighQualityRandState &state,
| |||
double &x,double &y)
| |||
{
| |||
//--- create variables
| |||
double v=0;
| |||
double mx=0;
| |||
double mn=0;
| |||
//--- initialization
| |||
x=0;
| |||
y=0;
| |||
//--- function call
| |||
do
| |||
HQRndNormal2(state,x,y);
| |||
while(!(x!=0.0 || y!=0.0));
| |||
//--- change values
| |||
mx=MathMax(MathAbs(x),MathAbs(y));
| |||
mn=MathMin(MathAbs(x),MathAbs(y));
| |||
v=mx*MathSqrt(1+CMath::Sqr(mn/mx));
| |||
//--- get result
| |||
x=x/v;
| |||
y=y/v;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Random number generator: normal numbers |
| |||
//| This function generates two independent random numbers from |
| |||
//| normal distribution. Its performance is equal to that of |
| |||
//| HQRNDNormal() |
| |||
//| State structure must be initialized with HQRNDRandomize() or |
| |||
//| HQRNDSeed(). |
| |||
//+------------------------------------------------------------------+
| |||
void CHighQualityRand::HQRndNormal2(CHighQualityRandState &state,
| |||
double &x1,double &x2)
| |||
{
| |||
//--- create variables
| |||
double u=0;
| |||
double v=0;
| |||
double s=0;
| |||
//--- initialization
| |||
x1=0;
| |||
x2=0;
| |||
//--- cycle
| |||
while(true)
| |||
{
| |||
u=2*HQRndUniformR(state)-1;
| |||
v=2*HQRndUniformR(state)-1;
| |||
s=CMath::Sqr(u)+CMath::Sqr(v);
| |||
//--- check
| |||
if(s>0.0 && s<1.0)
| |||
{
| |||
//--- two Sqrt's instead of one to
| |||
//--- avoid overflow when S is too small
| |||
s=MathSqrt(-(2*MathLog(s)))/MathSqrt(s);
| |||
x1=u*s;
| |||
x2=v*s;
| |||
//--- exit the function
| |||
return;
| |||
}
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Random number generator: exponential distribution |
| |||
//| State structure must be initialized with HQRNDRandomize() or |
| |||
//| HQRNDSeed(). |
| |||
//+------------------------------------------------------------------+
| |||
double CHighQualityRand::HQRndExponential(CHighQualityRandState &state,
| |||
const double lambdav)
| |||
{
| |||
//--- check
| |||
if(!CAp::Assert(lambdav>0.0,__FUNCTION__+": LambdaV<=0!"))
| |||
return(EMPTY_VALUE);
| |||
//--- return result
| |||
return(-(MathLog(HQRndUniformR(state))/lambdav));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function generates random number from discrete distribution|
| |||
//| given by finite sample X. |
| |||
//| INPUT PARAMETERS |
| |||
//| State - high quality random number generator, must be |
| |||
//| initialized with HQRNDRandomize() or HQRNDSeed(). |
| |||
//| X - finite sample |
| |||
//| N - number of elements to use, N>=1 |
| |||
//| RESULT |
| |||
//| this function returns one of the X[i] for random i=0..N-1 |
| |||
//+------------------------------------------------------------------+
| |||
double CHighQualityRand::HQRndDiscrete(CHighQualityRandState &state,
| |||
int n,CRowDouble &x)
| |||
{
| |||
double result=0;
| |||
//--- check
| |||
if(!CAp::Assert(n>0,__FUNCTION__+": N<=0"))
| |||
return (EMPTY_VALUE);
| |||
if(!CAp::Assert(n<=(int)x.Size(),__FUNCTION__+": Length(X)<N"))
| |||
return (EMPTY_VALUE);
| |||
//--- call function
| |||
result=x[HQRndUniformI(state,n)];
| |||
//--- return result
| |||
return(result);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function generates random number from discrete distribution|
| |||
//| given by finite sample X. |
| |||
//| INPUT PARAMETERS |
| |||
//| State - high quality random number generator, must be |
| |||
//| initialized with HQRNDRandomize() or HQRNDSeed(). |
| |||
//| X - finite sample |
| |||
//| N - number of elements to use, N>=1 |
| |||
//| RESULT |
| |||
//| this function returns one of the X[i] for random i=0..N-1 |
| |||
//+------------------------------------------------------------------+
| |||
template <typename T>
| |||
T CHighQualityRand::HQRndDiscrete(CHighQualityRandState &state,
| |||
int n,vector<T> &x)
| |||
{
| |||
T result=0;
| |||
//--- check
| |||
if(!CAp::Assert(n>0,__FUNCTION__+": N<=0"))
| |||
return (EMPTY_VALUE);
| |||
if(!CAp::Assert(n<=(int)x.Size(),__FUNCTION__+": Length(X)<N"))
| |||
return (EMPTY_VALUE);
| |||
//--- call function
| |||
result=x[HQRndUniformI(state,n)];
| |||
//--- return result
| |||
return(result);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function generates random number from continuous |
| |||
//| distribution given by finite sample X. |
| |||
//| INPUT PARAMETERS |
| |||
//| State - high quality random number generator, must be |
| |||
//| initialized with HQRNDRandomize() or HQRNDSeed(). |
| |||
//| X - finite sample, array[N] (can be larger, in this |
| |||
//| case only leading N elements are used). THIS ARRAY |
| |||
//| MUST BE SORTED BY ASCENDING. |
| |||
//| N - number of elements to use, N>=1 |
| |||
//| RESULT |
| |||
//| this function returns random number from continuous |
| |||
//| distribution which tries to approximate X as mush as possible. |
| |||
//| min(X)<=Result<=max(X). |
| |||
//+------------------------------------------------------------------+
| |||
double CHighQualityRand::HQRndContinuous(CHighQualityRandState &state,
| |||
int n,CRowDouble &x)
| |||
{
| |||
//--- create variables
| |||
double result=0;
| |||
double mx=0;
| |||
double mn=0;
| |||
int i=0;
| |||
//--- check
| |||
if(!CAp::Assert(n>0,__FUNCTION__+": N<=0"))
| |||
return (EMPTY_VALUE);
| |||
if(!CAp::Assert(n<=(int)x.Size(),__FUNCTION__+": Length(X)<N"))
| |||
return (EMPTY_VALUE);
| |||
//--- call function
| |||
if(n==1)
| |||
{
| |||
result=x[0];
| |||
return(result);
| |||
}
| |||
i=HQRndUniformI(state,n-1);
| |||
mn=x[i];
| |||
mx=x[i+1];
| |||
if(!CAp::Assert(mx>=mn,__FUNCTION__+": X is not sorted by ascending"))
| |||
return(EMPTY_VALUE);
| |||
if(mx!=mn)
| |||
result=(mx-mn)*HQRndUniformR(state)+mn;
| |||
else
| |||
result=mn;
| |||
//--- return result
| |||
return(result);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function generates random number from continuous |
| |||
//| distribution given by finite sample X. |
| |||
//| INPUT PARAMETERS |
| |||
//| State - high quality random number generator, must be |
| |||
//| initialized with HQRNDRandomize() or HQRNDSeed(). |
| |||
//| X - finite sample, array[N] (can be larger, in this |
| |||
//| case only leading N elements are used). THIS ARRAY |
| |||
//| MUST BE SORTED BY ASCENDING. |
| |||
//| N - number of elements to use, N>=1 |
| |||
//| RESULT |
| |||
//| this function returns random number from continuous |
| |||
//| distribution which tries to approximate X as mush as possible. |
| |||
//| min(X)<=Result<=max(X). |
| |||
//+------------------------------------------------------------------+
| |||
template <typename T>
| |||
T CHighQualityRand::HQRndContinuous(CHighQualityRandState &state,
| |||
int n,vector<T> &x)
| |||
{
| |||
//--- create variables
| |||
T result=0;
| |||
double mx=0;
| |||
double mn=0;
| |||
int i=0;
| |||
//--- check
| |||
if(!CAp::Assert(n>0,__FUNCTION__+": N<=0"))
| |||
return (EMPTY_VALUE);
| |||
if(!CAp::Assert(n<=(int)x.Size(),__FUNCTION__+": Length(X)<N"))
| |||
return (EMPTY_VALUE);
| |||
//--- call function
| |||
if(n==1)
| |||
{
| |||
result=x[0];
| |||
return(result);
| |||
}
| |||
i=HQRndUniformI(state,n-1);
| |||
mn=x[i];
| |||
mx=x[i+1];
| |||
if(!CAp::Assert(mx>=mn,__FUNCTION__+": X is not sorted by ascending"))
| |||
return(EMPTY_VALUE);
| |||
if(mx!=mn)
| |||
result=(T)((mx-mn)*HQRndUniformR(state)+mn);
| |||
else
| |||
result=mn;
| |||
//--- return result
| |||
return(result);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| L'Ecuyer, Efficient and portable combined random number |
| |||
//| generators |
| |||
//+------------------------------------------------------------------+
| |||
int CHighQualityRand::HQRndIntegerBase(CHighQualityRandState &state)
| |||
{
| |||
//--- create variables
| |||
int result=0;
| |||
int k=0;
| |||
//--- check
| |||
if(!CAp::Assert(state.m_magicv==m_HQRndMagic,__FUNCTION__+": State is not correctly initialized!"))
| |||
return(-1);
| |||
//--- initialization
| |||
k=state.m_s1/53668;
| |||
state.m_s1=40014*(state.m_s1-k*53668)-k*12211;
| |||
//--- check
| |||
if(state.m_s1<0)
| |||
state.m_s1=state.m_s1+2147483563;
| |||
//--- change values
| |||
k=state.m_s2/52774;
| |||
state.m_s2=40692*(state.m_s2-k*52774)-k*3791;
| |||
//--- check
| |||
if(state.m_s2<0)
| |||
state.m_s2=state.m_s2+2147483399;
| |||
//--- Result
| |||
result=state.m_s1-state.m_s2;
| |||
//--- check
| |||
if(result<1)
| |||
result=result+2147483562;
| |||
//--- return result
| |||
return(result);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Math functions |
| |||
//+------------------------------------------------------------------+
| |||
class CMath
| |||
{
| |||
public:
| |||
//--- class variables
| |||
static bool m_first_call;
| |||
static double m_last;
| |||
static CHighQualityRandState m_state;
| |||
//--- machine constants
| |||
static const double m_machineepsilon;
| |||
static const double m_maxrealnumber;
| |||
static const double m_minrealnumber;
| |||
//--- methods
| |||
static bool IsFinite(const double d);
| |||
static double RandomReal(void);
| |||
static int RandomInteger(const int n);
| |||
static double Sqr(const double x) { return(x*x); }
| |||
static double AbsComplex(const complex z);
| |||
static double AbsComplex(const double r);
| |||
static complex Conj(const complex z);
| |||
static complex Csqr(const complex z);
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
//| Initialize class constants |
| |||
//+------------------------------------------------------------------+
| |||
const double CMath::m_machineepsilon=5E-16;
| |||
const double CMath::m_maxrealnumber=1E300;
| |||
const double CMath::m_minrealnumber=1E-300;
| |||
bool CMath::m_first_call=true;
| |||
double CMath::m_last=0.0;
| |||
CHighQualityRandState CMath::m_state;
| |||
//+------------------------------------------------------------------+
| |||
//| Check on +-inf |
| |||
//+------------------------------------------------------------------+
| |||
bool CMath::IsFinite(const double d)
| |||
{
| |||
return(MathIsValidNumber(d));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Random real value [0,1) |
| |||
//+------------------------------------------------------------------+
| |||
double CMath::RandomReal(void)
| |||
{
| |||
double result;
| |||
//--- check
| |||
if(m_first_call)
| |||
{
| |||
CHighQualityRand::HQRndSeed(1+MathRand(),1+MathRand(),m_state);
| |||
m_first_call=false;
| |||
}
| |||
//--- get value
| |||
result=CHighQualityRand::HQRndUniformR(m_state);
| |||
//--- check
| |||
if(result==m_last)
| |||
{
| |||
m_first_call=true;
| |||
return(RandomReal());
| |||
}
| |||
//--- change value
| |||
m_last=result;
| |||
//--- return result
| |||
return(CHighQualityRand::HQRndUniformR(m_state));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Random integer value |
| |||
//+------------------------------------------------------------------+
| |||
int CMath::RandomInteger(const int n)
| |||
{
| |||
//--- check
| |||
if(m_first_call)
| |||
{
| |||
CHighQualityRand::HQRndSeed(1+MathRand(),1+MathRand(),m_state);
| |||
m_first_call=false;
| |||
}
| |||
//--- check and return result
| |||
if(n>=CHighQualityRand::m_HQRndM1-1)
| |||
return(CHighQualityRand::HQRndUniformI(m_state,CHighQualityRand::m_HQRndM1-2));
| |||
else
| |||
return(CHighQualityRand::HQRndUniformI(m_state,n));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| The absolute value of a complex number |
| |||
//+------------------------------------------------------------------+
| |||
double CMath::AbsComplex(const complex z)
| |||
{
| |||
//--- initialization
| |||
double xabs=MathAbs(z.real);
| |||
double yabs=MathAbs(z.imag);
| |||
//--- check
| |||
if(xabs==0)
| |||
return(yabs);
| |||
//--- check
| |||
if(yabs==0)
| |||
return(xabs);
| |||
//--- check
| |||
//--- calculation
| |||
double t=MathSqrt(MathPow(xabs,2)+MathPow(yabs,2));
| |||
//--- return result
| |||
return(t);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| The absolute value of a complex number |
| |||
//+------------------------------------------------------------------+
| |||
double CMath::AbsComplex(const double r)
| |||
{
| |||
//--- initialization
| |||
complex z=r;
| |||
double w=0.0;
| |||
double v=0.0;
| |||
double xabs=MathAbs(z.real);
| |||
double yabs=MathAbs(z.imag);
| |||
//--- check
| |||
if(xabs>yabs)
| |||
w=xabs;
| |||
else
| |||
w=yabs;
| |||
//--- check
| |||
if(xabs<yabs)
| |||
v=xabs;
| |||
else
| |||
v=yabs;
| |||
//--- check
| |||
if(v==0)
| |||
return(w);
| |||
//--- calculation
| |||
double t=v/w;
| |||
//--- return result
| |||
return(w*MathSqrt(1+t*t));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get conjugate |
| |||
//+------------------------------------------------------------------+
| |||
complex CMath::Conj(const complex z)
| |||
{
| |||
complex res;
| |||
res.real=z.real;
| |||
res.imag=-z.imag;
| |||
//--- return result
| |||
return(res);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Squaring |
| |||
//+------------------------------------------------------------------+
| |||
complex CMath::Csqr(const complex z)
| |||
{
| |||
complex res;
| |||
res.real=z.real*z.real-z.imag*z.imag;
| |||
res.imag=2*z.real*z.imag;
| |||
//--- return result
| |||
return(res);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Global array of constants |
| |||
//+------------------------------------------------------------------+
| |||
char _sixbits2char_tbl[] =
| |||
{
| |||
'0','1','2','3','4','5','6','7',
| |||
'8','9','A','B','C','D','E','F',
| |||
'G','H','I','J','K','L','M','N',
| |||
'O','P','Q','R','S','T','U','V',
| |||
'W','X','Y','Z','a','b','c','d',
| |||
'e','f','g','h','i','j','k','l',
| |||
'm','n','o','p','q','r','s','t',
| |||
'u','v','w','x','y','z','-','_'
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
//| Global array of constants |
| |||
//+------------------------------------------------------------------+
| |||
int _char2sixbits_tbl[128] =
| |||
{
| |||
-1,-1,-1,-1,-1,-1,-1,-1,
| |||
-1,-1,-1,-1,-1,-1,-1,-1,
| |||
-1,-1,-1,-1,-1,-1,-1,-1,
| |||
-1,-1,-1,-1,-1,-1,-1,-1,
| |||
-1,-1,-1,-1,-1,-1,-1,-1,
| |||
-1,-1,-1,-1,-1,62,-1,-1,
| |||
0,1,2,3,4,5,6,7,
| |||
8,9,-1,-1,-1,-1,-1,-1,
| |||
-1,10,11,12,13,14,15,16,
| |||
17,18,19,20,21,22,23,24,
| |||
25,26,27,28,29,30,31,32,
| |||
33,34,35,-1,-1,-1,-1,63,
| |||
-1,36,37,38,39,40,41,42,
| |||
43,44,45,46,47,48,49,50,
| |||
51,52,53,54,55,56,57,58,
| |||
59,60,61,-1,-1,-1,-1,-1
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
//| Serializer object (should not be used directly) |
| |||
//+------------------------------------------------------------------+
| |||
class CSerializer
| |||
{
| |||
//--- enumeration
| |||
enum SMODE { DEFAULT,ALLOC,TO_STRING,FROM_STRING };
| |||
| |||
private:
| |||
//--- class constants
| |||
static const int m_ser_entries_per_row;
| |||
static const int m_ser_entry_length;
| |||
//--- variables
| |||
SMODE m_mode;
| |||
int m_entries_needed;
| |||
int m_entries_saved;
| |||
int m_bytes_asked;
| |||
int m_bytes_written;
| |||
int m_bytes_read;
| |||
char m_out_str[];
| |||
char m_in_str[];
| |||
//---local temporaries
| |||
char m_entry_buf_char[];
| |||
char m_entry_buf_byte[];
| |||
| |||
//--- private methods
| |||
int Get_Alloc_Size(void);
| |||
static char SixBits2Char(const int v);
| |||
static int Char2SixBits(const char c);
| |||
static void ThreeBytes2FourSixBits(uchar &src[],const int src_offs,int &dst[],const int dst_offs);
| |||
static void FourSixBits2ThreeBytes(int &src[],const int src_offs,uchar &dst[],const int dst_offs);
| |||
static void Bool2Str(const bool v,char &buf[],int &offs);
| |||
static bool Str2Bool(char &buf[],int &offs);
| |||
static void Int2Str(const int v,char &buf[],int &offs);
| |||
static int Str2Int(char &buf[],int &offs);
| |||
static void Double2Str(const double v,char &buf[],int &offs);
| |||
static double Str2Double(char &buf[],int &offs);
| |||
| |||
public:
| |||
//--- constructor, destructor
| |||
CSerializer(void);
| |||
~CSerializer(void);
| |||
//--- public methods
| |||
void ClearBuffers(void);
| |||
void Alloc_Start(void);
| |||
void Alloc_Entry(void);
| |||
void Alloc_Byte_Array(char &a[]);
| |||
| |||
void SStart_Str(void);
| |||
void UStart_Str(const string s);
| |||
void Reset(void);
| |||
void Stop(void);
| |||
//--- serialization
| |||
void Serialize_Bool(const bool v);
| |||
void Serialize_Int(const int v);
| |||
void Serialize_Double(const double v);
| |||
//--- unserialization
| |||
bool Unserialize_Bool(void);
| |||
int Unserialize_Int(void);
| |||
double Unserialize_Double(void);
| |||
//--- get string
| |||
string Get_String(void);
| |||
};
| |||
//+------------------------------------------------------------------+
| |||
//| Initialize constants |
| |||
//+------------------------------------------------------------------+
| |||
const int CSerializer::m_ser_entries_per_row=5;
| |||
const int CSerializer::m_ser_entry_length=11;
| |||
//+------------------------------------------------------------------+
| |||
//| Constructor without parameters |
| |||
//+------------------------------------------------------------------+
| |||
CSerializer::CSerializer(void): m_mode(DEFAULT),m_entries_needed(0),
| |||
m_bytes_asked(0)
| |||
{
| |||
ArrayRemove(m_entry_buf_byte,m_ser_entry_length+2);
| |||
ArrayRemove(m_entry_buf_char,m_ser_entry_length+2);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Destructor |
| |||
//+------------------------------------------------------------------+
| |||
CSerializer::~CSerializer(void)
| |||
{
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::ClearBuffers(void)
| |||
{
| |||
ArrayFree(m_out_str);
| |||
ArrayFree(m_in_str);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Start |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::Alloc_Start(void)
| |||
{
| |||
//--- change values
| |||
m_entries_needed=0;
| |||
m_bytes_asked=0;
| |||
m_mode=ALLOC;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Entry |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::Alloc_Entry(void)
| |||
{
| |||
//--- check
| |||
if(m_mode!=ALLOC)
| |||
{
| |||
Print(__FUNCTION__+": internal error during (un)serialization");
| |||
//--- exit the function
| |||
return;
| |||
}
| |||
m_entries_needed++;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::Alloc_Byte_Array(char &a[])
| |||
{
| |||
if(m_mode!=ALLOC)
| |||
{
| |||
Print(__FUNCTION__": internal error during (un)serialization");
| |||
return;
| |||
}
| |||
int n=CAp::Len(a);
| |||
n=n/8+(n%8>0?1:0);
| |||
m_entries_needed+=1+n;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Switching state on TO_STRING |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::SStart_Str(void)
| |||
{
| |||
//--- get size
| |||
int allocsize=Get_Alloc_Size();
| |||
//--- clear input/output buffers which may hold pointers to unneeded memory
| |||
//--- NOTE: it also helps us to avoid errors when data are written to incorrect location
| |||
ClearBuffers();
| |||
//--- check and change m_mode
| |||
if(m_mode!=ALLOC)
| |||
{
| |||
Print(__FUNCTION__+": internal error during (un)serialization");
| |||
//--- exit the function
| |||
return;
| |||
}
| |||
m_mode=TO_STRING;
| |||
//--- other preparations
| |||
ArrayResizeAL(m_out_str,allocsize);
| |||
m_entries_saved=0;
| |||
m_bytes_written=0;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Switching state on FROM_STRING |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::UStart_Str(const string s)
| |||
{
| |||
//--- check and change m_mode
| |||
if(m_mode!=DEFAULT)
| |||
{
| |||
Print(__FUNCTION__+": internal error during (un)serialization");
| |||
//--- exit the function
| |||
return;
| |||
}
| |||
m_mode=FROM_STRING;
| |||
StringToCharArray(s,m_in_str);
| |||
m_bytes_read=0;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Reset parameters |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::Reset(void)
| |||
{
| |||
m_mode=DEFAULT;
| |||
m_entries_needed=0;
| |||
m_bytes_asked=0;
| |||
ClearBuffers();
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Serialize bool |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::Serialize_Bool(const bool v)
| |||
{
| |||
//--- check
| |||
if(m_mode!=TO_STRING)
| |||
{
| |||
Print(__FUNCTION__+": internal error during (un)serialization");
| |||
//--- exit the function
| |||
return;
| |||
}
| |||
//--- function call
| |||
Bool2Str(v,m_out_str,m_bytes_written);
| |||
m_entries_saved++;
| |||
//--- check
| |||
if(m_entries_saved%m_ser_entries_per_row!=0)
| |||
{
| |||
m_out_str[m_bytes_written]=' ';
| |||
m_bytes_written++;
| |||
}
| |||
else
| |||
{
| |||
m_out_str[m_bytes_written+0]='\r';
| |||
m_out_str[m_bytes_written+1]='\n';
| |||
m_bytes_written+=2;
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Serialize int |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::Serialize_Int(const int v)
| |||
{
| |||
//--- check
| |||
if(m_mode!=TO_STRING)
| |||
{
| |||
Print(__FUNCTION__+": internal error during (un)serialization");
| |||
//--- exit the function
| |||
return;
| |||
}
| |||
//--- function call
| |||
Int2Str(v,m_out_str,m_bytes_written);
| |||
m_entries_saved++;
| |||
//--- check
| |||
if(m_entries_saved%m_ser_entries_per_row!=0)
| |||
{
| |||
m_out_str[m_bytes_written]=' ';
| |||
m_bytes_written++;
| |||
}
| |||
else
| |||
{
| |||
m_out_str[m_bytes_written+0]='\r';
| |||
m_out_str[m_bytes_written+1]='\n';
| |||
m_bytes_written+=2;
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Serialize double |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::Serialize_Double(const double v)
| |||
{
| |||
//--- check
| |||
if(m_mode!=TO_STRING)
| |||
{
| |||
Print(__FUNCTION__+": internal error during (un)serialization");
| |||
//--- exit the function
| |||
return;
| |||
}
| |||
//--- function call
| |||
Double2Str(v,m_out_str,m_bytes_written);
| |||
m_entries_saved++;
| |||
//--- check
| |||
if(m_entries_saved%m_ser_entries_per_row!=0)
| |||
{
| |||
m_out_str[m_bytes_written]=' ';
| |||
m_bytes_written++;
| |||
}
| |||
else
| |||
{
| |||
m_out_str[m_bytes_written+0]='\r';
| |||
m_out_str[m_bytes_written+1]='\n';
| |||
m_bytes_written+=2;
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Unserialize bool |
| |||
//+------------------------------------------------------------------+
| |||
bool CSerializer::Unserialize_Bool(void)
| |||
{
| |||
//--- check
| |||
if(m_mode!=FROM_STRING)
| |||
{
| |||
Print(__FUNCTION__+": internal error during (un)serialization");
| |||
//--- return result
| |||
return(false);
| |||
}
| |||
//--- return result
| |||
return(Str2Bool(m_in_str,m_bytes_read));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Unserialize int |
| |||
//+------------------------------------------------------------------+
| |||
int CSerializer::Unserialize_Int(void)
| |||
{
| |||
//--- check
| |||
if(m_mode!=FROM_STRING)
| |||
{
| |||
Print(__FUNCTION__+": internal error during (un)serialization");
| |||
//--- return result
| |||
return(-1);
| |||
}
| |||
//--- return result
| |||
return(Str2Int(m_in_str,m_bytes_read));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Unserialize double |
| |||
//+------------------------------------------------------------------+
| |||
double CSerializer::Unserialize_Double(void)
| |||
{
| |||
//--- check
| |||
if(m_mode!=FROM_STRING)
| |||
{
| |||
Print(__FUNCTION__+": internal error during (un)serialization");
| |||
//--- return result
| |||
return(EMPTY_VALUE);
| |||
}
| |||
//--- return result
| |||
return(Str2Double(m_in_str,m_bytes_read));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Stop |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::Stop(void)
| |||
{
| |||
if(m_mode==TO_STRING)
| |||
{
| |||
m_out_str[m_bytes_written]='.';
| |||
m_bytes_written++;
| |||
return;
| |||
}
| |||
if(m_mode==FROM_STRING)
| |||
{
| |||
//--- because input string may be from pre-3.11 serializer,
| |||
//--- which does not include trailing dot, we do not test
| |||
//--- string for presence of "." symbol. Anyway, because string
| |||
//--- is not stream, we do not have to read ALL trailing symbols.
| |||
return;
| |||
}
| |||
Print(__FUNCTION__": internal error during unserialization");
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get string |
| |||
//+------------------------------------------------------------------+
| |||
string CSerializer::Get_String(void)
| |||
{
| |||
return(GetSelectionString(m_out_str,0,m_bytes_written));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| Get alloc size |
| |||
//+------------------------------------------------------------------+
| |||
int CSerializer::Get_Alloc_Size(void)
| |||
{
| |||
//--- create variables
| |||
int rows;
| |||
int lastrowsize;
| |||
int result;
| |||
//--- check and change m_mode
| |||
if(m_mode!=ALLOC)
| |||
{
| |||
Print(__FUNCTION__+": internal error during (un)serialization");
| |||
//--- return result
| |||
return(-1);
| |||
}
| |||
//--- if no entries needes (degenerate case)
| |||
if(m_entries_needed==0)
| |||
{
| |||
m_bytes_asked=1;
| |||
//--- return result
| |||
return(m_bytes_asked);
| |||
}
| |||
//--- non-degenerate case
| |||
rows=m_entries_needed/m_ser_entries_per_row;
| |||
lastrowsize=m_ser_entries_per_row;
| |||
//--- check
| |||
if(m_entries_needed%m_ser_entries_per_row!=0)
| |||
{
| |||
lastrowsize=m_entries_needed%m_ser_entries_per_row;
| |||
rows++;
| |||
}
| |||
//--- calculate result size
| |||
result=((rows-1)*m_ser_entries_per_row+lastrowsize)*m_ser_entry_length;
| |||
result+=(rows-1)*(m_ser_entries_per_row-1)+(lastrowsize-1);
| |||
result+=rows*2;
| |||
//--- save result
| |||
m_bytes_asked=result;
| |||
//--- return result
| |||
return(result);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function converts six-bit value (from 0 to 63) to character |
| |||
//| (only digits, lowercase and uppercase letters, minus and |
| |||
//| underscore are used). If v is negative or greater than 63, this |
| |||
//| function returns '?'. |
| |||
//+------------------------------------------------------------------+
| |||
char CSerializer::SixBits2Char(const int v)
| |||
{
| |||
//--- check
| |||
if(v<0 || v>63)
| |||
return('?');
| |||
//--- return result
| |||
return(_sixbits2char_tbl[v]);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function converts character to six-bit value (from 0 to 63).|
| |||
//| This function is inverse of ae_sixbits2char() |
| |||
//| If c is not correct character, this function returns -1. |
| |||
//+------------------------------------------------------------------+
| |||
int CSerializer::Char2SixBits(const char c)
| |||
{
| |||
//--- check
| |||
if(c>=0 && c<127)
| |||
return(_char2sixbits_tbl[c]);
| |||
//--- return result
| |||
return(-1);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function converts three bytes (24 bits) to four six-bit |
| |||
//| values (24 bits again). |
| |||
//| src array |
| |||
//| src_offs offset of three-bytes chunk |
| |||
//| dst array for ints |
| |||
//| dst_offs offset of four-ints chunk |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::ThreeBytes2FourSixBits(uchar &src[],const int src_offs,
| |||
int &dst[],const int dst_offs)
| |||
{
| |||
//--- get bits
| |||
dst[dst_offs+0]=src[src_offs+0]&0x3F;
| |||
dst[dst_offs+1]=(src[src_offs+0]>>6)|((src[src_offs+1]&0x0F)<<2);
| |||
dst[dst_offs+2]=(src[src_offs+1]>>4)|((src[src_offs+2]&0x03)<<4);
| |||
dst[dst_offs+3]=src[src_offs+2]>>2;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function converts four six-bit values (24 bits) to three |
| |||
//| bytes (24 bits again). |
| |||
//| src pointer to four ints |
| |||
//| src_offs offset of the chunk |
| |||
//| dst pointer to three bytes |
| |||
//| dst_offs offset of the chunk |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::FourSixBits2ThreeBytes(int &src[],const int src_offs,
| |||
uchar &dst[],const int dst_offs)
| |||
{
| |||
//--- get bytes
| |||
dst[dst_offs+0]=(uchar)(src[src_offs+0]|((src[src_offs+1]&0x03)<<6));
| |||
dst[dst_offs+1]=(uchar)((src[src_offs+1]>>2)|((src[src_offs+2]&0x0F)<<4));
| |||
dst[dst_offs+2]=(uchar)((src[src_offs+2]>>4)|(src[src_offs+3]<<2));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function serializes boolean value into buffer |
| |||
//| v boolean value to be serialized |
| |||
//| buf buffer, at least 11 characters wide |
| |||
//| offs offset in the buffer |
| |||
//| after return(from this function, offs points to the char's past |
| |||
//| the value being read. |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::Bool2Str(const bool v,char &buf[],int &offs)
| |||
{
| |||
char c;
| |||
//--- check
| |||
if(v)
| |||
c='1';
| |||
else
| |||
c='0';
| |||
//--- copy c
| |||
for(int i=0; i<m_ser_entry_length; i++)
| |||
buf[offs+i]=c;
| |||
//--- change value
| |||
offs+=m_ser_entry_length;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function unserializes boolean value from buffer |
| |||
//| buf buffer which contains value;leading |
| |||
//| spaces/tabs/newlines are ignored, traling |
| |||
//| spaces/tabs/newlines are treated as end of the |
| |||
//| boolean value. |
| |||
//| offs offset in the buffer |
| |||
//| after return(from this function, offs points to the char's past |
| |||
//| the value being read. |
| |||
//| This function raises an error in case unexpected symbol is found |
| |||
//+------------------------------------------------------------------+
| |||
bool CSerializer::Str2Bool(char &buf[],int &offs)
| |||
{
| |||
//--- create variables
| |||
bool was0;
| |||
bool was1;
| |||
string emsg=": unable to read boolean value from stream";
| |||
//--- initialization
| |||
was0=false;
| |||
was1=false;
| |||
//--- shift
| |||
while(buf[offs]==' ' || buf[offs]=='\t' || buf[offs]=='\n' || buf[offs]=='\r')
| |||
offs++;
| |||
//--- cycle
| |||
while(buf[offs]!=' ' && buf[offs]!='\t' && buf[offs]!='\n' && buf[offs]!='\r' && buf[offs]!=0)
| |||
{
| |||
//--- check
| |||
if(buf[offs]=='0')
| |||
{
| |||
was0=true;
| |||
offs++;
| |||
continue;
| |||
}
| |||
//--- check
| |||
if(buf[offs]=='1')
| |||
{
| |||
was1=true;
| |||
offs++;
| |||
continue;
| |||
}
| |||
Print(__FUNCTION__+" " + emsg);
| |||
//--- return result
| |||
return(false);
| |||
}
| |||
//--- check
| |||
if((!was0) && (!was1))
| |||
{
| |||
Print(__FUNCTION__+" " + emsg);
| |||
//--- return result
| |||
return(false);
| |||
}
| |||
//--- check
| |||
if(was0 && was1)
| |||
{
| |||
Print(__FUNCTION__+" " + emsg);
| |||
//--- return result
| |||
return(false);
| |||
}
| |||
//--- check
| |||
if(was1)
| |||
return(true);
| |||
//--- return result
| |||
return(false);
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function serializes integer value into buffer |
| |||
//| v integer value to be serialized |
| |||
//| buf buffer, at least 11 characters wide |
| |||
//| offs offset in the buffer |
| |||
//| after return(from this function, offs points to the char's past |
| |||
//| the value being read. |
| |||
//| This function raises an error in case unexpected symbol is found |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::Int2Str(const int v,char &buf[],int &offs)
| |||
{
| |||
//--- create variables
| |||
int i;
| |||
uchar c;
| |||
uchar _bytes[];
| |||
//--- get bytes of v
| |||
BitConverter::GetBytes(v,_bytes);
| |||
//--- create arrays
| |||
uchar bytes[];
| |||
int sixbits[];
| |||
//--- allocation
| |||
ArrayResizeAL(bytes,9);
| |||
ArrayResizeAL(sixbits,12);
| |||
//--- copy v to array of bytes, sign extending it and
| |||
//--- converting to little endian order. Additionally,
| |||
//--- we set 9th byte to zero in order to simplify
| |||
//--- conversion to six-bit representation
| |||
if(!BitConverter::IsLittleEndian())
| |||
ArrayReverse(_bytes);
| |||
//--- check
| |||
if(v<0)
| |||
c=(uchar)0xFF;
| |||
else
| |||
c=(uchar)0x00;
| |||
//--- copy
| |||
for(i=0; i<sizeof(int); i++)
| |||
bytes[i]=_bytes[i];
| |||
//--- fill remaining part
| |||
for(i=sizeof(int); i<8; i++)
| |||
bytes[i]=c;
| |||
bytes[8]=0;
| |||
//--- convert to six-bit representation, output
| |||
//--- NOTE: last 12th element of sixbits is always zero, we do not output it
| |||
ThreeBytes2FourSixBits(bytes,0,sixbits,0);
| |||
ThreeBytes2FourSixBits(bytes,3,sixbits,4);
| |||
ThreeBytes2FourSixBits(bytes,6,sixbits,8);
| |||
//--- copy
| |||
for(i=0; i<m_ser_entry_length; i++)
| |||
buf[offs+i]=SixBits2Char(sixbits[i]);
| |||
//--- change value
| |||
offs+=m_ser_entry_length;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function unserializes integer value from string |
| |||
//| buf buffer which contains value;leading |
| |||
//| spaces/tabs/newlines are ignored, traling |
| |||
//| spaces/tabs/newlines are treated as end of the |
| |||
//| integer value. |
| |||
//| offs offset in the buffer |
| |||
//| after return(from this function, offs points to the char's past |
| |||
//| the value being read. |
| |||
//| This function raises an error in case unexpected symbol is found |
| |||
//+------------------------------------------------------------------+
| |||
int CSerializer::Str2Int(char &buf[],int &offs)
| |||
{
| |||
//--- create variables
| |||
string emsg=": unable to read integer value from stream";
| |||
string emsg3264=": unable to read integer value from stream (value does not fit into 32 bits)";
| |||
int sixbitsread;
| |||
int i;
| |||
uchar c;
| |||
//--- create arrays
| |||
int sixbits[];
| |||
uchar bytes[];
| |||
uchar _bytes[];
| |||
//--- allocation
| |||
ArrayResizeAL(sixbits,12);
| |||
ArrayResizeAL(bytes,9);
| |||
ArrayResizeAL(_bytes,sizeof(int));
| |||
//--- 1. skip leading spaces
| |||
//--- 2. read and decode six-bit digits
| |||
//--- 3. set trailing digits to zeros
| |||
//--- 4. convert to little endian 64-bit integer representation
| |||
//--- 5. check that we fit into int
| |||
//--- 6. convert to big endian representation, if needed
| |||
sixbitsread=0;
| |||
while(buf[offs]==' ' || buf[offs]=='\t' || buf[offs]=='\n' || buf[offs]=='\r')
| |||
offs++;
| |||
while(buf[offs]!=' ' && buf[offs]!='\t' && buf[offs]!='\n' && buf[offs]!='\r' && buf[offs]!=0)
| |||
{
| |||
int d;
| |||
//--- function call
| |||
d=Char2SixBits(buf[offs]);
| |||
//--- check
| |||
if(d<0 || sixbitsread>=m_ser_entry_length)
| |||
{
| |||
Print(__FUNCTION__+" " + emsg);
| |||
//--- return result
| |||
return(-1);
| |||
}
| |||
sixbits[sixbitsread]=d;
| |||
sixbitsread++;
| |||
offs++;
| |||
}
| |||
//--- check
| |||
if(sixbitsread==0)
| |||
{
| |||
Print(__FUNCTION__+" " + emsg);
| |||
//--- return result
| |||
return(-1);
| |||
}
| |||
for(i=sixbitsread; i<12; i++)
| |||
sixbits[i]=0;
| |||
//--- function call
| |||
FourSixBits2ThreeBytes(sixbits,0,bytes,0);
| |||
//--- function call
| |||
FourSixBits2ThreeBytes(sixbits,4,bytes,3);
| |||
//--- function call
| |||
FourSixBits2ThreeBytes(sixbits,8,bytes,6);
| |||
//--- check
| |||
if((bytes[sizeof(int) -1]&0x80)!=0)
| |||
c=(uchar)0xFF;
| |||
else
| |||
c=(uchar)0x00;
| |||
for(i=sizeof(int); i<8; i++)
| |||
//--- check
| |||
if(bytes[i]!=c)
| |||
{
| |||
Print(__FUNCTION__+" " + emsg3264);
| |||
//--- return result
| |||
return(-1);
| |||
}
| |||
//--- copy
| |||
for(i=0; i<sizeof(int); i++)
| |||
_bytes[i]=bytes[i];
| |||
//--- check
| |||
if(!BitConverter::IsLittleEndian())
| |||
ArrayReverse(_bytes);
| |||
//--- return result
| |||
return(BitConverter::ToInt32(_bytes));
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function serializes double value into buffer |
| |||
//| v double value to be serialized |
| |||
//| buf buffer, at least 11 characters wide |
| |||
//| offs offset in the buffer |
| |||
//| after return(from this function, offs points to the char's past |
| |||
//| the value being read. |
| |||
//+------------------------------------------------------------------+
| |||
void CSerializer::Double2Str(const double v,char &buf[],int &offs)
| |||
{
| |||
//--- create variable
| |||
int i;
| |||
//--- create arrays
| |||
uchar bytes[];
| |||
int sixbits[];
| |||
//--- allocation
| |||
ArrayResizeAL(sixbits,12);
| |||
ArrayResizeAL(bytes,9);
| |||
//--- handle special quantities
| |||
if(CInfOrNaN::IsNaN(v))
| |||
{
| |||
buf[offs+0]='.';
| |||
buf[offs+1]='n';
| |||
buf[offs+2]='a';
| |||
buf[offs+3]='n';
| |||
buf[offs+4]='_';
| |||
buf[offs+5]='_';
| |||
buf[offs+6]='_';
| |||
buf[offs+7]='_';
| |||
buf[offs+8]='_';
| |||
buf[offs+9]='_';
| |||
buf[offs+10]='_';
| |||
offs+=m_ser_entry_length;
| |||
//--- exit the function
| |||
return;
| |||
}
| |||
//--- check
| |||
if(CInfOrNaN::IsPositiveInfinity(v))
| |||
{
| |||
buf[offs+0]='.';
| |||
buf[offs+1]='p';
| |||
buf[offs+2]='o';
| |||
buf[offs+3]='s';
| |||
buf[offs+4]='i';
| |||
buf[offs+5]='n';
| |||
buf[offs+6]='f';
| |||
buf[offs+7]='_';
| |||
buf[offs+8]='_';
| |||
buf[offs+9]='_';
| |||
buf[offs+10]='_';
| |||
offs+=m_ser_entry_length;
| |||
//--- exit the function
| |||
return;
| |||
}
| |||
//--- check
| |||
if(CInfOrNaN::IsNegativeInfinity(v))
| |||
{
| |||
buf[offs+0]='.';
| |||
buf[offs+1]='n';
| |||
buf[offs+2]='e';
| |||
buf[offs+3]='g';
| |||
buf[offs+4]='i';
| |||
buf[offs+5]='n';
| |||
buf[offs+6]='f';
| |||
buf[offs+7]='_';
| |||
buf[offs+8]='_';
| |||
buf[offs+9]='_';
| |||
buf[offs+10]='_';
| |||
offs+=m_ser_entry_length;
| |||
//--- exit the function
| |||
return;
| |||
}
| |||
//--- process general case:
| |||
//--- 1. copy v to array of chars
| |||
//--- 2. set 9th byte to zero in order to simplify conversion to six-bit representation
| |||
//--- 3. convert to little endian (if needed)
| |||
//--- 4. convert to six-bit representation
| |||
//--- (last 12th element of sixbits is always zero, we do not output it)
| |||
uchar _bytes[];
| |||
BitConverter::GetBytes(v,_bytes);
| |||
//--- check
| |||
if(!BitConverter::IsLittleEndian())
| |||
ArrayReverse(_bytes);
| |||
//--- copy
| |||
for(i=0; i<sizeof(double); i++)
| |||
bytes[i]=_bytes[i];
| |||
//--- filling
| |||
for(i=sizeof(double); i<9; i++)
| |||
bytes[i]=0;
| |||
//--- function call
| |||
ThreeBytes2FourSixBits(bytes,0,sixbits,0);
| |||
//--- function call
| |||
ThreeBytes2FourSixBits(bytes,3,sixbits,4);
| |||
//--- function call
| |||
ThreeBytes2FourSixBits(bytes,6,sixbits,8);
| |||
//--- function call
| |||
for(i=0; i<m_ser_entry_length; i++)
| |||
buf[offs+i]=SixBits2Char(sixbits[i]);
| |||
//--- change value
| |||
offs+=m_ser_entry_length;
| |||
}
| |||
//+------------------------------------------------------------------+
| |||
//| This function unserializes double value from string |
| |||
//| buf buffer which contains value;leading |
| |||
//| spaces/tabs/newlines are ignored, traling |
| |||
//| spaces/tabs/newlines are treated as end of the |
| |||
//| double value. |
| |||
//| offs offset in the buffer |
| |||
//| after return(from this function, offs points to the char's past |
| |||
//| the value being read. |
| |||
//| This function raises an error in case unexpected symbol is found |
| |||
//+------------------------------------------------------------------+
| |||
double CSerializer::Str2Double(char &buf[],int &offs)
| |||
{
| |||
//--- create variables
| |||
string emsg="ALGLIB: unable to read double value from stream";
| |||
int sixbitsread;
| |||
//--- create arrays
| |||
uchar bytes[];
| |||
uchar _bytes[];
| |||
int sixbits[];
| |||
//--- allocation
| |||
ArrayResizeAL(bytes,9);
| |||
ArrayResizeAL(sixbits,12);
| |||
ArrayResizeAL(_bytes,sizeof(double));
| |||
//--- skip leading spaces
| |||
while(buf[offs]==' ' || buf[offs]=='\t' || buf[offs]=='\n' || buf[offs]=='\r')
| |||
offs++;
| |||
//--- Handle special cases
| |||
if(buf[offs]=='.')
| |||
{
| |||
//--- function call
| |||
string s=GetSelectionString(buf,offs,m_ser_entry_length);
| |||
//--- check
| |||
if(s==".nan_______")
| |||
{
| |||
offs+=m_ser_entry_length;
| |||
//--- return result
| |||
return(CInfOrNaN::NaN());
| |||
}
| |||
//--- check
| |||
if(s==".posinf____")
| |||
{
| |||
offs+=m_ser_entry_length;
| |||
//--- return result
| |||
return(CInfOrNaN::PositiveInfinity());
| |||
}
| |||
//--- check
| |||
if(s==".neginf____")
| |||
{
| |||
offs+=m_ser_entry_length;
| |||
//--- return result
| |||
return(CInfOrNaN::NegativeInfinity());
| |||
}
| |||
Print(__FUNCTION__+"emsg");
| |||
//--- return result
| |||
return(EMPTY_VALUE);
| |||
}
| |||
//--- General case:
| |||
//--- 1. read and decode six-bit digits
| |||
//--- 2. check that all 11 digits were read
| |||
//--- 3. set last 12th digit to zero (needed for simplicity of conversion)
| |||
//--- 4. convert to 8 bytes
| |||
//--- 5. convert to big endian representation, if needed
| |||
sixbitsread=0;
| |||
while(buf[offs]!=' ' && buf[offs]!='\t' && buf[offs]!='\n' && buf[offs]!='\r' && buf[offs]!=0)
| |||
{
| |||
int d;
| |||
//--- function call
| |||
d=Char2SixBits(buf[offs]);
| |||
//--- check
| |||
if(d<0 || sixbitsread>=m_ser_entry_length)
| |||
{
| |||
Print(__FUNCTION__+"emsg");
| |||
//--- return result
| |||
return(EMPTY_VALUE);
| |||
}
| |||
sixbits[sixbitsread]=d;
| |||
sixbitsread++;
| |||
offs++;
| |||
}
| |||
//--- check
| |||
if(sixbitsread!=m_ser_entry_length)
| |||
{
| |||
Print(__FUNCTION__+"emsg");
| |||
//--- return result
| |||
return(EMPTY_VALUE);
| |||
}
| |||
sixbits[m_ser_entry_length]=0;
| |||
//--- function call
| |||
FourSixBits2ThreeBytes(sixbits,0,bytes,0);
| |||
//--- function call
| |||
FourSixBits2ThreeBytes(sixbits,4,bytes,3);
| |||
//--- function call
| |||
FourSixBits2ThreeBytes(sixbits,8,bytes,6);
| |||
//--- copy
| |||
for(int i=0; i<sizeof(double); i++)
| |||
_bytes[i]=bytes[i];
| |||
//--- check
| |||
if(!BitConverter::IsLittleEndian())
| |||
ArrayReverse(_bytes);
| |||
//--- return result
| |||
return(BitConverter::ToDouble(_bytes));
| |||
}
| |||
//+------------------------------------------------------------------+
|