Discussão do artigo "Distribuições estatísticas no MQL5 - tirando o melhor de R" - página 7

 
ivanivan_11:

Estou falando de R, mas minha habilidade é muito pequena)) Alguém pode verificar se o código está correto?

Se o código estiver correto, você pode verificar o benchmark?

O código está errado.

Você mediu o tempo de compilação da função, não de sua execução:

A função cmpfun compila o corpo de uma closure e retorna uma nova closure com os mesmos formais e o corpo substituído pela expressão do corpo compilado.


Prova do erro:

> library(microbenchmark)
> library(compiler)
> n <- 2000
> k <- seq(0,n,by=20)
> qqq<- function(xx) { a <- dbinom(k, n, pi/10, log = TRUE) }
> res <- microbenchmark(cmpfun(qqq))
> a
Ошибка: объект 'a' не найден

Se a função qqq tivesse sido executada durante o benchmark, o objeto a teria recebido os dados computados. Mas, em vez disso, descobriu-se que o objeto nem sequer foi criado.

Como resultado, o parâmetro de comparação contou o tempo de compilação em vez do tempo de execução. Em meu código, tudo está correto: o benchmark conta o tempo de execução real e o objeto a é criado com os dados corretos.


E sim, a compilação é um processo bastante dispendioso: ela é mostrada em milissegundos em vez de microssegundos

> print(res)
Unit: milliseconds
        expr      min       lq     mean   median       uq      max neval
 cmpfun(qqq) 1.741577 1.783867 1.856366 1.812613 1.853096 2.697548   100
 

E uma piada à parte, como você substituiu a função do sistema q() - sair - em seu exemplo.

Não havia como sair do R :)

 
Dr.Trader:

Quero dizer que o compilador mql já conhece todos os parâmetros de entrada no momento da compilação. É suficiente que ele calcule tudo durante a compilação e, ao chamar o script, ele apenas retorna o resultado pré-calculado. Vi alguns artigos no hub em que eles comparavam compiladores c++ e, a julgar pela análise do código assembler, é exatamente isso que acontece lá.

Sim, ele pode estar usando-o ativamente. Aqui estão alguns exemplos: https://www.mql5.com/ru/forum/58241.

Mas, nesse caso, isso não funcionará - você precisa contar por completo devido à complexidade, ao loop e ao preenchimento de array.

 
ivanivan_11:

Se o código estiver correto, você pode verificar o benchmark?

Você precisa substituirres <- microbenchmark(cmpfun ( q)) por res <- microbenchmark(q())). Mas as bibliotecas compiladas anteriormente não serão recompiladas em bytecode, obtive os mesmos resultados.

Renat Fatkhullin:
qqq<- function(xx) { a <- dbinom(k, n, pi/10, log = TRUE) }

"a", nesse caso, será uma variável local, inacessível fora da própria função. Mas você pode fazer isso desta forma -
a <<- dbinom(k, n, pi/10, log = TRUE)
então ela será uma variável global.

Renat Fatkhullin:

Mas, nesse caso, isso não funcionará - você precisa contar por completo devido à complexidade, ao loop e ao preenchimento da matriz.

Entendo, então a velocidade de execução é excelente

 

A propósito, não custa praticamente nada interpretar a chamada primitiva a <- dbinom(k, n, pi/10, log = TRUE) com uma queda direta no kernel do R com execução nativa(dbinom está em r.dll).

Portanto, tentar compilar essa chamada é obviamente inútil.

 

Como já escrevi muitas vezes sobre a rapidez do R, deixe-me colocar meus cinco centavos.

Caro Renat!

Seu exemplo não tem nada de mais!

Você pegou duas funções semelhantes e tirou uma conclusão sobre o desempenho do R.

As funções que você forneceu não representam o poder e a diversidade do R.

Você deve comparar operações com capacidade computacional.

Por exemplo, multiplicação de matriz...

Vamos medir a expressão no R

c <- a*b,

em que a e b são matrizes de tamanho mínimo de 100*100. Em seu código, certifique-se de que o R use o MKL da Intel. E isso é feito simplesmente instalando a versão correspondente do R.

