Errori, bug, domande - pagina 2160

 
Andrey Khatimlianskii:

Dal punto di vista di MQ, apparentemente correttamente. Come sempre, ha deciso per noi cosa è più conveniente.

Forum sul trading, sistemi di trading automatico e test di strategie di trading

Non ci sono messaggi nel mio profilo.

Renat Fatkhullin, 2018.03.08 10:31

Rimosso temporaneamente per ridurre la quantità di funzionalità che lavorano in modalità compatibilità.

Aggiungeremo nuove funzionalità non appena il processo di migrazione sarà completato.

Questo è un nuovo sistema molto grande e ricco di funzioni.


Sono state introdotte nuove chat room.

 
Andrey Khatimlianskii:

Dal punto di vista di MQ, apparentemente correttamente. Come sempre, ha deciso per noi come essere più confortevole.

Passando al livello di telepatia... )))))

 

Bug poco chiaro nell'indicatore principale. Appare solo su timeframe inferiori a H1, e solo all'avvio del terminale. Testo di errore "S-v5 (EURUSD,M10) array out of range in 'S-v5.mq5' (211,54)" . Il disegno è corretto, ma in ordine inverso, anche se il flag della serie temporale è impostato per tutti i buffer.

La composizione del modello - l'indicatore principale (#1) (dove si verifica l'errore), indicatore aggiuntivo (#2) (combinazione di diverse maniglie dell'indicatore principale con diversi parametri (timeframe)), indicatore (#3) che visualizza le frecce nel grafico principale sui segnali dell'indicatore #1), indicatore (#4) che visualizza le frecce nel grafico principale sui segnali dell'indicatore #2.

Commutazione di timeframe, riapplicazione del modello, se si rimuove qualsiasi 2 indicatori da 2 a 4 o solo al numero 1, l'uscita di un nuovo simbolo dalla panoramica del mercato e l'applicazione di questo modello - l'errore non viene riprodotto e il rendering di tutti gli indicatori è corretto.

 

Errore di compilazione

#import "Test1.ex5"
       void f1();
#import "Test2.dll"
       void f2();
#import
typedef void (*fn)();
void OnStart()
{
    fn fn1 =        f1; //нормально
    fn fn2 =        f2; //Error: 'f2' - pointer to this function type is not supported yet
    fn fn3 = Test2::f2; //нормально
}
 

Il messaggio di errore non permette di capire la causa nel codice esteso

struct A {
    void f( int    ) {}
    void g( int fn ) { f( fn ); } //Error: ')' - unexpected token ???
};
typedef void (*fn)();

sotto è chiaro

struct A {
    void f( int    ) {}
    void g( int fn ) { f( fn ); } //Error: 'fn' - identifier already used
};
struct fn {};
 

Nessun messaggio di errore

typedef void (*fn)();
void f( int i ) { Print( __FUNCTION__, ":", i ); }
void OnStart()
{
    f( fn() );
}

inoltre, è in esecuzione e c'è anche un risultato (!)

In questa variante:

typedef int (*fn)();
void OnStart() { Print( fn() ); }

nessun salto alla linea di errore (con Enter)


 

Errore di compilazione

    void g(  int ) {}
    void g( uint ) {}
#import "Test.ex5"
    void f(  int );
    void f( uint );
#import
typedef void (*fn1)(  int );
typedef void (*fn2)( uint );
void OnStart()
{
    fn1 g1 = g; /*нормально и результат*/ g1( 1 ); //совпадает с ожидаемым
    fn2 g2 = g; /*нормально и результат*/ g2( 1 ); //совпадает с ожидаемым
    fn1 f1 = f; //Error: 'f' - cannot resolve function address
    fn2 f2 = f; /*нормально и результат*/ f2( 1 ); //совпадает с ожидаемым
                                                   //при наличии Test.ex5
}
 

Nel tentativo di accelerare le cose quando stavo creando questo esempio, mi sono imbattuto in una stranezza completamente per caso, che ho appena messo da parte.

E ora, quando ho cercato di affrontare questa stranezza, sono stato ancora più confuso.

Quindi, nel calcolo uso la funzione di radice quadrata sqrt(), che ho deciso di aggirare creando un array doppio.

Dato che prendo sempre la radice quadrata dai numeri interi, la creazione di un array si presenta così:

   double SQRT[];
   int ss=Width*Width+Height*Height;
   ArrayResize(SQRT,ss);
   for(double w=0;w<ss;w++) SQRT[(int)w]=sqrt(w);

È logico supporre che leggere dall'array SQRT[x] sia più veloce che usare la funzione sqrt(x).
E questo è confermato dal codice di controllo:

   double Sum1=0,Sum2=0;
   ulong t=GetMicrosecondCount();
   for(int i=0;i<ss;i++) Sum1+=sqrt(double(i));   // Находим сумму квадратных корней всех целых чисел от 0 до ss
   t=GetMicrosecondCount()-t;
   Print("Время на сумму "+IntegerToString(ss)+" значений функций = "+IntegerToString(t)+" мкс, Сумма = "+DoubleToString(Sum1));
   t=GetMicrosecondCount();
   for(int i=0;i<ss;i++) Sum2+=SQRT[(int)(i)];    // Находим сумму квадратных корней всех целых чисел от 0 до ss через сложение элементов массива SQRT[]
   t=GetMicrosecondCount()-t;
   Print("Время на сумму "+IntegerToString(ss)+" значений массива = "+IntegerToString(t)+" мкс, Сумма = "+DoubleToString(Sum2));

il risultato mostra un guadagno di velocità di ~1,5 volte:

Ma quando sostituisco la funzione sqrt() nel codice con la lettura degli elementi dell'array SQRT[], invece di accelerare, ottengo terribili ritardi.

Leggere un elemento dall'array SQRT[] richiede molte volte, forse anche un ordine di grandezza più lungo dell'esecuzione di sqrt().

E non capisco dove si verifica la perdita di velocità. Il codice di controllo qui sopra vi dice il contrario.

Possiamo supporre che il compilatore acceda ad una grande matrice in qualche modo strano e sembra "dimenticarsene" ad ogni giro di loop ed esegue ogni volta la propria indicizzazione di servizio.

Ma questo è un bug logico o strategico del compilatore. E ovviamente dovreste fare qualcosa perché questa perdita di velocità è molto significativa e difficile da rilevare perché non è così evidente.

Allego il codice dello script per dimostrare questa stranezza.

L'esecuzione di default (arr=false) calcola sqrt(), ma quando si cambia arr in true, il valore della radice quadrata viene preso dall'array.

COSA C'È CHE NON VA? PERCHÉ È LENTO?

File:
Swirl.mq5  11 kb
 
Nikolai Semko:

Nel tentativo di accelerare le cose, quando ho creato questo esempio, mi sono imbattuto in una stranezza completamente per caso, che ho appena accantonato.


È logico assumere che leggere dall'array SQRT[x] sia più veloce che prendere sqrt(x).

Da una matrice dinamica, non è un fatto.

Inoltre, la presa della radice è già nel livello di comando del processore SQRTSD. Cioè, non si può battere l'implementazione del processore usando il famigerato costo di accesso in un array dinamico.


E questo è confermato dal codice di verifica:

il risultato mostra un guadagno di velocità di ~1,5 volte:

Dubito che sia confermato.

Il codice di questo tipo è come qualcosa uscito da un libro di testo sull'ottimizzazione dei cicli. L'ottimizzatore di codice potrebbe fare un dolce perché è un caso molto semplice:

   for(int i=0;i<ss;i++) 
      Sum2+=SQRT[i];

Cioè, la misurazione delle prestazioni nel caso di applicazione dei casi deliberatamente perfettamente ottimizzati deve essere chiaramente collegata agli obiettivi del test.

Il test in questo caso è sbagliato.

Ci vuole molte volte, forse anche un ordine di grandezza in più per leggere un elemento dall'arraya SQRT[] che per eseguire la funzione sqrt().

E non capisco dove si verifica la perdita di velocità. Dopo tutto, il codice del test di cui sopra dice il contrario.

Senza vedere il codice assembler finale, propendo per:

  1. sqrt è effettivamente veloce (abbiamo un generatore molto efficiente per il codice nativo, sqrt si trasforma in puro SQRTSD)
  2. il codice di controllo è troppo semplice e compensa i ritardi ottimizzando


Controlliamo attentamente l'intero codice. È interessante scoprire qual è la vera ragione.

SQRTSD — Compute Square Root of Scalar Double-Precision Floating-Point Value
  • www.felixcloutier.com
Computes square root of the low double-precision floating-point value in xmm3/m64 and stores the results in xmm1 under writemask k1. Also, upper double-precision floating-point value (bits[127:64]) from xmm2 is copied to xmm1[127:64].
 
Renat Fatkhullin:

Da una matrice dinamica, non un fatto.


Senza vedere il codice assembler finale, propendo per:

  1. sqrt è effettivamente veloce (abbiamo un generatore molto efficiente nel codice nativo, sqrt si trasforma in puro SQRTSD)
  2. il codice del checker è troppo semplice e compensa i ritardi ottimizzando

Ho provato con un array statico - stessa cosa.

Per quanto sqrt sia veloce, trovo difficile credere che questa funzione possa essere 10 volte più veloce della semplice lettura di un elemento dell'array.

Inoltre, se nel mio esempio la dimensione della tela è ridotta, diciamo 50x50 (c'è un parametro di input Size per questo, devi impostare 50 invece di 0),

e l'array sarà molto più piccolo (5000 elementi), il quadro della velocità cambia drasticamente. Non c'è più un contrasto così forte.

Ma non capisco: la dimensione dell'array influenza la velocità di accesso ai suoi elementi?

Forse avete ragione sulla semplicità del codice di controllo.

Ho provato a renderlo un po' più complicato e il risultato è completamente diverso:

for(int i=0;i<ss;i++) Sum1+=i*sqrt(double(i));
....
for(int i=0;i<ss;i++) Sum2+=i* SQRT[(int)(i)];


Motivazione: