Davvero, non si possono paragonare i doppi. È solo una regola dura.
Naturalmente, è possibile e a volte anche necessario confrontare i doppi direttamente tra loro.
Per esempio, OnTick a volte viene chiamato un trilione di volte durante l'ottimizzazione. Per capire se eseguire o meno un limite pendente, il tester integrato confronta il prezzo corrente del simbolo corrispondente e il prezzo limite. Lo fa per ogni ordine pendente prima di ogni chiamata OnTick. Cioè questi controlli vengono fatti decine e centinaia di miliardi di volte.
E lo si fa ogni volta attraverso la normalizzazione. Beh, questo è un orribile spreco di risorse informatiche. Poiché i prezzi degli ordini pendenti e del simbolo sono preliminarmente normalizzati. Pertanto, possono e devono essere confrontati direttamente tra loro.
Il MQL-custom MQL Tester supera facilmente il tester integrato nativo in termini di prestazioni.
Naturalmente, è possibile e a volte anche necessario confrontare i doppi direttamente tra loro.
Per esempio, OnTick è chiamato un trilione di volte durante Optimize. Il tester integrato, per capire se eseguire o meno un limite pendente, confronta il prezzo corrente del simbolo corrispondente e il prezzo limite. Lo fa per ogni ordine pendente prima di ogni chiamata OnTick. Cioè questi controlli vengono fatti decine e centinaia di miliardi di volte.
E lo si fa ogni volta attraverso la normalizzazione. Beh, questo è un orribile spreco di risorse informatiche. Poiché i prezzi degli ordini pendenti e del simbolo sono preliminarmente normalizzati. Pertanto, possono e devono essere confrontati direttamente tra loro.
Il MQL-custom MQL Tester supera facilmente il tester integrato nativo in termini di prestazioni.
NormalizeDouble() è una funzione molto costosa. Pertanto, è meglio dimenticarsene.
Ecco uno script che dimostra la differenza tra NormalizeDouble() e normalize with int:
#define SIZE 1000000int Ceil (double x) {return (x-(int)x>0)?(int)x+1:(int)x;}
int Round(double x) {return (x>0)?(int)(x+0.5):(int)(x-0.5);}
int Floor(double x) {return (x>0)?(int)x:((int)x-x>0)?(int)x-1:(int)x;}
//+------------------------------------------------------------------+//| Script program start function |//+------------------------------------------------------------------+voidOnStart()
{
double a[SIZE];
double s1=0,s2=0, s3=0;
for (int i=0;i<SIZE;i++) a[i]=(rand()-16384)/M_PI;
ulong t1=GetMicrosecondCount();
for (int i=0;i<SIZE;i++) s1+=a[i];
t1=GetMicrosecondCount()-t1;
ulong t2=GetMicrosecondCount();
for (int i=0;i<SIZE;i++) s2+=NormalizeDouble(a[i],5);
t2=GetMicrosecondCount()-t2;
ulong t3=GetMicrosecondCount();
for (int i=0;i<SIZE;i++) s3+=Round(a[i]*100000);
s3/=100000;
t3=GetMicrosecondCount()-t3;
Print("простая сумма - " + string(t1)+ " микросекунд, сумма = "+ DoubleToString(s1,18));
Print("сумма с NormalizeDouble - " + string(t2)+ " микросекунд, сумма = "+ DoubleToString(s2,18));
Print("сумма, нормализированная через int - " + string(t3)+ " микросекунд, сумма = "+ DoubleToString(s3,18));
}
NormalizeDouble() è una funzione molto costosa. Ecco perché è meglio dimenticarsene.
Ecco uno script che dimostra la differenza tra NormalizeDouble() e normalize with int:
risultato:
SZZ la normalizzazione per int è ancora più accurata (si può vedere dal numero di nove dopo l'ultima cifra della normalizzazione - evidenziata in blu).
e se la somma non è via double, ma via long, allora il risultato è ancora più impressionante, poiché la somma via int (moltiplicazione e arrotondamento seguito dalla divisione della somma finale) calcola più velocemente della normale somma di double.
#define SIZE 1000000int Ceil (double x) {return (x-(int)x>0)?(int)x+1:(int)x;}
int Round(double x) {return (x>0)?(int)(x+0.5):(int)(x-0.5);}
int Floor(double x) {return (x>0)?(int)x:((int)x-x>0)?(int)x-1:(int)x;}
//+------------------------------------------------------------------+//| Script program start function |//+------------------------------------------------------------------+voidOnStart()
{
double a[SIZE];
double s1=0,s2=0, s3=0;
long s=0;
for (int i=0;i<SIZE;i++) a[i]=(rand()-16384)/M_PI;
ulong t1=GetMicrosecondCount();
for (int i=0;i<SIZE;i++) s1+=a[i];
t1=GetMicrosecondCount()-t1;
ulong t2=GetMicrosecondCount();
for (int i=0;i<SIZE;i++) s2+=NormalizeDouble(a[i],5);
t2=GetMicrosecondCount()-t2;
ulong t3=GetMicrosecondCount();
for (int i=0;i<SIZE;i++) s+=Round(a[i]*100000);
s3=s/100000.0;
t3=GetMicrosecondCount()-t3;
Print("простая сумма - " + string(t1)+ " микросекунд, сумма = "+ DoubleToString(s1,18));
Print("сумма с NormalizeDouble - " + string(t2)+ " микросекунд, сумма = "+ DoubleToString(s2,18));
Print("сумма, нормализированная через int - " + string(t3)+ " микросекунд, сумма = "+ DoubleToString(s3,18));
}
E se la somma non è via double, ma via long, allora il risultato è ancora più impressionante, perché la somma via int (moltiplicazione e arrotondamento, seguito dalla divisione della somma totale) è più veloce di una normale somma double.
Nikolai Semko: Inoltre, la normalizzazione attraverso int risulta anche essere più accurata (lo si può vedere dal numero di nove dopo l'ultima cifra della normalizzazione - evidenziata in blu).
Il test non è corretto. Perché dividete per 100000.0 solo una volta alla fine? Dovrebbe essere eseguito ad ogni iterazione e poi sommato. Questo è un confronto corretto. Ma questa non è affatto una normalizzazione - avete appena ottimizzato il vostro algoritmo di test. Naturalmente, sarà più veloce e più preciso (perché l'errore accumulato è ridotto).
Perché puoi inserire prezzi non normalizzati nel Tester e li gestirà in modo identico.
Dopo tutto, anche se i prezzi non sono normalizzati, il controllo si fa facilmente senza alcuna normalizzazione.
Per normalizzazione intendevo in questo caso, un unico standard-algoritmo, dopo averlo applicato, è possibile confrontare direttamente i doppi di questo standard.
Quindi il tester non confronta direttamente i doppi. Lo fa attraverso NormalizeDouble, ticksize o qualcos'altro. Ma certamente non attraverso il confronto diretto dei doppi. E non è affatto razionale.
Naturalmente, è possibile e a volte anche necessario confrontare i doppi direttamente tra loro.
Per esempio, OnTick è chiamato un trilione di volte durante Optimize. Il tester integrato, per capire se eseguire o meno una limit call in sospeso, confronta il prezzo corrente del simbolo corrispondente e il prezzo della limit call. Lo fa per ogni ordine pendente prima di ogni chiamata OnTick. Cioè questi controlli vengono fatti decine e centinaia di miliardi di volte.
E lo si fa ogni volta attraverso la normalizzazione. Beh, questo è un orribile spreco di risorse informatiche. Poiché i prezzi degli ordini pendenti e del simbolo sono preliminarmente normalizzati. Pertanto, possono e devono essere confrontati direttamente tra loro.
Il MQL-custom MQL Tester non batte il tester integrato nativo in termini di prestazioni.
Così ho deciso di controllare la versione senza senso delle prestazioni. E il risultato è stato sorprendente. Il confronto anche del doppio pre-normalizzato è ancora più lento in media di quando il doppio viene confrontato attraverso epsilon o conversione in int
#define SIZE 1000000int Ceil (double x) {return (x-(int)x>0)?(int)x+1:(int)x;}
int Round(double x) {return (x>0)?(int)(x+0.5):(int)(x-0.5);}
int Floor(double x) {return (x>0)?(int)x:((int)x-x>0)?(int)x-1:(int)x;}
bool is_equal(double d1, double d2, double e=0.000000001) {returnfabs(d1-d2)<e;}
voidOnStart()
{
double a[SIZE], a_norm[SIZE];
int s1=0,s2=0, s3=0;
for (int i=0;i<SIZE;i++) {
a[i]=(rand()-16384)/1641.1452;
a_norm[i]=NormalizeDouble(a[i],2);
}
double test = 1.11;
ulong t1=GetMicrosecondCount();
for (int i=0;i<SIZE;i++) if (a_norm[i]==test) s1++;
t1=GetMicrosecondCount()-t1;
ulong t2=GetMicrosecondCount();
for (int i=0;i<SIZE;i++) if (is_equal(a[i],test,0.005)) s2++;
t2=GetMicrosecondCount()-t2;
ulong t3=GetMicrosecondCount();
int test_int = test*100;
for (int i=0;i<SIZE;i++) if (Round(a[i]*100)==test_int) s3++;
t3=GetMicrosecondCount()-t3;
Print("простое сравнение предварительно нормализированых double - " + string(t1)+ " микросекунд, всего совпадений = "+ string(s1));
Print("сравнение double через эпсилон - " + string(t2)+ " микросекунд, всего совпадений = "+ string(s2));
Print("сравнение double через преобразование в int - " + string(t3)+ " микросекунд, всего совпадений = "+ string(s3));
}
Il risultato:
2020.08.1014:31:39.620 TestCompareDouble (USDCAD,H4) простое сравнение предварительно нормализированых double - 900 микросекунд, всего совпадений = 4862020.08.1014:31:39.620 TestCompareDouble (USDCAD,H4) сравнение double через эпсилон - 723 микросекунд, всего совпадений = 4862020.08.1014:31:39.620 TestCompareDouble (USDCAD,H4) сравнение double через преобразование в int - 805 микросекунд, всего совпадений = 4862020.08.1014:31:42.607 TestCompareDouble (USDCAD,H4) простое сравнение предварительно нормализированых double - 1533 микросекунд, всего совпадений = 4882020.08.1014:31:42.607 TestCompareDouble (USDCAD,H4) сравнение double через эпсилон - 758 микросекунд, всего совпадений = 4882020.08.1014:31:42.607 TestCompareDouble (USDCAD,H4) сравнение double через преобразование в int - 790 микросекунд, всего совпадений = 4882020.08.1014:31:44.638 TestCompareDouble (USDCAD,H4) простое сравнение предварительно нормализированых double - 986 микросекунд, всего совпадений = 4722020.08.1014:31:44.638 TestCompareDouble (USDCAD,H4) сравнение double через эпсилон - 722 микросекунд, всего совпадений = 4722020.08.1014:31:44.638 TestCompareDouble (USDCAD,H4) сравнение double через преобразование в int - 834 микросекунд, всего совпадений = 472
Non escludo che molto dipenda dalla novità e dall'architettura del processore, e per qualcuno il risultato può essere diverso.
A dire la verità - non capisco nemmeno perché succede. Sembra che il compilatore non abbia nulla da ottimizzare con la somma di numeri casuali. Non puoi mettere l'arrotondamento fuori dalle parentesi. Sembra che il confronto dei doppi nel processore sia un comando Quando si confronta tramite epsilon (il modo più veloce) abbiamo ancora un'operazione di confronto di due doppi ma in più abbiamo una chiamata di funzione con passaggio di tre parametri e un'operazione di sottrazione. Il rendimento dell'operazione di confronto di due doppi dipende dai valori delle variabili stesse? Ne dubito. Cavolo, non capisco. Per favore aiutatemi, cosa non ho preso in considerazione o dove ho sbagliato?
Solo l'arrotondamento non viene fatto usando gli standard round(), ceil(), floor() perché anch'essi restituiscono doppio.
Ma attraverso questi, soprattutto lavorano più velocemente di quelli regolari:
Potrebbe essere più veloce, ma è semplicemente sbagliato.
L'hai provato tu stesso?
Provate:
Uscita:
dovrebbe essere 12346, perché è un ceil ("Restituisce il valore numerico intero più vicino dall'alto")il primo caso è 12345, perché le cifre significative nel tipo doppio sono 17, mentre voi avete 18
Davvero, non si possono paragonare i doppi. È solo una regola dura.
Naturalmente, è possibile e a volte anche necessario confrontare i doppi direttamente tra loro.
Per esempio, OnTick a volte viene chiamato un trilione di volte durante l'ottimizzazione. Per capire se eseguire o meno un limite pendente, il tester integrato confronta il prezzo corrente del simbolo corrispondente e il prezzo limite. Lo fa per ogni ordine pendente prima di ogni chiamata OnTick. Cioè questi controlli vengono fatti decine e centinaia di miliardi di volte.
E lo si fa ogni volta attraverso la normalizzazione. Beh, questo è un orribile spreco di risorse informatiche. Poiché i prezzi degli ordini pendenti e del simbolo sono preliminarmente normalizzati. Pertanto, possono e devono essere confrontati direttamente tra loro.
Il MQL-custom MQL Tester supera facilmente il tester integrato nativo in termini di prestazioni.
fxsaber:
Naturalmente, è possibile e a volte anche necessario confrontare i doppi direttamente tra loro.
Per esempio, OnTick è chiamato un trilione di volte durante Optimize. Il tester integrato, per capire se eseguire o meno un limite pendente, confronta il prezzo corrente del simbolo corrispondente e il prezzo limite. Lo fa per ogni ordine pendente prima di ogni chiamata OnTick. Cioè questi controlli vengono fatti decine e centinaia di miliardi di volte.
E lo si fa ogni volta attraverso la normalizzazione. Beh, questo è un orribile spreco di risorse informatiche. Poiché i prezzi degli ordini pendenti e del simbolo sono preliminarmente normalizzati. Pertanto, possono e devono essere confrontati direttamente tra loro.
Il MQL-custom MQL Tester supera facilmente il tester integrato nativo in termini di prestazioni.
NormalizeDouble() è una funzione molto costosa. Pertanto, è meglio dimenticarsene.
Ecco uno script che dimostra la differenza tra NormalizeDouble() e normalize with int:
risultato:
SZZ la normalizzazione per int è anche più accurata (si può vedere dal numero di nove dopo l'ultima cifra della normalizzazione - evidenziata in blu).NormalizeDouble() è una funzione molto costosa. Ecco perché è meglio dimenticarsene.
Ecco uno script che dimostra la differenza tra NormalizeDouble() e normalize with int:
risultato:
SZZ la normalizzazione per int è ancora più accurata (si può vedere dal numero di nove dopo l'ultima cifra della normalizzazione - evidenziata in blu).e se la somma non è via double, ma via long, allora il risultato è ancora più impressionante, poiché la somma via int (moltiplicazione e arrotondamento seguito dalla divisione della somma finale) calcola più velocemente della normale somma di double.
risultato:
E se la somma non è via double, ma via long, allora il risultato è ancora più impressionante, perché la somma via int (moltiplicazione e arrotondamento, seguito dalla divisione della somma totale) è più veloce di una normale somma double.
risultato:
Decimale per l'aggiunta di confronto.
Link sbagliato, non è un'implementazione completa.
E lo si fa ogni volta attraverso la normalizzazione. Beh, questo è un terribile spreco di risorse informatiche.
Perché anche se i prezzi non sono normalizzati, il controllo viene fatto semplicemente senza alcuna normalizzazione:
Dato che i prezzi sono multipli di ticksize
Inoltre, la normalizzazione attraverso int risulta anche essere più accurata (lo si può vedere dal numero di nove dopo l'ultima cifra della normalizzazione - evidenziata in blu).
Il test non è corretto. Perché dividete per 100000.0 solo una volta alla fine? Dovrebbe essere eseguito ad ogni iterazione e poi sommato. Questo è un confronto corretto. Ma questa non è affatto una normalizzazione - avete appena ottimizzato il vostro algoritmo di test. Naturalmente, sarà più veloce e più preciso (perché l'errore accumulato è ridotto).
Come fa a sapere questo?
Perché puoi inserire prezzi non normalizzati nel Tester e li gestirà in modo identico.
Dopo tutto, anche se i prezzi non sono normalizzati, il controllo si fa facilmente senza alcuna normalizzazione.
Per normalizzazione intendevo in questo caso, un unico standard-algoritmo, dopo averlo applicato, è possibile confrontare direttamente i doppi di questo standard.
Quindi il tester non confronta direttamente i doppi. Lo fa attraverso NormalizeDouble, ticksize o qualcos'altro. Ma certamente non attraverso il confronto diretto dei doppi. E non è affatto razionale.
Naturalmente, è possibile e a volte anche necessario confrontare i doppi direttamente tra loro.
Per esempio, OnTick è chiamato un trilione di volte durante Optimize. Il tester integrato, per capire se eseguire o meno una limit call in sospeso, confronta il prezzo corrente del simbolo corrispondente e il prezzo della limit call. Lo fa per ogni ordine pendente prima di ogni chiamata OnTick. Cioè questi controlli vengono fatti decine e centinaia di miliardi di volte.
E lo si fa ogni volta attraverso la normalizzazione. Beh, questo è un orribile spreco di risorse informatiche. Poiché i prezzi degli ordini pendenti e del simbolo sono preliminarmente normalizzati. Pertanto, possono e devono essere confrontati direttamente tra loro.
Il MQL-custom MQL Tester non batte il tester integrato nativo in termini di prestazioni.
Così ho deciso di controllare la versione senza senso delle prestazioni.
E il risultato è stato sorprendente.
Il confronto anche del doppio pre-normalizzato è ancora più lento in media di quando il doppio viene confrontato attraverso epsilon o conversione in int
Il risultato:
Non escludo che molto dipenda dalla novità e dall'architettura del processore, e per qualcuno il risultato può essere diverso.
A dire la verità - non capisco nemmeno perché succede.
Sembra che il compilatore non abbia nulla da ottimizzare con la somma di numeri casuali. Non puoi mettere l'arrotondamento fuori dalle parentesi.
Sembra che il confronto dei doppi nel processore sia un comando
Quando si confronta tramite epsilon (il modo più veloce) abbiamo ancora un'operazione di confronto di due doppi ma in più abbiamo una chiamata di funzione con passaggio di tre parametri e un'operazione di sottrazione.
Il rendimento dell'operazione di confronto di due doppi dipende dai valori delle variabili stesse? Ne dubito.
Cavolo, non capisco. Per favore aiutatemi, cosa non ho preso in considerazione o dove ho sbagliato?