Se olharmos para o R, veremos que há montanhas de código contendo operações computacionalmente intensivas. Para executá-las, são usadas bibliotecas, que são as mais eficientes no momento.

E a utilidade do R na negociação não está nas funções que você reescreveu (embora elas também sejam necessárias), mas nos modelos. Em uma de minhas respostas a você, mencionei o pacote caret. Veja o que ele é.... A implementação de qualquer modelo de negociação praticamente útil dentro da estrutura desse pacote e no µl lhe dará a resposta

Além disso, não se esqueça de que carregar todos os núcleos de um computador é uma rotina do R. Além disso, você pode carregar comps vizinhas na rede local.

PS.

Para mim, a ideia de comparar o desempenho do MKL e do R é questionável: esses dois sistemas têm áreas temáticas completamente diferentes

 

SanSanych, testaremos tudo e lançaremos um benchmark. Mas primeiro vamos concluir a funcionalidade.

O teste foi justificado e revelou imediatamente o problema. Apresentei a justificativa teórica e tenho certeza de que a sobrecarga do sistema do R será preservada para a enorme quantidade de funcionalidades.

Podemos multiplicar as matrizes de tal forma que a Intel perderá. Não se trata de ciência de foguetes há muito tempo, e a Intel (ou melhor, esses programadores terceirizados dentro da afiliação da empresa) não é campeã em conhecimento mítico de seus processadores.

[Excluído]  
СанСаныч Фоменко:

Como já escrevi muitas vezes sobre a rapidez do R, deixe-me colocar meus cinco centavos.

.................

Para San-Sanych e os outros colegas.

San-Sanych, você sabe o quanto eu o respeito... ((S) Kataev e Feinzilberg, conhecidos como "Ilf e Petrov"), apesar de algumas de suas piadas pós-soviéticas aqui.

Deixe-me esclarecer algo importante para você:

1). O principal trabalho de um programador não é escrever programas, mas LER programas, especialmente os seus próprios. Qualquer programador 95... 99% do seu tempo fica sentado olhando para o monitor. Ele escreve um programa? Não, na maioria das vezes ele o lê. Portanto, quanto mais próximo da linguagem natural for o que ele lê na tela, ou seja, do que lhe foi ensinado pela mãe, pelo pai, pela avó, pelo professor da escola, mais eficientemente ele decifrará essas krakozebras linguisticamente obedientes na tela e encontrará a correspondência entre o algoritmo e seu programa.

2). Para os fins do ponto (1), não há nada melhor, em média, do que a linguagem C. É por isso que, por exemplo, eu pessoalmente (bem como 2-3 pessoas responsáveis e não muito responsáveis) consegui escrever um projeto com mais de 700 sub-rotinas em C, MQL4, CUDA..... E tudo funciona.

3). Do ponto de vista do ponto (1), a variante orientada a objetos do C, ou seja, o C++, é muito pior. (Mas falaremos disso em outra ocasião).

4). A compatibilidade total do C clássico com a MQL4 é simplesmente inestimável. A transferência de um procedimento para frente e para trás leva meio minuto.

5). A principal vantagem do C+MQL4 é a CLAREZA. Ou seja, a compreensibilidade e a transparência de tudo o que está na tela do programador.

Se compararmos o C-MQL4 com o seu R, não devemos olhar para a velocidade e o volume do código escrito, mas para a CLAREZA do texto. Ou seja, sua compreensibilidade. Caso contrário, o programador ficará olhando para a tela por 24 horas em tentativas vãs de entender o que o programa faz, quais parâmetros ele tem, por que o autor os nomeou assim e, em geral, por que o programador fez isso dessa maneira e não de outra. Não é a velocidade do programa que é importante aqui, mas a correção de seu trabalho e a velocidade de sua APLICABILIDADE para o programador final.

Desse ponto de vista, o que o Metaquotes fez foi, obviamente, um grande apoio para aqueles que querem inserir estatísticas em seus EAs. Não há nada que se compare em termos de simplicidade e compreensibilidade das funções. E isso é importante. Especialmente se você tiver cálculos delicados (e o Forex e as negociações em geral exigem cálculos delicados).

