Domanda ai maestri di MQL4. Di nuovo a proposito di Double Compare. - pagina 6

 
VBAG:
...
La bellezza del codice di Irtron è la sua compattezza (assolutamente nulla di extra - anche le variabili sono salvate!)
...


Qui, guardate il metodo proposto da Irtron

int ComparePrice(double a, double b, double digit)
{
     a -= b;
     b = digit;
     if (a > b)
         return (1);
     if (a < -b)
         return (-1);
     return (0);
 }

È sia compatto che più veloce del mio, ma anche a prima vista sembra sospetto, perché il confronto coinvolge due variabili double!!!!

In questo schema, solo la cifra agisce come una costante e può essere confrontata, mentre la variabile a, che è anche confrontata, è rimasta doppia non normalizzata!
Questo desta sospetti? (Per costante intendo le costanti usuali - "#define" e quelle variabili che non erano coinvolte nelle operazioni).

Anche in altri rami gli sviluppatori stessi hanno scritto che anche le costanti raddoppiano meglio non confrontare!!!
Non è nemmeno corretto fare NormalizeDouble(a) ! NormalizeDouble(b), !OC! - operatore di confronto!

Tanto più che nella versione originale invece di cifre costanti era così b = Punto / 2 - qui già due di due variabili non normalizzate?

Mi piacerebbe credere che questa variante sia geniale, ma prima dissipa i miei dubbi!

Forse qualcuno troverà degli errori anche nella mia variante?
 
gravity001:

Ecco uno sguardo al metodo che Irtron ha suggerito

int ComparePrice(double a, double b, double digit)
{
     a -= b;
     b = digit;
     if (a > b)
         return (1);
     if (a < -b)
         return (-1);
     return (0);
 }
Ho suggerito un metodo diverso.
Guarda più da vicino, per favore.


Tanto più che nella versione originale invece delle cifre costanti era così b = Punto / 2 - qui già due delle due variabili non normalizzate?

Di quali versioni stiamo parlando?

Vi ho già parlato della normalizzazione. Prima dimmi perché applicarlo, e poi come e dove.

Per esempio, forse sapete, perché dovremmo confrontare i prezzi con la precisione di 14 segni, che è menzionata come qualche risultato nella discussione sopra? :) Ti ricordo che la funzione che ho suggerito si chiama ComparePrice :)
 

Irtron писал (а):
...
Ho suggerito un metodo diverso.
Guardate con più attenzione, per favore.
...

Di quali versioni stiamo parlando?

Vi ho già parlato della normalizzazione. Prima dimmi perché dovrebbe essere applicato, e poi come e dove.

Per esempio, forse sapete perché dovremmo confrontare i prezzi con una precisione di 14 cifre, che è menzionata come una sorta di risultato nella discussione di cui sopra? :) Ti ricordo che la funzione che ho suggerito si chiama ComparePrice :)
Ecco, questo è tuo? Sto citando correttamente ora?
Irtron 10.09.2007 04:07

...

int ComparePrice(double a, double b)
{
a -= b;
b = Punto / 2;
se (a > b)
ritorno (1);
se (a < -b)
ritorno (-1);
ritorno (0);
}
...
Solo un promemoria, la funzione che ho suggerito si chiama ComparePrice. :)

Se avete notato, ho anche citato la funzione chiamata ComparePrice. È solo che il tuo è già stato modificato da VBAG. Ecco perché mi sono riferito alla versione incontaminata intendendo quella originale, cioè la tua funzione!
Ho testato personalmente entrambe le funzioni. Sì, si sono rivelati più veloci. Ma come verificare l'affidabilità del confronto? Sono molto confuso dal confronto di due variabili doppie. Anche se tutto deve essere corretto perché ci vuole un intervallo! Ma c'è ancora il sospetto che non funzioni sempre correttamente!

Ho già parlato della normalizzazione. Prima dimmi perché applicarlo, e poi come e dove.

Questa è la domanda chiave, giusto? Io stesso ci ho pensato a lungo: "Si scrive il doppio e si ottiene il doppio ".
Non ho trovato la risposta esatta. Ma posso immaginarlo così

doppio a = 2.000000000000
doppio b = 2.000000000001
doppio c = 1.99999999999999

Tutte queste variabili sono diverse e sono memorizzate con precisione fino all'ultima cifra!
In questo caso, siamo noi stessi a definire i segni (cifre). Tutto ciò che non è definito è riempito di zeri.

