Erreurs, bugs, questions - page 2160

 
Andrey Khatimlianskii:

Du point de vue de MQ, apparemment correctement. Comme toujours, il a décidé pour nous comment être plus confortable.

En passant au niveau de la télépathie... )))))

 

Bug peu clair dans l'indicateur principal. Apparaît uniquement sur les délais inférieurs à H1, et uniquement au démarrage du terminal. Texte de l'erreur "S-v5 (EURUSD,M10) array out of range in 'S-v5.mq5' (211,54)" . Le dessin est correct, mais dans l'ordre inverse, bien que l'indicateur de série chronologique soit activé pour tous les tampons.

La composition du modèle - l'indicateur principal (#1) (où l'erreur se produit), l'indicateur supplémentaire (#2) (combinaison de plusieurs poignées de l'indicateur principal avec différents paramètres (timeframe)), l'indicateur (#3) qui affiche des flèches dans le graphique principal sur les signaux de l'indicateur #1), l'indicateur (#4) qui affiche des flèches dans le graphique principal sur les signaux de l'indicateur #2.

Changement d'horizon temporel, réapplication du modèle, si vous supprimez 2 indicateurs de 2 à 4 ou seulement au numéro 1, la sortie d'un nouveau symbole de l'aperçu du marché et l'application de ce modèle - l'erreur n'est pas reproduite et le rendu de tous les indicateurs est correct.

 

Erreur de compilation

#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; //нормально
}
 

Le message d'erreur ne permet pas de comprendre la cause dans le code étendu

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

ci-dessous est clair

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

Aucun message d'erreur

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

de plus, il fonctionne et il y a même un résultat ( !)

Dans cette variante :

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

pas de saut à la ligne d'erreur (par Enter)


 

Erreur de compilation

    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
}
 

En essayant d'accélérer les choses lors de la création de cet exemple, je suis tombé sur une bizarrerie tout à fait par hasard, que j'ai simplement mise de côté.

Et maintenant, quand j'ai essayé de faire face à cette bizarrerie, j'ai été encore plus confus.

Ainsi, dans le calcul, j'utilise la fonction racine carrée sqrt(), que j'ai décidé de contourner en créant un tableau double.

Comme je prends toujours la racine carrée des nombres entiers, la création d'un tableau ressemble à ceci :

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

Il est logique de supposer que la lecture du tableau SQRT[x] est plus rapide que l'utilisation de la fonction sqrt(x).
Et cela est confirmé par le code de contrôle :

   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));

le résultat montre un gain de vitesse de ~1,5 fois :

Mais lorsque je remplace la fonction sqrt() dans le code par la lecture des éléments du tableau SQRT[], au lieu d'accélérer, j'obtiens des décalages terribles.

La lecture d'un élément du tableau SQRT[] prend beaucoup de temps, peut-être même un ordre de grandeur plus long que l'exécution de sqrt().

Et je ne comprends pas où la fuite de vitesse se produit. Le code de contrôle ci-dessus vous indique le contraire.

Nous pouvons supposer que le compilateur accède à un grand tableau d'une manière étrange et semble "l'oublier" à chaque tour de boucle et effectue à chaque fois sa propre indexation de service.

Mais il s'agit d'un bug logique ou stratégique du compilateur. Et vous devriez évidemment faire quelque chose à ce sujet, car cette fuite de vitesse est très importante et difficile à détecter parce qu'elle n'est pas si évidente.

Je joins le code du script pour démontrer cette bizarrerie.

L'exécution par défaut (arr=false) calcule sqrt(), mais lorsque vous changez arr en true, la valeur de la racine carrée est prise dans le tableau.

QU'EST-CE QUI NE VA PAS ? POURQUOI EST-CE LENT ?

Dossiers :
Swirl.mq5  11 kb
 
Nikolai Semko:

Pour tenter d'accélérer les choses, j'ai rencontré, lors de la création de cet exemple, une bizarrerie tout à fait par hasard, que j'ai simplement mise de côté.


Ilest logique de supposer que la lecture du tableau SQRT[x] est plus rapide que l'exécution de sqrt(x).

D'un point de vue dynamique, ce n'est pas un fait.

De plus, la prise de la racine est déjà au niveau de la commande du processeur SQRTSD. En d'autres termes, vous ne pouvez pas battre l'implémentation du processeur en utilisant le fameux coût d'accès dans un tableau dynamique.


Et ceci est confirmé par le code de vérification :

le résultat montre un gain de vitesse de ~1,5 fois :

Je doute que cela soit confirmé.

Le code de ce type est comme sorti d'un manuel sur l'optimisation des boucles. L'optimiseur de code pourrait s'en faire une raison parce que c'est un cas très simple :

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

En d'autres termes, la mesure des performances dans le cas de l'application des cas délibérément parfaitement optimisés doit être clairement liée aux objectifs du test.

Dans ce cas, le test est erroné.

Il faut plusieurs fois, peut-être même un ordre de grandeur, plus de temps pour lire un élément du tableau SQRT[] que pour exécuter la fonction sqrt().

Et je ne comprends pas où se produit la fuite de vitesse. Après tout, le code de test ci-dessus dit le contraire.

Sans voir le code assembleur final, je penche pour :

  1. sqrt est en fait rapide (nous avons un générateur très efficace en code natif, sqrt se transforme en pur SQRTSD)
  2. le code du vérificateur est trop simple et compense les retards en optimisant


Vérifions attentivement l'ensemble du code. Il est intéressant de découvrir quelle est la véritable raison.

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:

D'un tableau dynamique, pas d'un fait.


Sans voir le code assembleur final, je penche pour :

  1. sqrt est en fait rapide (nous avons un générateur très efficace en code natif, sqrt se transforme en pur SQRTSD)
  2. le code du vérificateur est trop simple et compense les retards en optimisant

J'ai essayé un tableau statique - même chose.

Aussi rapide que soit sqrt, j'ai du mal à croire que cette fonction puisse être 10 fois plus rapide que la simple lecture d'un élément de tableau.

De plus, si dans mon exemple la taille de la toile est réduite, disons 50x50 (il existe un paramètre d'entrée Size pour cela, vous devez définir 50 au lieu de 0),

et le tableau sera beaucoup plus petit (5000 éléments), l'image de la vitesse change radicalement. Il n'y a plus de contraste aussi fort.

Mais je ne comprends pas : la taille du tableau affecte-t-elle la vitesse d'accès à ses éléments ?

Vous avez peut-être raison en ce qui concerne la simplicité du code de contrôle.

J'ai essayé de le rendre un peu plus compliqué et le résultat est complètement différent :

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


 
Renat Fatkhullin:


Vérifions attentivement l'ensemble du code. Intéressant de découvrir la vraie raison.

Cool ! Merci ! Je suis aussi intéressé.

Et sqrt est très rapide en effet. Moins d'une nanoseconde :)). Fantastique !