Vamos comparar.

Aqui está a aparência da função de integração em C - MQL4:

//__________________________________________________________________
//|
// Integral_Simpson_3_Points_Lite ()|
//_______________________________________________________|
#define  FACTOR_1_3      (1.0 / 3.0)

double Integral_Simpson_3_Points_Lite
(
   double       & Price_Array[],
   int          Period_Param,
   int          Last_Bar
)
{
        double  Sum, Sum_Full_Cycles, Sum_Tail, Sum_Total;
        int             i, j;
        int             Quant;
        int             Full_Cycles;
        int             Tail_Limit;
        int             Tail_Start;

        //..................................................................
        if (Last_Bar < 0)
        {
                Last_Bar = 0;
        }
        //.........................................
        if (Period_Param <= 1)
        {
                return (0.0);
        }
        //.................................................................
        if (Period_Param == 2)
        {
                return (0.5 * (Price_Array[Last_Bar] + Price_Array[Last_Bar + 1]));
        }
        //=============================================================================================
        //=============================================================================================
        Quant = 3;
        Full_Cycles = (Period_Param - 1) / (Quant - 1);
        Tail_Start = Full_Cycles * (Quant - 1);
        Tail_Limit = Period_Param - Tail_Start;
        //...........................................................
        j = Last_Bar;

        Sum = 0.0;
        for (i = 0; i < Full_Cycles; i ++)
        {
                //.........................................................................
                Sum += Price_Array[j];
                Sum += 4.0 * Price_Array[j + 1];
                Sum += Price_Array[j + 2];
                j = j + (Quant - 1);
        }
        //...........................................................
        Sum_Full_Cycles = Sum * FACTOR_1_3;
        Sum_Tail = Integral_Trapezoid_Lite (Price_Array,
                                            Tail_Limit,
                                            Last_Bar + Tail_Start);
        //.........................................................................
        Sum_Total = Sum_Full_Cycles + Sum_Tail;
        //...............................................................
        return (Sum_Total) ;

}
[Excluído]  

Vou escrever em partes, pois é mais fácil escrever dessa forma.

Há uma função de integração trapezoidal em seu interior:

//__________________________________________________________________
//|
// Integral_Trapezoid_Lite ()|
//_______________________________________________________|
double Integral_Trapezoid_Lite
(
   double       & Price_Array[],
   int          Period_Param,
   int          Last_Bar
)
{
        double  Sum;
        int             i;
        int             Price_Index ;
        //.........................................
        if (Last_Bar < 0)
        {
                Last_Bar = 0;
        }
        //.........................................
        if (Period_Param <= 1)
        {
                return (0.0);
        }
        //.................................................................
        if (Period_Param == 2)
        {
                return (0.5 * (Price_Array[Last_Bar] + Price_Array[Last_Bar + 1]));
        }
        //..................................................................
        //..................................................................
        Sum = 0.0;
        for (i = 0; i < Period_Param; i++)
        {
                Price_Index = Last_Bar + i;
                if (Price_Index < 0)
                {
                        break;
                }
                //........................................
                if ((i == 0) || (i == (Period_Param - 1)))
                {
                        Sum = Sum + Price_Array[i] * 0.5;
                }
                else
                {
                        Sum = Sum + Price_Array[i];
                }
        }
        //...............................................................
        return (Sum) ;
}
[Excluído]  

Tudo é absolutamente claro e compreensível. E o mais importante é que ele sempre funciona e funciona bem, ou seja, com poucos erros, mesmo no MT4-MQL4, o que economiza muito tempo.

Mas se você quiser descobrir por que tem erros incompreensíveis ao trabalhar no R, ou se quiser apenas entender quais parâmetros existem no procedimento de integração ou qual método de integração foi programado, você verá o seguinte (Deus me perdoe por postar isso para crianças imaturas em programação):

http://www.netlib.org/quadpack/