Se avessimo definito il doppio a = 2,0, ed esso è memorizzato come 2,0000001 o 1,9999999, è chiaro che NormalizeDouble() non sarebbe di aiuto, perché restituirebbe un valore impreciso!
Penso che un tale errore non si verifichi quasi mai quando si memorizza un valore di variabile. Inoltre, non credo che il numero 2.0 sia memorizzato come 1.999999999999999, perché ogni carattere (cifra o punto) è memorizzato con un bit specifico nella stringa di bit! Pertanto, il numero 2.0 è memorizzato in modo sicuro come 2.00000...00.

L'altro caso è quando non siamo noi stessi a determinare i segni:

a = 4.0;
b = 2.0;
c = a / b // - l'operazione di "divisione" è fatta dal processore, o meglio dal co-processore, e riempie il premenente di caratteri (cifre).

Dopo l'operazione può essere:
Più comunemente:
с = 2.000...0
с= 1.99999999...
с= 2.00000001...

cioè il risultato spesso differisce dal valore vero di una piccola quantità.

I grandi errori si verificano molto raramente:
с = 2.3

Qui ci sono due spiegazioni:
1) una parte della stringa di bit è stata influenzata in memoria quando si chiama a o b, cioè le variabili a e b sono state cambiate.
2) si è verificato un errore durante l'operazione "divide".

Penso che il 2) si verifichi più spesso. Perché non lo so. Penso che abbia a che fare con il fatto che il co-processore è destinato ad essere altamente ottimizzato a scapito dell'inutilità.

Quando si confronta una variabile con il numero 2.000...00, l'uguaglianza ovviamente fallisce. Non tutti i bit saranno uguali.

Ora, NormalizeDouble() è qui per aiutare!
NormalizeDouble() "aggiusterà" questo piccolo errore!
Poiché l'errore è spesso molto piccolo, l'arrotondamento con una piccola precisione darà sempre il risultato corretto.

Guardatela in questo modo:
Arrotondare il numero a = 2,111...11 alla seconda cifra.
NormalizeDouble() scriverà 2.11 in una nuova variabile e riempirà i bit rimanenti con zeri, non con uno!
Penso che sarà così:

double MyNormalizeDouble(double value, int digits)
{
    int factor = MathRound( MathPow(10, digits) ); // factor - это множитель,
                                                      с помощью которого мы из VALUE сделаем целое число
    double result = MathRound(factor * value) / factor;
    
    return(result);
}
Qui, ho fatto del mio meglio per spiegare perché NormalizeDouble() è necessaria.

Fino a poco tempo fa ero completamente soddisfatto di questa spiegazione, ma recentemente mi sono convinto che questo schema non funziona sempre

NormalizeDouble(a, 2) !OC! NormalizeDouble(b, 2) dove !OC! - è un operatore di confronto.
Anche se secondo la mia comprensione deve sempre funzionare!
Pertanto, sarò lieto di ricevere qualsiasi critica ragionata e comprensibile!
 
gravity001:

Inoltre, in altri thread gli stessi sviluppatori hanno scritto che anche le costanti doppie è meglio non confrontarle!!!
Questa è una novità per me! Questo è quello che si chiama una domanda sostanziale!
Se puoi, per favore dammi un link!

Ho una domanda per gli sviluppatori:

Per favore, spiega quali sono le limitazioni o i possibili problemi quando si confrontano i doppi usando le costanti:
1.
doppio a=1,23456789;
doppio b;

se(a>b) o se(a<b)

E in questa forma:
2.
#define a 1,23456789;

doppio b;

se(a>b) o se(a<b)
 
gravity001:

Soprattutto perché la versione originale aveva b = Punto / 2 invece di cifre costanti - qui già due di due variabili non normalizzate?

Ecco perché ho sostituito b = Punto / 2 con costante (1.meno operazioni - maggiore velocità 2.trasferimento costante esplicito - maggiore affidabilità)

Ma alla luce della tua affermazione sull'inaffidabilità del doppio confronto costante, l'intero punto è perso. Dobbiamo esaminare più da vicino questo problema.

Mi chiedo cosa diranno gli sviluppatori.
 
