Libreria di classi generiche - bug, descrizione, domande, caratteristiche d'uso e suggerimenti - pagina 18
Ti stai perdendo delle opportunità di trading:
- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Registrazione
Accedi
Accetti la politica del sito e le condizioni d’uso
Se non hai un account, registrati
Esegui questo
e ho ottenuto questo.
CArrayList è più veloce della variante hash. Sono entrato nelle viscere di CArrayList, e c'è questo
Ora mi sento imbrogliato. CArrayList è risultato essere un wrapper per un normale array. Pensavo fosse una lista normale con puntatori Prev/Next, ma è così
A parte gli algoritmi di lavoro con le strutture in sé, c'è anche il problema di scegliere il contenitore giusto in base alle specifiche del compito.
Quindi l'interfaccia può essere la stessa per diverse implementazioni. Qualche delusione, non dall'interfaccia, ma dall'implementazione specifica - l'array. Rispetto all'hashish, è il cielo e la terra.
Ora mi sento imbrogliato. CArrayList è risultato essere un wrapper per un normale array. Pensavo fosse una lista normale con puntatori Prev/Next, ma ecco qui
Forum sul trading, sistemi di trading automatico e test di strategia
Algoritmi, metodi di soluzione, confronto delle prestazioni
Sergey Dzyublik, 2017.12.10 20:52
Che tipo di DBMS, cosa dici a un uomo che non sa nulla distrutture di dati.
Se non esiste il concetto di ArrayList (vettore dal C++), di cosa possiamo parlare qui.....
È più la tua disattenzione qui...
Leggi tutto l'elenco disponibile -https://www.mql5.com/ru/docs/standardlibrary/generic
CArrayList è un analogo di std::vector del C++
CLinkedList è molto probabilmente un analogo di std::list del C++
Esegui questo
e ho ottenuto questo.
CArrayList è più veloce della variante hash. Sono entrato nelle viscere di CArrayList, e c'è questo
Ora mi sento imbrogliato. CArrayList è risultato essere un wrapper per un normale array. Pensavo fosse una lista normale con puntatori Prev/Next, ma sembrava così
Storicamente, List non è affatto un foglio - è un array. Quindi è tutto a posto. Se ottenete una lista in generico, probabilmente si chiamerà LinkedList o qualcosa del genere.
Un po' di frustrazione, non con l'interfaccia, ma con l'implementazione specifica - l'array.
Forum sul trading, sistemi di trading automatico e test di strategie di trading
Libreria di classi generiche - bug, descrizione, domande, particolarità d'uso e suggerimenti
Sergey Dzyublik, 2017.12.09 01:12
Ci sono alcuni suggerimenti per un possibile miglioramento:
1) A mio modesto parere, l'implementazione contiene una scelta non del tutto corretta della capacità - sia la dimensione iniziale 3 che quelle successive quando si ricostruisce la tabella hash.
Sì, è corretto che un numero primo dovrebbe essere scelto per l'uniformità della distribuzione.
Tuttavia, l'implementazione di CPrimeGenerator non soddisfa le aspettative e contiene omissioni di numeri primi.
Lo scopo di un tale "generatore" è chiaro - fornire un fattore di incremento dell'ordine di 1,2 con la generazione automatica di numeri primi.
Tuttavia, non è un coefficiente troppo piccolo? In C++ per i vettori, il coefficiente è di solito 1,5-2,0, a seconda della libreria (poiché influenza fortemente la complessità media dell'operazione).
La via d'uscita potrebbe essere un coefficiente costante seguito dall'arrotondamento del numero al primo attraverso una ricerca binaria di una lista di numeri primi.
E una dimensione iniziale di 3 è troppo piccola, non viviamo nel secolo scorso.
2) Attualmente la tabella hash viene ricostruita (Resize) solo quando la capacità è piena al 100% (tutte le m_entries[] sono riempite).
A causa di questo, ci può essere una quantità significativa di collisioni per chiavi che non sono distribuite in modo molto uniforme.
Come opzione, considerate l'introduzione di un fattore di riempimento, che ridurrebbe il 100% del limite necessario per la ricostruzione della tabella hash.
1) Il fattore di crescita del volume (capacità) non è uguale a 1,2, il metodo CPrimeGenerator::ExpandPrime è usato per calcolare il nuovo volume in CHashMap:
In questo metodo, la vecchia dimensione della collezione viene moltiplicata per due, poi troviamo il numero semplice più vicino dall'alto per il valore risultante e lo restituiamo come nuovo volume.
Sul valore iniziale della capacità - sono d'accordo, è molto piccolo.
Ma d'altra parte ci sono sempre i costruttori, dove si può specificare esplicitamente la capacità iniziale:
Quindi non vedo molto senso di cambiare qualcosa qui.
2) L'aggiunta di un parametro di fattore di riempimento aiuterebbe davvero ad evitare le collisioni in alcuni casi. Il più probabile da implementare.
1) Il coefficiente di capacità non è uguale a 1,2, per calcolare il nuovo volume in CHashMap, si usa il metodo CPrimeGenerator::ExpandPrime:
In questo metodo, la vecchia dimensione della collezione viene moltiplicata per due, poi per il valore risultante troviamo il più vicino al numero primo superiore e lo restituiamo come nuovo volume.
Sul valore iniziale della capacità - sono d'accordo, è molto piccolo.
Ma d'altra parte ci sono sempre i costruttori, dove si può specificare esplicitamente la capacità iniziale:
Ecco perché non vedo alcuna ragione per cambiare qualcosa qui.
2) Aggiungere il parametro del fattore di riempimento aiuterà davvero ad evitare le collisioni in alcuni casi. Molto probabilmente sarà implementato.
Roman, credo che tu ti sia fatto un'idea sbagliata. Ora alcune classi non contengono nemmeno i metodi più necessari. Avete mai provato a usarli? Prendete CRedBlackTree, per esempio, la classica implementazione di un albero rosso-nero. Algoritmo abbastanza figo ma senza la possibilità di iterazione. Cosa vuoi dire con questo? Ci sono molte altre cose di cui potreste aver bisogno ma che nessuno si è preoccupato di implementare per qualche motivo. La roba di GetHashCode è orribile. Mi dispiace, ma non è al livello di MQ!
Roman, non credo che tu stia facendo la cosa giusta. Ora alcune classi generiche non contengono nemmeno i metodi più necessari. Avete provato ad usarli? Prendiamo ad esempio CRedBlackTree - una classica implementazione di un albero rosso-nero. Algoritmo abbastanza figo ma senza la possibilità di iterazione. Cosa vuoi dire con questo? Ci sono molte altre cose di cui potreste aver bisogno ma che nessuno si è preoccupato di implementare per qualche motivo. La roba di GetHashCode è orribile. Mi dispiace, ma questo non è il livello di MQ!
Sono ben consapevole della necessità di iteratori per tutte le collezioni di modelli della libreria Genric, ma senza la possibilità di creare classi annidate e l'ereditarietà multipla dalle interfacce, non è possibile implementarle correttamente.
Vorrei sentire commenti più specifici su GetHashCode.
...
Per quanto riguarda GetHashCode, mi piacerebbe sentire osservazioni più specifiche.
Problema
Ovviamente, GetHashCode non può essere implementato correttamente in un ambiente MQL5 personalizzato. Questo perché non tutti gli oggetti sono accessibili. E mentre l'implementazione funziona bene per i membri primitivi come double int, per gli oggetti complessi (classi, strutture e persino enumerazioni) l'hash è calcolato per nome. Se abbiamo migliaia di CObjects o anche ENUM_something_that, allora CHashMap e CHashSet degenereranno in LinkedList:
Non possiamo evitarlo perché tutto ciò che abbiamo a livello utente è il nome dell'oggetto:
Quindi, gli hash di tutti gli oggetti di tipo complesso sono uguali tra loro e questo codice di ricerca qui comporta un'enumerazione di array completa:
In effetti, questo è così critico che sconfigge il punto di usare tutti i generici alla radice. Il punto è che nella maggior parte dei casi è necessario associare o memorizzare oggetti complessi: enumerazioni, strutture o classi. Se avete bisogno di operare solo con tipi semplici, potete fare con qualcosa di più semplice.
Soluzione
Ovviamente, MQL5 è un linguaggio di programmazione personalizzato e sicuro di tipo che gira in una macchina virtuale interna. Qualcosa come Net. Questo significa che l'accesso necessario agli oggetti esiste ancora, ma ad un livello più sistematico. Quindi,forse scrivere la funzione di sistema GetHashCode con il prossimo prototipo:
Come dovrebbe funzionare? In primo luogo, deve essere onnivoro e veloce. Dovrebbe dare una distribuzione uniforme. Per esempio:
Questa funzione potrebbe trovarsi nella sezione delle funzioni di sistema. Non vedo altre soluzioni.
s.e. Farò altri suggerimenti su interfacce, ereditarietà multipla e altre cose legacy del C++ un po' più tardi.