Question aux maîtres du MQL4. Encore une fois à propos de Double Comparaison. - page 6

 
VBAG:
...
La beauté du code d'Irtron est sa compacité (absolument rien de plus - même les variables sont sauvegardées !)
...


Voici la méthode proposée par 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);
 }

Elle est à la fois plus compacte et plus rapide que la mienne, mais même à première vue, elle semble suspecte, car la comparaison fait intervenir deux variables : double !!!!.

Dans ce schéma, seul digit agit comme une constante et peut être comparé, tandis que la variable a, qui est également comparée, est restée double non normalisée!
Cela éveille-t-il des soupçons ? (Par constante, j'entends les constantes habituelles - "#define" et les variables qui ne sont pas impliquées dans les opérations).

De plus, dans d'autres branches, les développeurs eux-mêmes ont écrit que même les constantes doubles, il vaut mieux ne pas les comparer ! !!
Il n'est pas non plus correct de faire NormalizeDouble(a) ! NormalizeDouble(b), !OC ! - opérateur de comparaison !

D'autant plus, dans la version originale au lieu de chiffres constants était donc b = Point / 2 - ici déjà deux de deux variables non normalisées ?

J'aimerais croire que cette variante est géniale, mais dissipez d'abord mes doutes !

Peut-être que quelqu'un trouvera des erreurs dans ma variante aussi ?
 
gravity001:

Voici un aperçu de la méthode suggérée par 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);
 }
J'ai suggéré une autre méthode.
Regardez de plus près, s'il vous plaît.


D'autant plus que dans la version originale au lieu de la constante des chiffres c'était donc b = Point / 2 - ici déjà deux des deux variables non normalisées ?

De quelles versions s'agit-il ?

Je vous ai déjà parlé de la normalisation. D'abord, dites-moi pourquoi l'appliquer, puis comment et .

Par exemple, peut-être savez-vous pourquoi nous devrions comparer les prix avec la précision de 14 signes, qui est mentionnée comme une réalisation dans la discussion ci-dessus ? :) Laissez-moi vous rappeler que la fonction que j'ai suggérée s'appelle ComparePrice :)
 

Irtron писал (а):
...
J'ai suggéré une autre méthode.
Regardez plus attentivement, s'il vous plaît.
...

De quelles versions s'agit-il ?

Je vous ai déjà parlé de la normalisation. Dites-moi d'abord pourquoi il faut l'appliquer, puis comment et .

Par exemple, peut-être savez-vous pourquoi nous devrions comparer les prix avec une précision de 14 chiffres, qui est mentionnée comme une sorte de réussite dans la discussion ci-dessus ? :) Laissez-moi vous rappeler que la fonction que j'ai suggérée s'appelle ComparePrice :)
Tiens, c'est à toi ? Est-ce que je cite correctement maintenant ?
Irtron 10.09.2007 04:07

...

int ComparePrice(double a, double b)
{
a -= b ;
b = Point / 2 ;
si (a > b)
retour (1) ;
si (a < -b)
retour (-1) ;
retour (0) ;
}
...
Pour rappel, la fonction que j'ai suggérée s'appelle ComparePrice. :)

Si vous avez remarqué, j'ai également cité la fonction appelée ComparePrice. C'est juste que le vôtre a déjà été modifié par VBAG. C'est pourquoi j'ai fait référence à la version vierge, c'est-à-dire la version originale, c'est-à-dire votre fonction !
J'ai testé moi-même ces deux fonctions. Oui, ils se sont avérés être plus rapides. Mais comment vérifier la fiabilité de la comparaison ? Je suis très confus par la comparaison de deux variables doubles. Bien que tout doit être correct puisqu'il faut un intervalle ! Mais il y a toujours des soupçons qu'il ne fonctionne pas toujours correctement !

J'ai déjà parlé de normalisation. Dites-moi d'abord pourquoi l'appliquer, puis comment et .

C'est la question clé, n'est-ce pas ? J'y ai moi-même longtemps pensé : "On tape double et on obtient double ".
Je n'ai pas trouvé la réponse exacte. Mais je peux l'imaginer de cette façon

double a = 2.000000000000
double b = 2.000000000001
double c = 1.99999999999999

Toutes ces variables sont différentes et sont stockées en mémoire avec une précision au dernier chiffre !
Dans ce cas, nous définissons nous-mêmes les signes (chiffres). Tout ce qui n'est pas défini est rempli de zéros.

Si nous avions défini double a = 2.0, et qu'il est stocké en mémoire sous la forme 2.0000001 ou 1.9999999, il est clair que NormalizeDouble() ne serait d'aucune utilité, car il renverrait une valeur inexacte !
Je pense qu'une telle erreur ne se produit presque jamais lors de la mémorisation d'une valeur variable. En outre, je ne pense pas que le nombre 2.0 soit stocké sous la forme 1.999999999999999, car chaque caractère (chiffre ou point) est stocké avec un bit spécifique dans la chaîne de bits ! Par conséquent, le nombre 2.0 est stocké en toute sécurité sous la forme 2.00000...00.

L'autre cas est celui où nous ne déterminons pas nous-mêmes les signes :

a = 4.0 ;
b = 2.0 ;
c = a / b // - l'opération de "division" est effectuée par le processeur, ou plutôt par le coprocesseur, et elle remplit le préambule avec des caractères (chiffres).

Après l'opération, il peut l'être :
Le plus souvent :
с = 2.000...0
с= 1.99999999...
с= 2.00000001...

c'est-à-dire que le résultat diffère souvent de la valeur réelle par une petite quantité.

Les erreurs importantes sont très rares :
с = 2.3

Ici, il y a deux explications :
1) une partie de la chaîne de bits a été affectée en mémoire lors de l'appel de a ou b, c'est-à-dire que les variables a et b ont été modifiées.
2) une erreur s'est produite pendant l'opération de "division".

Je pense que le point 2) est le plus fréquent. Pourquoi je ne sais pas. Je pense que cela a à voir avec le fait que le coprocesseur est destiné à être hautement optimisé au détriment de l'inutilité.

Si l'on compare une variable au nombre 2.000...00, l'égalité échouera évidemment. Tous les bits ne seront pas égaux.

Maintenant, NormalizeDouble() est là pour vous aider !
NormalizeDouble() va "réparer" cette petite erreur !
L'erreur étant souvent très faible, l'arrondi avec une petite précision donnera toujours le résultat correct.

Voyez-le de cette façon :
Arrondissez le nombre a = 2,111...11 au deuxième chiffre.
NormalizeDouble() écrira 2.11 dans une nouvelle variable et remplira les bits restants avec des zéros, pas des uns !
Je pense que ça va ressembler à ça :

double MyNormalizeDouble(double value, int digits)
{
    int factor = MathRound( MathPow(10, digits) ); // factor - это множитель,
                                                      с помощью которого мы из VALUE сделаем целое число
    double result = MathRound(factor * value) / factor;
    
    return(result);
}
Ici, j'ai fait de mon mieux pour expliquer pourquoi NormalizeDouble() est nécessaire.

Jusqu'à récemment, j'étais entièrement satisfait de cette explication, mais je me suis récemment convaincu que ce système ne fonctionne pas toujours.

NormalizeDouble(a, 2) !OC ! NormalizeDouble(b, 2) où !OC ! - est un opérateur de comparaison.
Bien que, d'après ce que j'ai compris, cela doit toujours fonctionner !
Par conséquent, je serai heureux de recevoir toute critique raisonnée et compréhensible !
 
gravity001:

De plus, dans d'autres fils de discussion, les développeurs eux-mêmes ont écrit que même les constantes doubles sont mieux de ne pas être comparées ! !!
C'est une nouvelle pour moi ! C'est ce qu'on appelle une question de fond !
Si vous le pouvez, donnez moi un lien !

J'ai une question pour les développeurs :

Veuillez expliquer quelles sont les limites ou les problèmes possibles lors de la comparaison de doubles en utilisant des constantes :
1.
double a=1.23456789 ;
double b ;

si(a>b) ou si(a<b)

Et sous cette forme :
2.
#define a 1.23456789 ;

double b ;

si(a>b) ou si(a<b)
 
gravity001:

D'autant plus que la version originale avait b = Point / 2 au lieu des chiffres constants - ici déjà deux de deux variables non normalisées ?

C'est pourquoi j'ai remplacé b = Point / 2 par constante (1.moins d'opérations - vitesse plus rapide 2.transfert constant explicite - fiabilité plus élevée)

Mais à la lumière de votre déclaration sur le manque de fiabilité de la comparaison double constante, tout l'intérêt est perdu. Nous devons examiner cette question de plus près.

Je me demande ce que les développeurs vont dire.
 
VBAG писал (а):
...
C'est une nouvelle pour moi ! C'est ce qu'on appelle une question de fond !
Si vous le pouvez, donnez-moi un lien !
...
Oui, je cherchais le lien, je voulais le coller tout de suite, mais je ne l'ai pas trouvé ! Je me souviens l'avoir vu quelque part, mais il y avait tellement de sujets de ce genre. J'ai également lu un grand nombre de sujets sur d'autres forums et dans des livres sur le sujet.
Je me souviens que quelqu'un a écrit quelque part, mais je ne me rappelle pas où(((((. Donc, probablement, ce n'était pas correct de ma part d'écrire : "dans d'autres fils, les développeurs eux-mêmes ont écrit" !
Je m'excuse.
Mais si je trouve le lien, je ne manquerai pas de le poster.

Je crois l'avoir lu dans un livre sur le C++. Il décrit comment comparer des nombres réels et dit qu'il est préférable de passer aux nombres entiers !
 
gravity001:
VBAG a écrit (a) :
...
C'est une nouvelle pour moi ! C'est ce qu'on appelle une question de fond !
Si vous le pouvez, donnez moi un lien !
...
Oui, je cherchais le lien, je voulais l'insérer immédiatement, mais je ne l'ai pas trouvé ! Je me souviens l'avoir vu quelque part, mais il y avait tellement de sujets de ce genre. J'ai également lu un grand nombre de sujets sur d'autres forums et dans des livres sur le sujet.
Je me souviens que quelqu'un a écrit quelque part, mais je ne me rappelle pas où(((((. Donc, probablement, ce n'était pas correct de ma part d'écrire : "dans d'autres fils de discussion, les développeurs eux-mêmes ont écrit" !
Je m'excuse.
Mais si je trouve le lien, je ne manquerai pas de le poster.

Je crois l'avoir lu dans un livre sur le C++. Il décrit comment comparer des nombres réels et dit qu'il est préférable de passer aux nombres entiers !
Merci de votre participation et de votre aide. Malheureusement, je n'ai pas de formation universitaire en programmation. Je dois donc écouter et mémoriser davantage. Et j'espère que les développeurs répondront et clarifieront ma question.
J'ai une question pour les développeurs :

Pouvez-vous expliquer quelles sont les limites ou les problèmes éventuels lors de la comparaison de doublets à l'aide de constantes ?
1.
double a=1.23456789 ;
double b ;

si(a>b) ou si(a<b)

Et sous cette forme :
2.
#define a 1.23456789 ;

double b ;

si(a>b) ou si(a<b)
 
De tels problèmes - 1.3333+0.0004 != 1.3337
 

Cette conversation semble se poursuivre indéfiniment. Lorsqu'un nouvel utilisateur a acquis l'expérience et les connaissances nécessaires, il a généralement le temps de se heurter plusieurs fois à la normalisation.

Dans MT5, il est peut-être judicieux de limiter de force la précision des nombres réels dans les opérations de comparaison à, disons, 8 décimales (c'est-à-dire d'exécuter de force NormalizeDouble() avec digit=8). Et seulement si la fonction NormalizeDouble() est explicitement spécifiée, effectuer la normalisation conformément aux paramètres qui y sont spécifiés. Dans ce cas, la question se posera beaucoup moins souvent, à savoir uniquement lorsque l'utilisateur a besoin exactement de la précision spécifiée. À mon avis, cette bite est un peu, mais toujours plus douce qu'un radis.

 
VBAG:
Bonjour !
Comme vous le savez, non seulement l'exactitude des calculs, mais aussi la fiabilité du code que vous avez écrit dépendent du style de programmation et de la précision du code.
Nous n'écrivons pas de jouets et la fiabilité du fonctionnement du programme écrit est donc la toute première exigence. La plupart des calculs sont effectués en dubles et une comparaison correcte dans le code du
de deux nombres réels dans le code du programme nécessite une certaine approche et précision.
J'essaie de trouver le "bon" style de programmation, d'où ma question :

Pour une expression

double a ;
double b ;

si(a==b) ou si(a!=b)
{......} {.... ..}

les développeurs recommandent ceci
//+------------------------------------------------------------------+
//| Fonction permettant de comparer deux nombres réels. |
//+------------------------------------------------------------------+
bool CompareDouble(double Nombre1, double Nombre2)
{
bool Compare = NormalizeDouble(Number1 - Number2, 8) == 0 ;
retour(Compare) ;
}
//+------------------------------------------------------------------+


Ce code est-il correct ?

double a ;
double b ;

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


Très probablement pas dans le cas général. Quelle est la manière correcte de le vérifier ?
En général, quel style de travail avec les dubles est le plus approprié ?
Merci d'avance à tous ceux qui répondent.

Tu as fait un gâchis... :)

La comparaison des nombres flottants se fait en comparant le module de la différence avec un petit seuil.

Retourner (fabs(d1-d2) < 1e-10) par exemple.

Quel est l'intérêt de brouiller les pistes... La fonction NormalizeDouble(...) ne sert qu'à produire de beaux rapports.