Rundung von Zahlen in MT4 über NormalizeDouble - Seite 16

 
fxsaber:
Veraltet

Die Standardbibliothek verfügt über eine Preisnormalisierungsfunktion, die die Granularität berücksichtigt

//+------------------------------------------------------------------+
//| 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:

Die Standardbibliothek verfügt über eine Preisnormalisierungsfunktion, die die Granularität berücksichtigt

Ich bin mir dieser extrem langsamen Umsetzung bewusst. Es ging um die Feinabstimmung von NormalizeDouble (und Help) an die aktuellen Gegebenheiten. Jeder kann seine eigene Granularität schreiben.
 
transcendreamer:
Ich fing an zu vermuten, dass NormalizeDouble(new_lot-sum_lots,Lots_Digits); nicht genau 0 ausgibt und einen Rest speichert

Wenn die Variablen new_lot und sum_lots gleich sind, dann ist die Differenz genau 0. Aber es ist nicht bekannt, wie Sie sie berechnen, sie können in der Tat ungleich sein, wenn sie berechnet werden, daher die Differenz ungleich Null. Machen Sie dasselbe so:

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

Wenn die Variablen innerhalb einer bestimmten Anzahl von Ziffern gleich sind, ist die Differenz genau 0.

 
Sergei Vladimirov:

Wenn die Variablen new_lot und sum_lots gleich sind, dann ist die Differenz genau 0. Aber es ist nicht bekannt, wie Sie sie berechnen, sie können in der Tat ungleich sein, wenn sie berechnet werden, daher die Differenz ungleich Null. Machen Sie dasselbe so:

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

Wenn die Variablen innerhalb der angegebenen Anzahl von Stellen gleich sind, ist die Differenz genau 0.

Oh, danke!
 
transcendreamer:

Nochmals zur Rundung......

Bitte informieren Sie mich über die Situation (werfen Sie nicht mit Tomaten, ich bin ein Menschenfreund),

es eine solche Variable gibt:

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

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

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

Das Delta ist ursprünglich normalisiert,

OrderLots sollte wahrscheinlich normalisierte Dubs zurückgeben,

aber manchmal, bei seltenen Gelegenheiten, erhalte ich Zahlen wie 2.775557561562891e-17

Es ist also fast Null, aber nicht Null.......

Erste Frage: Ist das normal?

...


Ich habe ihn noch einmal sorgfältig gelesen. Das ist nicht normal. Wenn Funktion NormalizeDouble arbeitet :

  1. Der ganzzahlige Teil wird ausgewählt - I
  2. Bruchteil wird ausgewählt - F
  3. F = F * 10^Ziffern
  4. F = F (+ oder - je nach Vorzeichen) 0,5
  5. F = (ganzzahliger Teil von F) / 10^Ziffern
  6. Ergebnis = I + F
dannsollte auch das Ergebnis vonNormalizeDouble(new_lot - sum_lots, Lots_Digits) strikt Null sein, wenn new_lot und sum_lots innerhalb der angegebenen Anzahl von Ziffern gleich sind. In seltenen Fällen kann die letzte Ziffer um 1 abweichen (der Grund dafür ist in den Punkten 4 und 5 zu finden), aber das Ergebnis 2,775557561562891e-17 ist seltsam, das sollte es nicht sein.
 

Ich habe einen kleinen Übungscode geschrieben (ich war selbst daran interessiert, darin herumzustochern), der das Innenleben einer Gleitkommazahl aufdeckt. Wenn jemand daran interessiert ist, können Sie es ausführen (C++-Code, können Sie einige Online-Compiler verwenden. Hier https://goo.gl/tP691X, zum Beispiel)

#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';
}

Die Ausgabe bei f == 0,5 + 1/(2^24). 1/(2^24) ist die niedrigstwertige Stelle der Mantisse bei einem bestimmten Grad:

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

Grad = 126 - 127 = -1

Mantisse = 1,00000000000000000000000000001

Verschiebung der Mantisse auf Grad -1 = 0,1000000000000000000001 = 1^(-1) + 1^(-24) = 1/(2^1) + 1/(2^24) = 0,5 + 0,00000005960464478 = 0,50000005960464478


Als Theorie https://habrahabr.ru/post/112953/.

SZZ: dieser Online-Compiler ist besser als http://rextester.com/l/cpp_online_compiler_gcc

 
pavlick_:

Ich habe einen kleinen Übungscode geschrieben (ich wollte selbst ein wenig herumstöbern), der das Innenleben einer Gleitkommazahl zeigt. Wenn jemand daran interessiert ist, können Sie es ausführen (C++-Code, können Sie einige Online-Compiler verwenden. Hier https://www.tutorialspoint.com/compile_cpp11_online.php, zum Beispiel)

Sie können es auch in MQL5 ausführen - ersetzen Sie c[Pos] durch _R(f)[(char)Pos] (oder _R(f).Bytes[Pos]), indem Sie diese Bibliothek anschließen.

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';
}

Ergebnis

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

Was ist mit der Mantisse passiert?

32 ist der Ascii-Code des Problems. Es sieht so aus, als ob die Bibliothek , bei der der Fehler auftritt, keine char-Version hat. Ich denke, wir müssen die Probleme zwischen den Mantissenwerten beseitigen. Oder vielleicht anstelle von ' ' " " schreiben?

 
pavlick_:

Was ist mit der Mantisse passiert?

32 ist der Ascii-Code des Problems. Es sieht aus wie eine Bibliothek mit einer Wanze. Ich denke, wir müssen die Probleme zwischen den Mantissenwerten beseitigen. Oder vielleicht anstelle von ' ' " " schreiben?

Die Datei fmtprntl.mqh ist nicht von mir, daher kann ich das nicht mit Sicherheit sagen.

Ich will mir nicht die Mühe machen, also für Ihre f gedruckten Byte-Werte

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:

Eine damit verbundene Nebenwirkung.

Das erwies sich als praktisch. Ursprünglich war er jedoch nicht für diese Verwendung gedacht.

Es gibt spezielle Funktionen, um reelle Zahlen mit der erforderlichen Genauigkeit zu drucken.

Erklären Sie mir, warum Sie reelle Zahlen bei der Berechnung runden müssen? Denn in diesem Fall verlieren Sie die Rechengenauigkeit!

Es geht um den korrekten Vergleich von Preisen, Haltestellen, Losen

Hier ist eine gewisse Genauigkeit erforderlich.