Esse é apenas o título da função originalmente escrita em Fortran. O texto principal virá mais tarde. Esse é o programa original usado no pacote R para integração.

O que há para entender aqui, me diga?

      subroutine qagse(f,a,b,epsabs,epsrel,limit,result,abserr,neval,
     *   ier,alist,blist,rlist,elist,iord,last)
c***begin prologue  qagse
c***date written   800101   (yymmdd)
c***revision date  830518   (yymmdd)
c***category no.  h2a1a1
c***keywords  automatic integrator, general-purpose,
c             (end point) singularities, extrapolation,
c             globally adaptive
c***author  piessens,robert,appl. math. & progr. div. - k.u.leuven
c           de doncker,elise,appl. math. & progr. div. - k.u.leuven
c***purpose  the routine calculates an approximation result to a given
c            definite integral i = integral of f over (a,b),
c            hopefully satisfying following claim for accuracy
c            abs(i-result).le.max(epsabs,epsrel*abs(i)).
c***description
c
c        computation of a definite integral
c        standard fortran subroutine
c        real version
c
c        parameters
c         on entry
c            f      - real
c                     function subprogram defining the integrand
c                     function f(x). the actual name for f needs to be
c                     declared e x t e r n a l in the driver program.
c
c            a      - real
c                     lower limit of integration
c
c            b      - real
c                     upper limit of integration
c
c            epsabs - real
c                     absolute accuracy requested
c            epsrel - real
c                     relative accuracy requested
c                     if  epsabs.le.0
c                     and epsrel.lt.max(50*rel.mach.acc.,0.5 d-28),
c                     the routine will end with ier = 6.
c
c            limit  - integer
c                     gives an upperbound on the number of subintervals
c                     in the partition of (a,b)
c
c         on return
c            result - real
c                     approximation to the integral
c
c            abserr - real
c                     estimate of the modulus of the absolute error,
c                     which should equal or exceed abs(i-result)
c
c            neval  - integer
c                     number of integrand evaluations
c
c            ier    - integer
c                     ier = 0 normal and reliable termination of the
c                             routine. it is assumed that the requested
c                             accuracy has been achieved.
c                     ier.gt.0 abnormal termination of the routine
c                             the estimates for integral and error are
c                             less reliable. it is assumed that the
c                             requested accuracy has not been achieved.
c            error messages
c                         = 1 maximum number of subdivisions allowed
c                             has been achieved. one can allow more sub-
c                             divisions by increasing the value of limit
c                             (and taking the according dimension
c                             adjustments into account). however, if
c                             this yields no improvement it is advised
c                             to analyze the integrand in order to
c                             determine the integration difficulties. if
c                             the position of a local difficulty can be
c                             determined (e.g. singularity,
c                             discontinuity within the interval) one
c                             will probably gain from splitting up the
c                             interval at this point and calling the
c                             integrator on the subranges. if possible,
c                             an appropriate special-purpose integrator
c                             should be used, which is designed for
c                             handling the type of difficulty involved.
c                         = 2 the occurrence of roundoff error is detec-
c                             ted, which prevents the requested
c                             tolerance from being achieved.
c                             the error may be under-estimated.
c                         = 3 extremely bad integrand behaviour
c                             occurs at some points of the integration
c                             interval.
c                         = 4 the algorithm does not converge.
c                             roundoff error is detected in the
c                             extrapolation table.
c                             it is presumed that the requested
c                             tolerance cannot be achieved, and that the
c                             returned result is the best which can be
c                             obtained.
c                         = 5 the integral is probably divergent, or
c                             slowly convergent. it must be noted that
c                             divergence can occur with any other value
c                             of ier.
c                         = 6 the input is invalid, because
c                             epsabs.le.0 and
c                             epsrel.lt.max(50*rel.mach.acc.,0.5 d-28).
c                             result, abserr, neval, last, rlist(1),
c                             iord(1) and elist(1) are set to zero.
c                             alist(1) and blist(1) are set to a and b
c                             respectively.
c
c            alist  - real
c                     vector of dimension at least limit, the first
c                      last  elements of which are the left end points
c                     of the subintervals in the partition of the
c                     given integration range (a,b)
c
c            blist  - real
c                     vector of dimension at least limit, the first
c                      last  elements of which are the right end points
c                     of the subintervals in the partition of the given
c                     integration range (a,b)
c
c            rlist  - real
c                     vector of dimension at least limit, the first
c                      last  elements of which are the integral
c                     approximations on the subintervals
c
c            elist  - real
c                     vector of dimension at least limit, the first
c                      last  elements of which are the moduli of the
c                     absolute error estimates on the subintervals
c
c            iord   - integer
c                     vector of dimension at least limit, the first k
c                     elements of which are pointers to the
c                     error estimates over the subintervals,
c                     such that elist(iord(1)), ..., elist(iord(k))
c                     form a decreasing sequence, with k = last
c                     if last.le.(limit/2+2), and k = limit+1-last
c                     otherwise
c
c            last   - integer
c                     number of subintervals actually produced in the
c                     subdivision process
c
c***references  (none)
c***routines called  qelg,qk21,qpsrt,r1mach
c***end prologue  qagse
c
      real a,abseps,abserr,alist,area,area1,area12,area2,a1,
     *  a2,b,blist,b1,b2,correc,defabs,defab1,defab2,r1mach,
     *  dres,elist,epmach,epsabs,epsrel,erlarg,erlast,errbnd,
     *  errmax,error1,error2,erro12,errsum,ertest,f,oflow,resabs,
     *  reseps,result,res3la,rlist,rlist2,small,uflow
      integer id,ier,ierro,iord,iroff1,iroff2,iroff3,jupbnd,k,ksgn,
     *  ktmin,last,limit,maxerr,neval,nres,nrmax,numrl2
      logical extrap,noext
c
      dimension alist(limit),blist(limit),elist(limit),iord(limit),
     * res3la(3),rlist(limit),rlist2(52)
c
      external f
c
c            the dimension of rlist2 is determined by the value of
c            limexp in subroutine qelg (rlist2 should be of dimension
c            (limexp+2) at least).
c
c            list of major variables
c            -----------------------
c
c           alist     - list of left end points of all subintervals
c                       considered up to now
c           blist     - list of right end points of all subintervals
c                       considered up to now
c           rlist(i)  - approximation to the integral over
c                       (alist(i),blist(i))
c           rlist2    - array of dimension at least limexp+2
c                       containing the part of the epsilon table
c                       which is still needed for further computations
c           elist(i)  - error estimate applying to rlist(i)
c           maxerr    - pointer to the interval with largest error
c                       estimate
c           errmax    - elist(maxerr)
c           erlast    - error on the interval currently subdivided
c                       (before that subdivision has taken place)
c           area      - sum of the integrals over the subintervals
c           errsum    - sum of the errors over the subintervals
c           errbnd    - requested accuracy max(epsabs,epsrel*
c                       abs(result))
c           *****1    - variable for the left interval
c           *****2    - variable for the right interval
c           last      - index for subdivision
c           nres      - number of calls to the extrapolation routine
c           numrl2    - number of elements currently in rlist2. if an
c                       appropriate approximation to the compounded
c                       integral has been obtained it is put in
c                       rlist2(numrl2) after numrl2 has been increased
c                       by one.
c           small     - length of the smallest interval considered
c                       up to now, multiplied by 1.5
c           erlarg    - sum of the errors over the intervals larger
c                       than the smallest interval considered up to now
c           extrap    - logical variable denoting that the routine
c                       is attempting to perform extrapolation
c                       i.e. before subdividing the smallest interval
c                       we try to decrease the value of erlarg.
c           noext     - logical variable denoting that extrapolation
c                       is no longer allowed (true value)
c
c            machine dependent constants
c            ---------------------------
c
c           epmach is the largest relative spacing.
c           uflow is the smallest positive magnitude.
c           oflow is the largest positive magnitude.
c
c***first executable statement  qagse
      epmach = r1mach(4)
c
c            test on validity of parameters
c            ------------------------------