Arrondir les nombres dans MT4 via NormalizeDouble - page 16

 
fxsaber:
Obsolète

La bibliothèque standard dispose d'une fonction de normalisation des prix tenant compte de la granularité.

//+------------------------------------------------------------------+
//| Normalize price                                                  |
//+------------------------------------------------------------------+
double CSymbolInfo::NormalizePrice(const double price) const
  {
   if(m_tick_size!=0)
      return(NormalizeDouble(MathRound(price/m_tick_size)*m_tick_size,m_digits));
//---
   return(NormalizeDouble(price,m_digits));
  }
 
Slawa:

La bibliothèque standard dispose d'une fonction de normalisation des prix tenant compte de la granularité.

Je suis conscient de cette mise en œuvre extrêmement lente. Il s'agissait d'ajuster NormalizeDouble (et Help) aux réalités actuelles. Chacun peut écrire ses propres granularités.
 
transcendreamer:
Je commençais à supposer que NormalizeDouble(new_lot-sum_lots,Lots_Digits) ; il ne produit pas exactement 0 et stocke un peu de queue.

Si les variables new_lot et sum_lots sont égales, alors la différence est exactement 0. Mais on ne sait pas comment vous les calculez, elles peuvent en effet être inégales lors du calcul, d'où la différence non nulle. Fais la même chose comme ça :

NormalizeDouble(new_lot, Lots_Digits) - NormalizeDouble(sum_lots, Lots_Digits).

Si les variables sont égales dans un nombre spécifié de chiffres, alors la différence sera strictement égale à 0.

 
Sergei Vladimirov:

Si les variables new_lot et sum_lots sont égales, alors la différence est exactement 0. Mais on ne sait pas comment vous les calculez, elles peuvent en effet être inégales lors du calcul, d'où la différence non nulle. Fais la même chose comme ça :

NormalizeDouble(new_lot, Lots_Digits) - NormalizeDouble(sum_lots, Lots_Digits).

Si les variables sont égales dans le nombre de chiffres spécifié, la différence sera strictement égale à 0.

Oh, merci !
 
transcendreamer:

Encore une fois à propos des arrondis......

Veuillez me conseiller sur la situation (ne jetez pas de tomates, je suis un humanitaire),

il existe une telle variable :

      double delta=NormalizeDouble(new_lot-sum_lots,Lots_Digits);

      if(delta>0) delta-=OrderLots();

      if(delta<0) delta+=OrderLots();

Le delta est normalisé à l'origine,

Les lots de commande devraient probablement renvoyer des dubs normalisés,

mais d'une manière ou d'une autre, à de rares occasions, j'obtiens des chiffres comme 2.775557561562891e-17

Donc c'est presque zéro mais pas zéro.......

Première question : est-ce normal ?

...


Je l'ai relu attentivement. Ce n'est pas normal. Si fonction NormalizeDouble :

  1. La partie entière est sélectionnée - I
  2. La partie fractionnaire est sélectionnée - F
  3. F = F * 10^chiffres
  4. F = F (+ ou - selon le signe) 0,5
  5. F = (partie entière de F) / 10^chiffres
  6. résultat = I + F
alors le résultat deNormalizeDouble(new_lot - sum_lots, Lots_Digits) devrait être strictement nul si new_lot et sum_lots sont égaux dans le nombre de chiffres spécifié. Dans de rares cas, il peut y avoir une différence de 1 dans le dernier chiffre (la raison est dans les points 4 et 5), mais le résultat 2.775557561562891e-17 est étrange, il ne devrait pas l'être.
 

J'ai écrit un petit code tutorial (j'avais envie de farfouiller moi-même) qui montre les entrailles d'un nombre flottant. Si quelqu'un est intéressé, vous pouvez l'exécuter (code C++, vous pouvez utiliser un compilateur en ligne. Ici https://goo.gl/tP691X, par exemple)

#include <iostream>
using namespace std;

int main()
{
    cout.precision(17);
    float f = 0.5;
    //float add = 0.00000002980232239; //-25   1/(2^25)
    float add = 0.00000005960464478; //-24     1/(2^24)
    //float add = 0.0000001192092896; //-23   1/(2^23)
    //float add = 0.0000002384185791; // -22  1/(2^22)
    f+= add;

    cout << "value = " << f << endl;
    cout << "----------\n";

    char *c = (char*)&f;  // char может ссылаться на любой тип
    cout << "mantissa:\n";
    cout << "implicit_1 ";
    cout << (c[2] >> 6 & 0 b1) << ' '; cout << (c[2] >> 5 & 0 b1) << ' ';
    cout << (c[2] >> 4 & 0 b1) << ' '; cout << (c[2] >> 3 & 0 b1) << ' ';
    cout << (c[2] >> 2 & 0 b1) << ' '; cout << (c[2] >> 1 & 0 b1) << ' ';
    cout << (c[2] >> 0 & 0 b1) << ' '; cout << (c[1] >> 7 & 0 b1) << ' ';
    cout << (c[1] >> 6 & 0 b1) << ' '; cout << (c[1] >> 5 & 0 b1) << ' ';
    cout << (c[1] >> 4 & 0 b1) << ' '; cout << (c[1] >> 3 & 0 b1) << ' ';
    cout << (c[1] >> 2 & 0 b1) << ' '; cout << (c[1] >> 1 & 0 b1) << ' ';
    cout << (c[1] >> 0 & 0 b1) << ' '; cout << (c[0] >> 7 & 0 b1) << ' ';
    cout << (c[0] >> 6 & 0 b1) << ' '; cout << (c[0] >> 5 & 0 b1) << ' ';
    cout << (c[0] >> 4 & 0 b1) << ' '; cout << (c[0] >> 3 & 0 b1) << ' ';
    cout << (c[0] >> 2 & 0 b1) << ' '; cout << (c[0] >> 1 & 0 b1) << ' ';
    cout << (c[0] >> 0 & 0 b1) << '\n';
    cout << "exponenta E - 127:\n";
    cout << "1= " << (c[2] >> 7 & 0 b1) << '\n';
    cout << "2= " << (c[3] >> 0 & 0 b1) << '\n';
    cout << "4= " << (c[3] >> 1 & 0 b1) << '\n';
    cout << "8= " << (c[3] >> 2 & 0 b1) << '\n';
    cout << "16= " << (c[3] >> 3 & 0 b1) << '\n';
    cout << "32= " << (c[3] >> 4 & 0 b1) << '\n';
    cout << "64= " << (c[3] >> 5 & 0 b1) << '\n';
    cout << "128= " << (c[3] >> 6 & 0 b1) << '\n';
    cout << "sign\n";
    cout << (c[3] >> 7 & 0 b00000001) << '\n';
}

La sortie à f == 0.5 + 1/(2^24). 1/(2^24) est le chiffre le moins significatif de la mantisse à un degré donné :

value = 0.50000005960464478
----------
mantissa:
implicit_1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
exponenta E - 127:
1= 0
2= 1
4= 1
8= 1
16= 1
32= 1
64= 1
128= 0
sign
0

Degré = 126 - 127 = -1

mantisse = 1,0000000000000000000000001

Décaler la mantisse au degré -1 = 0,1000000000000000000001 = 1^(-1) + 1^(-24) = 1/(2^1) + 1/(2^24) = 0,5 + 0,00000005960464478 = 0,50000005960464478


En tant que théorie https://habrahabr.ru/post/112953/.

SZZ : ce compilateur en ligne est plus agréable que http://rextester.com/l/cpp_online_compiler_gcc

 
pavlick_:

J'ai écrit un petit code tutorial (j'avais envie de farfouiller moi-même) qui montre les entrailles d'un nombre flottant. Si quelqu'un est intéressé, vous pouvez l'exécuter (code C++, vous pouvez utiliser un compilateur en ligne. Ici https://www.tutorialspoint.com/compi le_cpp11_online.php, par exemple)

Vous pouvez également l'exécuter dans MQL5 - remplacez c[Pos] par _R(f)[(char)Pos] (ou _R(f).Bytes[Pos]) en connectant cette bibliothèque.

SZ

#include "fmtprntl.mqh"    // https://www.mql5.com/en/blogs/post/680570
#include <TypeToBytes.mqh> // https://www.mql5.com/ru/code/16280

#define  c _R(f).Bytes
#define  endl "\n"

void OnStart()
{
  OutputStream cout(16, ' ');
  
  float f = 0.5;
  //float add = 0.00000002980232239; //-25   1/(2^25)
  float add = 0.00000005960464478; //-24     1/(2^24)
  //float add = 0.0000001192092896; //-23   1/(2^23)
  //float add = 0.0000002384185791; // -22  1/(2^22)
  f+= add;

  cout << "value = " << f << endl;
  cout << "----------\n";

  cout << "mantissa:\n";
  cout << "implicit_1 ";
  cout << (c[2] >> 6 & 1) << ' '; cout << (c[2] >> 5 & 1) << ' ';
  cout << (c[2] >> 4 & 1) << ' '; cout << (c[2] >> 3 & 1) << ' ';
  cout << (c[2] >> 2 & 1) << ' '; cout << (c[2] >> 1 & 1) << ' ';
  cout << (c[2] >> 0 & 1) << ' '; cout << (c[1] >> 7 & 1) << ' ';
  cout << (c[1] >> 6 & 1) << ' '; cout << (c[1] >> 5 & 1) << ' ';
  cout << (c[1] >> 4 & 1) << ' '; cout << (c[1] >> 3 & 1) << ' ';
  cout << (c[1] >> 2 & 1) << ' '; cout << (c[1] >> 1 & 1) << ' ';
  cout << (c[1] >> 0 & 1) << ' '; cout << (c[0] >> 7 & 1) << ' ';
  cout << (c[0] >> 6 & 1) << ' '; cout << (c[0] >> 5 & 1) << ' ';
  cout << (c[0] >> 4 & 1) << ' '; cout << (c[0] >> 3 & 1) << ' ';
  cout << (c[0] >> 2 & 1) << ' '; cout << (c[0] >> 1 & 1) << ' ';
  cout << (c[0] >> 0 & 1) << '\n';
  cout << "exponenta E - 127:\n";
  cout << "1= " << (c[2] >> 7 & 1) << '\n';
  cout << "2= " << (c[3] >> 0 & 1) << '\n';
  cout << "4= " << (c[3] >> 1 & 1) << '\n';
  cout << "8= " << (c[3] >> 2 & 1) << '\n';
  cout << "16= " << (c[3] >> 3 & 1) << '\n';
  cout << "32= " << (c[3] >> 4 & 1) << '\n';
  cout << "64= " << (c[3] >> 5 & 1) << '\n';
  cout << "128= " << (c[3] >> 6 & 1) << '\n';
  cout << "sign\n";
  cout << (c[3] >> 7 & 1) << '\n';
}

Résultat

2016.09.27 23:56:01.178 Test (Si-12.16,H1)       0
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      sign
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      128=  0
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      64=  1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      32=  1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      16=  1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      8=  1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      4=  1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      2=  1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)       1=  0
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      exponenta E - 127:
2016.09.27 23:56:01.178 Test (Si-12.16,H1)       implicit_1  0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 1
2016.09.27 23:56:01.178 Test (Si-12.16,H1)       mantissa:
2016.09.27 23:56:01.178 Test (Si-12.16,H1)       ----------
2016.09.27 23:56:01.178 Test (Si-12.16,H1)      value =  0.5000000596046448 
 
implicit_1  0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 0 32 1

Qu'est-il arrivé à la mantisse ?

32 est le code ascii du problème. Il semble que la bibliothèque avec l'erreur n'a pas une version char. Je pense que nous devons supprimer les problèmes entre les valeurs de mantisse. Ou peut-être qu'au lieu de ' ', il faut écrire " " ?

 
pavlick_:

Qu'est-il arrivé à la mantisse ?

32 est le code ascii du problème. On dirait une bibliothèque avec un bug. Je pense que nous devons supprimer les problèmes entre les valeurs de mantisse. Ou peut-être qu'au lieu de ' ', il faut écrire " " ?

Le fmtprntl.mqh n'est pas à moi, donc je ne peux pas en être sûr.

Je ne veux pas m'embêter, alors pour vos valeurs d' octets imprimés f

2016.09.28 00:34:09.813 Test (Si-12.16,H1)      c[0] = 1
2016.09.28 00:34:09.813 Test (Si-12.16,H1)      c[1] = 0
2016.09.28 00:34:09.813 Test (Si-12.16,H1)      c[2] = 0
2016.09.28 00:34:09.813 Test (Si-12.16,H1)      c[3] = 63
 
Slawa:

Un effet secondaire connexe.

Ça s'est avéré être pratique. Mais à l'origine, elle n'était pas destinée à être utilisée de cette manière.

Il existe des fonctions spéciales pour imprimer des nombres réels avec la précision requise.

Dites-moi pourquoi vous devez arrondir les nombres réels dans le processus de calcul ? Car dans ce cas, vous perdez en précision de calcul !

Nous parlons de la comparaison correcte des prix, des arrêts, des lots...

Vous avez besoin d'une certaine précision ici.