MetaDriver: Maintenant, j'ai un problème. J'ai besoin de faire un tri efficace des tableaux avec un grand "coût" de la copie des éléments (c'est-à-dire les éléments dont les structures sont grandes, "lourdes", des objets de classe, de longues chaînes, etc). Le bon sens suggère que nous devrions les laisser en place, mais trier à la place une sorte de pointeurs - index des cellules de leur emplacement d'origine. Voici la citation de https://www.mql5.com/ru/forum/6476#comment_178318Оставим jusqu'à présent, avec leurs nombreuses tâches en cours, et l'implémenter dans mql5.
L'entrée doit être une copie du tableau à trier, les commentaires doivent être annotés et le superflu commenté.
Tu es méchant ! Tu as gâché la chanson... Ou plutôt, j'ai essayé. :)
// Il est clair qu'il existe de bonnes approximations. J'aurais pu aussi bien tirer un échantillon de la bibliothèque standard. :)
Il y a des modèles. Et il y en a d'excellentes, aussi. Mais quand même. Dans ce cas, il est important de tout enregistrer et de tout déboguer pour obtenir un produit utilisable distinct. De plus (pourquoi je l'envoie ici) - le plus vite possible. C'est-à-dire que je suggère d'exploiter toutes les performances possibles jusqu'aux centièmes de pour cent inclus. :)
C'est le premier. Deuxièmement, pour les objets, nous avons besoin d'un nombre de tableaux d'index égal au nombre de critères de tri, qui, dans le cas général, peuvent être plusieurs, + (de préférence) une fonction d'insertion dans un tableau indexé trié selon plusieurs critères.
Tu es méchant ! Tu as gâché la chanson... Ou plutôt, vous avez essayé. :)
// Il est clair qu'il existe de bonnes approximations. J'aurais pu aussi bien tirer un échantillon de la bibliothèque standard. :)
Il y a des échantillons. Et même quelques grands. Mais quand même. Il est important de tout vérifier et de tout déboguer pour obtenir un produit distinct et utilisable. Et (pourquoi je l'envoie ici) - le plus rapide. C'est-à-dire que je suggère d'exploiter toutes les performances possibles jusqu'aux centièmes de pour cent inclus. :)
C'est la première chose. Deuxièmement - pour les objets, nous avons besoin d'un nombre de tableaux d'index égal au nombre de critères de tri, qui en général peuvent être plusieurs, + (de préférence) une fonction d'insertion dans un tableau indexé trié par plusieurs critères.
Tout est là. Sous un problème concret, il est possible de refaire sous manipulation non pas des colonnes mais des lignes, il y a des colonnes faites pour il est possible de les déclarer comme des types différents. Si le type de table est le même, tout peut être rejoué.
Voici un exemple de classe pour travailler avec OCL. Bien sûr, certaines choses sont incomplètes et maladroites, mais peut-être que quelqu'un trouvera cela utile.
//——————————————————————————————————————————————————————————————————————————————//| class OCL.mqh |//| Copyright 2011, JQS aka Joo |//| https://www.mql5.com/ru/users/joo |//——————————————————————————————————————————————————————————————————————————————#property copyright "Copyright 2011, JQS aka Joo"#property link "https://www.mql5.com/ru/users/joo"//——————————————————————————————————————————————————————————————————————————————class OCL
{
public:
bool DeviceInfo(int DeviceID);
bool InitOCL (int DeviceID,uint &Offset[],uint &Work[],int BuffCount,int ArgCount,string Source);
bool BuffInit (int buffID,int size,int regime);
bool Execute (int work_dim);
void DeinitOCL ();
//---int BuffID[]; // идентификаторы буферов//----------------------------------------------------------------------------private:
int cl_ctx; // идентификатор контекстаint cl_prg; // идентификатор программыint cl_krn; // идентификатор ядра//---int ArguID[]; // идентификаторы аргументовuint offset[];
uint work [];
};
//——————————————————————————————————————————————————————————————————————————————bool OCL::DeviceInfo(int DeviceID)
{
long DeviceCount=CLGetInfoInteger(0,CL_DEVICE_COUNT);
if(DeviceCount<1)
return(false);
else
{
string s="Всего устройств OCL: "+(string)CLGetInfoInteger(0,CL_DEVICE_COUNT)+" - ";
long DeviceType=CLGetInfoInteger(DeviceID,CL_DEVICE_TYPE);
switch(DeviceType)
{
case CL_DEVICE_ACCELERATOR:
s=s+"Используется спец.OpenCL ускоритель (например, IBM CELL Blade)";
break;
case CL_DEVICE_CPU:
s=s+"Используется CPU";
break;
case CL_DEVICE_GPU:
s=s+"Используется GPU";
break;
case CL_DEVICE_DEFAULT:
s=s+"Устройство по умолчанию";
break;
case CL_DEVICE_CUSTOM:
s=s+"Специализированный ускоритель, не поддерживает OpenCL";
break;
default:
s=s+"Непонятное устройство, скорее всего это какое то устройство по умолчанию";
break;
}
Print(s);
return(true);
}
}
//——————————————————————————————————————————————————————————————————————————————bool OCL::InitOCL(int DeviceID,uint &Offset[],uint &Work[], int BuffCount,int ArgCount,string Source)
{
ArrayResize(offset,ArraySize(Offset)); ArrayCopy(offset,Offset,0,0,WHOLE_ARRAY);
ArrayResize(work, ArraySize(Work)); ArrayCopy(work, Work, 0,0,WHOLE_ARRAY);
if((cl_ctx=CLContextCreate(DeviceID))==-1)
{
Print("OpenCL не найден: ",GetLastError());
return(false);
}
//----------------------------------------------------------------------------// Создаем OpenCL программу из исходного кодаif((cl_prg=CLProgramCreate(cl_ctx,Source))==-1)
{
CLContextFree(cl_ctx);
Print("Ошибка созания OpenCL-программы");
switch(GetLastError())
{
case ERR_OPENCL_INVALID_HANDLE:
Print("Некоректный хендл на программу OpenCL");
break;
caseERR_INVALID_PARAMETER:
Print("Некоректный строковой параметр");
break;
case ERR_OPENCL_TOO_LONG_KERNEL_NAME:
Print("Имя кернела содержит более 127 символов");
break;
case ERR_OPENCL_KERNEL_CREATE:
Print("Внутренняя ошибка при создании объекта OpenCL.");
break;
default: Print("Неопознанная ошибка.");
}
return(false);
}
//----------------------------------------------------------------------------//Создаем точку входа в программу OpenCL if((cl_krn=CLKernelCreate(cl_prg,"Work"))==-1)
{
CLProgramFree(cl_prg);
CLContextFree(cl_ctx);
Print("Ошибка создания OpenCL-ядра");
return(false);
}
//----------------------------------------------------------------------------ArrayResize(BuffID,BuffCount);
ArrayResize(ArguID,ArgCount);
return(true);
}
//——————————————————————————————————————————————————————————————————————————————void OCL::DeinitOCL()
{
for(int i=0;i<ArraySize(BuffID);i++)
CLBufferFree(BuffID[i]);
CLKernelFree (cl_krn);
CLProgramFree(cl_prg);
CLContextFree(cl_ctx);
}
//——————————————————————————————————————————————————————————————————————————————bool OCL::Execute(int work_dim)
{
if(!CLExecute(cl_krn,work_dim,offset,work))
{
Print("Ошибка при расчете в OpenCL");
return(false);
}
return(true);
}
//——————————————————————————————————————————————————————————————————————————————bool OCL::BuffInit(int buffID,int size,int regime)
{
if(buffID>=ArraySize(BuffID))
return(false);
BuffID[buffID]=CLBufferCreate(cl_ctx,size,regime);
if(BuffID[buffID]==-1)
{
Print("OpenCL buffer create failed");
switch(GetLastError())
{
case ERR_OPENCL_INVALID_HANDLE:
Print("Нкоректный хендл на контекст OpenCL");
break;
caseERR_NOT_ENOUGH_MEMORY:
Print("Недостаточно памяти");
break;
case ERR_OPENCL_BUFFER_CREATE:
Print("Внутренняя ошибка создания буфера");
break;
default: Print("Неопознанная ошибка.");
}
return(false);
}
//Выставляем буфер OpenCL в качестве параметра функции OpenCLif(!CLSetKernelArgMem(cl_krn,buffID,BuffID[buffID]))
return(false);
return(true);
}
//——————————————————————————————————————————————————————————————————————————————
J'ai retravaillé un peu l'initialisation, maintenant vous pouvez exécuter des calculs multidimensionnels.
Je viens d'être confronté à un problème d'optimisation avec un algorithme pour trouver un extremum (minimum) de prix. Les conditions sont les suivantes : il existe une barre, dont n barres à gauche et à droite sont inférieures (supérieures) à son maximum :
n est une valeur libre choisie arbitrairement. La période n est toujours impaire, car la somme des deux barres à droite et à gauche sera toujours un nombre pair auquel on ajoute la barre centrale de l'extremum de prix proprement dit.
Je n'ai pas beaucoup réfléchi à la première version de l'algorithme et j'ai écrit le code le plus évident. Maintenant, je l'écris en C# en utilisant la plateforme WealthLab, mais je pense que vous pouvez facilement comprendre l'essence de l'algorithme problématique, voici la partie la plus problématique de celui-ci :
//Перебираем все бары
for (int bar = 0; bar < MyQuotes.Count; bar++)
{
//Подготовка данных
...
int pperiod = (N - 1)/2;//Перебираем бары относительно потенциального экстремумаfor (int i = 1; i <= pperiod; i++)
{
if (MyQuotes.High[bar - i] > MyQuotes.High[bar] ||
MyQuotes.High[bar + i] > MyQuotes.High[bar])
up = false;
if (MyQuotes.Low[bar - i] < MyQuotes.Low[bar] ||
MyQuotes.Low[bar + i] < MyQuotes.Low[bar])
down = false;
}
}
Tout le problème est dans la deuxième boucle. Il traite simultanément les branches gauche et droite d'un extremum potentiel et ne passe donc que par (N - 1)/2 barres, mais cela ne suffit pas. Des mesures montrent que le temps passé à identifier un extremum dans une progression arithmétique dépend de la période N, ce qui est très, très mauvais :
N Time
300:00:00.5460312400:00:00.4720270500:00:00.4820276600:00:00.4250243700:00:00.4410252800:00:00.4350249900:00:00.43002461000:00:00.43802511100:00:00.45202581200:00:00.44202531300:00:00.45002571400:00:00.46402661500:00:00.51002911600:00:00.49502841700:00:00.52002971800:00:00.51102921900:00:00.50902912000:00:00.56903262100:00:00.53203042200:00:00.55603182300:00:00.57503292400:00:00.58503352500:00:00.61403512600:00:00.61203502700:00:00.61603522800:00:00.65103732900:00:00.65103723000:00:00.67703873100:00:00.69003953200:00:00.70404033300:00:00.70004003400:00:00.71904113500:00:00.73204193600:00:00.75104303700:00:00.75104293800:00:00.82904743900:00:00.77604444000:00:00.80804634100:00:00.79904574200:00:00.82404714300:00:00.84604844400:00:00.86904974500:00:00.86804964600:00:00.91205224700:00:00.88705074800:00:00.95205454900:00:00.92305285000:00:00.94305395100:00:00.94605415200:00:00.95905495300:00:00.97505585400:00:00.99205675500:00:01.00105735600:00:01.04405975700:00:01.04005955800:00:01.06106075900:00:01.06106066000:00:01.08606226100:00:01.07306136200:00:01.11706396300:00:01.14006526400:00:01.13706516500:00:01.11906406600:00:01.19606846700:00:01.17406716800:00:01.21106936900:00:01.24907157000:00:01.30107447100:00:01.27507307200:00:01.30907487300:00:01.30007447400:00:01.30607477500:00:01.36107797600:00:01.37407857700:00:01.41908127800:00:01.35007727900:00:01.33507648000:00:01.35307748100:00:01.46908408200:00:01.42708168300:00:01.38707948400:00:01.42508158500:00:01.42508158600:00:01.45008298700:00:01.46008358800:00:01.46308378900:00:01.45008309000:00:01.50608619100:00:01.49308549200:00:01.53408789300:00:01.56208939400:00:01.54708859500:00:01.54508849600:00:01.57308999700:00:01.56408959800:00:01.58409069900:00:01.5970914
En parcourant les périodes, il faudra du temps pour résumer la progression arithmétique, et il s'agit d'une très grande valeur.
Une solution possible est d'introduire une variable supplémentaire. Après tout, si un extremum est identifié, il est garanti qu'il n'y a pas de barre à sa droite pendant (N - 1)/2, de sorte qu'un nouvel extremum peut être identifié en commençant par bar : current_bar + (N - 1)/2. Cependant, les extrema doivent être identifiés en même temps que les minima et un nouveau minimum peut être trouvé avant current_bar + (N - 1)/2. Il sera donc nécessaire de diviser la recherche des extrema et des minima en deux passes, ce qui annulera tout gain de performance. Nous pouvons facilement diviser deux passes en deux threads traités simultanément sur deux cœurs en C# mais j'aimerais d'abord trouver l'algorithme optimal et l'optimiser. J'attends l'aide d'experts.
C-4: Je suis maintenant confronté au problème d'optimisation de l'algorithme de recherche d'un extremum (minimum) de prix.
Ce n'est pas un problème d'optimisation.
En essayant de parcourir les périodes, on obtient la somme de la progression arithmétique, et cette valeur est très grande.
La recherche d'un extremum semble être un problème de l'ordre de O(n), où n est le nombre de données. Comment vous pouvez rendre cette asymptotique pire, c'est-à-dire O(n^2) - je ne peux même pas imaginer. Ou vous confondez les termes.
L'algorithme le plus simple est ArraySort(), intégré assez rapidement, quelque chose autour de O(n * ln( n ) ). Mais il est probablement redondant pour ce problème.
Vous pourriez trouver quelque chose de récursif qui serait plus rapide.
Combien de temps faut-il pour trouver le minimum et pour combien de barres ? Eh bien, je ne crois pas que vous cherchiez un maximum d'une seconde et demie pour 100 barres.
L'algorithme le plus simple est ArraySort(), le tri intégré est assez rapide, mais il est probablement redondant pour cette tâche.
Le meilleur tri est O(n*log(n)). Exactement redondant.
On pourrait trouver quelque chose de récursif qui serait plus rapide.
Plus lentement. La récursion est le plus souvent maléfique. Récursif ? Il s'agit probablement d'un cas où, quelle que soit la façon dont vous le faites, la vitesse sera à peu près la même.
Par code :
//Перебираем все барыfor (int bar = 0; bar < MyQuotes.Count; bar++)
{
//Подготовка данных
...
int pperiod = (N - 1)/2;
//Перебираем бары относительно потенциального экстремумаfor (int i = 1; i <= pperiod; i++)
{
if (MyQuotes.High[bar - i] > MyQuotes.High[bar] ||
MyQuotes.High[bar + i] > MyQuotes.High[bar])
up = false;
if (MyQuotes.Low[bar - i] < MyQuotes.Low[bar] ||
MyQuotes.Low[bar + i] < MyQuotes.Low[bar])
down = false;
}
}
Les cycles pour min et max doivent être explicitement séparés. Et quittez la boucle immédiatement si elle échoue.
Maintenant, j'ai un problème. J'ai besoin de faire un tri efficace des tableaux avec un grand "coût" de la copie des éléments (c'est-à-dire les éléments dont les structures sont grandes, "lourdes", des objets de classe, de longues chaînes, etc). Le bon sens suggère que nous devrions les laisser en place, mais trier à la place une sorte de pointeurs - index des cellules de leur emplacement d'origine. Voici la citation de https://www.mql5.com/ru/forum/6476#comment_178318Оставим jusqu'à présent, avec leurs nombreuses tâches en cours, et l'implémenter dans mql5.
Tout a déjà été volé avant nous :)
Feuilles de calcul dans MQL5
L'entrée doit être une copie du tableau à trier, les commentaires doivent être annotés, et le superflu doit être commenté.
Tout a déjà été volé avant nous :)
Feuilles de calcul dans MQL5
L'entrée doit être une copie du tableau à trier, les commentaires doivent être annotés et le superflu commenté.
Tu es méchant ! Tu as gâché la chanson... Ou plutôt, j'ai essayé. :)
// Il est clair qu'il existe de bonnes approximations. J'aurais pu aussi bien tirer un échantillon de la bibliothèque standard. :)
Il y a des modèles. Et il y en a d'excellentes, aussi. Mais quand même. Dans ce cas, il est important de tout enregistrer et de tout déboguer pour obtenir un produit utilisable distinct. De plus (pourquoi je l'envoie ici) - le plus vite possible. C'est-à-dire que je suggère d'exploiter toutes les performances possibles jusqu'aux centièmes de pour cent inclus. :)
C'est le premier. Deuxièmement, pour les objets, nous avons besoin d'un nombre de tableaux d'index égal au nombre de critères de tri, qui, dans le cas général, peuvent être plusieurs, + (de préférence) une fonction d'insertion dans un tableau indexé trié selon plusieurs critères.
Tu es méchant ! Tu as gâché la chanson... Ou plutôt, vous avez essayé. :)
// Il est clair qu'il existe de bonnes approximations. J'aurais pu aussi bien tirer un échantillon de la bibliothèque standard. :)
Il y a des échantillons. Et même quelques grands. Mais quand même. Il est important de tout vérifier et de tout déboguer pour obtenir un produit distinct et utilisable. Et (pourquoi je l'envoie ici) - le plus rapide. C'est-à-dire que je suggère d'exploiter toutes les performances possibles jusqu'aux centièmes de pour cent inclus. :)
C'est la première chose. Deuxièmement - pour les objets, nous avons besoin d'un nombre de tableaux d'index égal au nombre de critères de tri, qui en général peuvent être plusieurs, + (de préférence) une fonction d'insertion dans un tableau indexé trié par plusieurs critères.
Même réponse Feuilles de calcul dans MQL5.
Tout est là. Sous un problème concret, il est possible de refaire sous manipulation non pas des colonnes mais des lignes, il y a des colonnes faites pour il est possible de les déclarer comme des types différents. Si le type de table est le même, tout peut être rejoué.
Réalisation d'un inluder avec des index de tri pour les types de base.
Le tri par défaut est "descendant", pour trier dans la direction ascendante, mettez l'indicateur de direction du tri à false.
Résultats du test : // indexation des tableaux double[], int[], string[] ; séquentiellement : tableau brut, tableau descendant, tableau ascendant
Bibliothèque et test dans la remorque.
Placez l'indexeur dans le dossier "MQL5\Include\Indexes\".
Voici un exemple de classe pour travailler avec OCL. Bien sûr, certaines choses sont incomplètes et maladroites, mais peut-être que quelqu'un trouvera cela utile.
J'ai retravaillé un peu l'initialisation, maintenant vous pouvez exécuter des calculs multidimensionnels.
Grand sujet !
Je viens d'être confronté à un problème d'optimisation avec un algorithme pour trouver un extremum (minimum) de prix. Les conditions sont les suivantes : il existe une barre, dont n barres à gauche et à droite sont inférieures (supérieures) à son maximum :
n est une valeur libre choisie arbitrairement. La période n est toujours impaire, car la somme des deux barres à droite et à gauche sera toujours un nombre pair auquel on ajoute la barre centrale de l'extremum de prix proprement dit.
Je n'ai pas beaucoup réfléchi à la première version de l'algorithme et j'ai écrit le code le plus évident. Maintenant, je l'écris en C# en utilisant la plateforme WealthLab, mais je pense que vous pouvez facilement comprendre l'essence de l'algorithme problématique, voici la partie la plus problématique de celui-ci :
Tout le problème est dans la deuxième boucle. Il traite simultanément les branches gauche et droite d'un extremum potentiel et ne passe donc que par (N - 1)/2 barres, mais cela ne suffit pas. Des mesures montrent que le temps passé à identifier un extremum dans une progression arithmétique dépend de la période N, ce qui est très, très mauvais :
En parcourant les périodes, il faudra du temps pour résumer la progression arithmétique, et il s'agit d'une très grande valeur.
Une solution possible est d'introduire une variable supplémentaire. Après tout, si un extremum est identifié, il est garanti qu'il n'y a pas de barre à sa droite pendant (N - 1)/2, de sorte qu'un nouvel extremum peut être identifié en commençant par bar : current_bar + (N - 1)/2. Cependant, les extrema doivent être identifiés en même temps que les minima et un nouveau minimum peut être trouvé avant current_bar + (N - 1)/2. Il sera donc nécessaire de diviser la recherche des extrema et des minima en deux passes, ce qui annulera tout gain de performance. Nous pouvons facilement diviser deux passes en deux threads traités simultanément sur deux cœurs en C# mais j'aimerais d'abord trouver l'algorithme optimal et l'optimiser. J'attends l'aide d'experts.
Ce n'est pas un problème d'optimisation.
En essayant de parcourir les périodes, on obtient la somme de la progression arithmétique, et cette valeur est très grande.
La recherche d'un extremum semble être un problème de l'ordre de O(n), où n est le nombre de données. Comment vous pouvez rendre cette asymptotique pire, c'est-à-dire O(n^2) - je ne peux même pas imaginer. Ou vous confondez les termes.
L'algorithme le plus simple est ArraySort(), intégré assez rapidement, quelque chose autour de O(n * ln( n ) ). Mais il est probablement redondant pour ce problème.
Vous pourriez trouver quelque chose de récursif qui serait plus rapide.
Combien de temps faut-il pour trouver le minimum et pour combien de barres ? Eh bien, je ne crois pas que vous cherchiez un maximum d'une seconde et demie pour 100 barres.
L'algorithme le plus simple est ArraySort(), le tri intégré est assez rapide, mais il est probablement redondant pour cette tâche.
Le meilleur tri est O(n*log(n)). Exactement redondant.
On pourrait trouver quelque chose de récursif qui serait plus rapide.
Plus lentement. La récursion est le plus souvent maléfique. Récursif ? Il s'agit probablement d'un cas où, quelle que soit la façon dont vous le faites, la vitesse sera à peu près la même.
Par code :
Les cycles pour min et max doivent être explicitement séparés. Et quittez la boucle immédiatement si elle échoue.
En principe, oui. Mais toujours pas plus de O(n).
OCL serait utile ici. L'asymptotique restera la même, bien sûr. Mais la vitesse pourrait bien être multipliée par cent.