VBAG писал (а):
...
Questa è una novità per me! Questo è ciò che si chiama una domanda sostanziale!
Se puoi, per favore dammi un link!
...
Sì, stavo cercando il link, volevo incollarlo immediatamente, ma non l'ho trovato! Ricordo di averlo visto da qualche parte, ma c'erano così tanti argomenti del genere. Ho anche letto un sacco di argomenti su altri forum, e da libri sull'argomento.
Ricordo che qualcuno ha scritto da qualche parte, ma non riesco a ricordare dove(((((. Quindi, probabilmente, non è stato corretto da parte mia scrivere: "in altri thread che gli stessi sviluppatori hanno scritto"!
Mi scuso.
Ma se trovo il link assicurati di postare.

Credo di averlo letto in un libro su C++. Descriveva come confrontare i numeri reali e diceva che è meglio passare ai numeri interi!
 
gravity001:
VBAG ha scritto (a):
...
Questa è una novità per me! Questo è ciò che si chiama una domanda sostanziale!
Se puoi, per favore dammi un link!
...
Sì, stavo cercando il link, volevo inserirlo immediatamente, ma non l'ho trovato! Ricordo di averlo visto da qualche parte, ma c'erano così tanti argomenti del genere. Ho anche letto un sacco di argomenti su altri forum, e da libri sull'argomento.
Ricordo che qualcuno ha scritto da qualche parte, ma non riesco a ricordare dove(((((. Quindi, probabilmente, non è stato corretto da parte mia scrivere: "in altri thread che gli stessi sviluppatori hanno scritto"!
Mi scuso.
Ma se trovo il link assicurati di postare.

Credo di averlo letto in un libro su C++. Descriveva come confrontare i numeri reali e diceva che è meglio passare ai numeri interi!
Grazie per la vostra partecipazione e il vostro aiuto. Sfortunatamente, non ho un background accademico nella programmazione. Quindi devo ascoltare e memorizzare di più. E spero che gli sviluppatori rispondano e chiariscano la mia domanda.
Ho una domanda per gli sviluppatori:

Si prega di chiarire quali sono le limitazioni o i possibili problemi quando si confrontano i dub usando le costanti:
1.
doppio a=1,23456789;
doppio b;

se(a>b) o se(a<b)

E in questa forma:
2.
#define a 1,23456789;

doppio b;

se(a>b) o se(a<b)
 
Tali problemi - 1.3333+0.0004 != 1.3337
 

Questa conversazione sembra andare avanti all'infinito. Nel momento in cui un nuovo utente ha acquisito la giusta esperienza e conoscenza, di solito riesce a sbattere contro la normalizzazione diverse volte.

Forse, in MT5 ha senso limitare forzatamente la precisione dei numeri reali nelle operazioni di confronto, diciamo, a 8 cifre decimali (cioè forzare l'esecuzione di NormalizeDouble() con digit=8). E solo se la funzione NormalizeDouble() è esplicitamente specificata, eseguire la normalizzazione in conformità con i parametri specificati in essa. In questo caso, la questione si presenterà molto meno spesso, cioè solo quando l'utente ha bisogno esattamente della precisione specificata. A mio parere, questo cazzo è un po', ma ancora più dolce di un ravanello.

 
VBAG:
Ciao!
Come sapete, non solo la correttezza dei calcoli, ma anche l'affidabilità del codice che avete scritto dipende dallo stile di programmazione e dalla precisione del codice.
Noi non scriviamo giocattoli e quindi l'affidabilità del funzionamento del programma scritto è il primo requisito. La maggior parte dei calcoli sono eseguiti in duble e un confronto corretto di due reali
di due numeri reali nel codice del programma richiede un certo approccio e precisione.
Sto cercando di capire lo stile di programmazione "giusto", da qui la domanda:

Per un'espressione

doppio a;
doppio b;

se(a==b) o se(a!=b)
{......} {.... ..}

gli sviluppatori raccomandano questo
//+------------------------------------------------------------------+
//| Funzione per confrontare due numeri reali.
//+------------------------------------------------------------------+
bool CompareDouble(double Number1, double Number2)
{
bool Compare = NormalizeDouble(Number1 - Number2, 8) == 0;
ritorno(Compare);
}
//+------------------------------------------------------------------+


Questo codice è corretto?

doppio a;
doppio b;

se(a>b) se(a<b)
{......} {......}


Molto probabilmente non nel caso generale. Qual è il modo corretto di controllarlo?
In generale, quale stile di lavoro con i dubles è più appropriato?
Grazie in anticipo a tutti coloro che rispondono.

Hai fatto un casino di cose... :)

Il confronto dei numeri fluttuanti è fatto confrontando il modulo della differenza con una piccola soglia.

Restituisce (fabs(d1-d2) < 1e-10) per esempio.

Che senso ha confondere le acque... La funzione NormalizeDouble(...) è solo per rapporti dall'aspetto gradevole.

Motivazione: