Arrotondamento dei numeri in MT4 tramite NormalizeDouble - pagina 16

 
fxsaber:
Obsolete

La libreria standard ha una funzione di normalizzazione dei prezzi che tiene conto della 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 libreria standard ha una funzione di normalizzazione dei prezzi che tiene conto della granularità

Sono consapevole di questa implementazione estremamente lenta. Si trattava di mettere a punto NormalizeDouble (e Help) per le realtà attuali. Ognuno può scrivere le proprie granularità.
 
transcendreamer:
Stavo cominciando a pensare che NormalizeDouble(new_lot-sum_lots,Lots_Digits); non produce esattamente 0 e memorizza qualche coda

Se le variabili new_lot e sum_lots sono uguali, allora la differenza è esattamente 0. Ma non si sa come li calcoli, possono effettivamente essere disuguali quando vengono calcolati, da cui la differenza non zero. Fate la stessa cosa in questo modo:

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

Se le variabili sono uguali entro il numero specificato di cifre, allora la differenza sarà strettamente 0.

 
Sergei Vladimirov:

Se le variabili new_lot e sum_lots sono uguali, allora la differenza è esattamente 0. Ma non si sa come li calcoli, possono effettivamente essere disuguali quando vengono calcolati, da cui la differenza non zero. Fate la stessa cosa in questo modo:

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

Se le variabili sono uguali entro il numero di cifre specificato, la differenza sarà strettamente 0.

Oh, grazie!
 
transcendreamer:

Ancora sull'arrotondamento......

Per favore consigliatemi sulla situazione (per favore non tirate pomodori, sono un umanitario),

esiste una tale variabile:

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

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

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

Il delta è originariamente normalizzato,

OrderLots dovrebbe probabilmente restituire dubs normalizzati,

ma in qualche modo a volte in rare occasioni ottengo numeri come 2.775557561562891e-17

Quindi è quasi zero ma non zero.......

prima domanda - è normale?

...


L'ho letto di nuovo attentamente. Non è normale. Se funzione NormalizeDouble:

  1. Si seleziona la parte intera - I
  2. La parte frazionaria è selezionata - F
  3. F = F * 10^digit
  4. F = F (+ o - a seconda del segno) 0,5
  5. F = (parte intera di F) / 10^digit
  6. risultato = I + F
allora anche il risultato diNormalizeDouble(new_lot - sum_lots, Lots_Digits) dovrebbe essere strettamente zero se new_lot e sum_lots sono uguali entro il numero di cifre specificato. In rari casi ci può essere una differenza di 1 nell'ultima cifra (la ragione è nei punti 4 e 5), ma il risultato 2.775557561562891e-17 è strano, non dovrebbe essere.
 

Ho scritto un piccolo codice tutorial (ero interessato a curiosare io stesso) che scopre le interiora di un numero fluttuante. Se qualcuno è interessato, è possibile eseguirlo (codice C++, si può usare qualche compilatore online. Qui https://goo.gl/tP691X, per esempio)

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

L'uscita a f == 0,5 + 1/(2^24). 1/(2^24) è la cifra meno significativa della mantissa ad un dato grado:

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

Grado = 126 - 127 = -1

mantissa = 1.000000000000000000000000001

Spostare la mantissa al grado -1 = 0,1000000000000000000001 = 1^(-1) + 1^(-24) = 1/(2^1) + 1/(2^24) = 0,5 + 0,00000005960464478 = 0,50000005960464478


Come teoria https://habrahabr.ru/post/112953/.

SZZ: questo compilatore online è più bello di http://rextester.com/l/cpp_online_compiler_gcc

 
pavlick_:

Ho scritto un piccolo codice tutorial (ero interessato a curiosare io stesso) che scopre le interiora di un numero fluttuante. Se qualcuno è interessato, è possibile eseguirlo (codice C++, si può usare qualche compilatore online. Qui https://www.tutorialspoint.com/compile_cpp11_online.php, per esempio)

Potete anche eseguirlo in MQL5 - sostituite c[Pos] con _R(f)[(char)Pos] (o _R(f).Bytes[Pos]) collegando questa libreria.

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

Risultato

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

Cosa è successo alla mantissa?

32 è il codice ascii del problema. Sembra che la libreria con l'errore non abbia una versione char. Penso che dobbiamo eliminare i problemi tra i valori di mantissa. O forse invece di ' ' scrivere " "?

 
pavlick_:

Cosa è successo alla mantissa?

32 è il codice ascii del problema. Sembra una biblioteca con un bug. Penso che dobbiamo eliminare i problemi tra i valori di mantissa. O forse invece di ' ' scrivere " "?

Il fmtprntl.mqh non è mio, quindi non posso dirlo con certezza.

Non voglio disturbare, quindi per i vostri valori di byte stampati 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 effetto collaterale correlato.

Si è rivelato conveniente. Ma non era originariamente destinato ad essere usato in questo modo.

Ci sono funzioni speciali per stampare numeri reali con la precisione richiesta.

Dimmi perché hai bisogno di arrotondare i numeri reali nel processo di calcolo? Perché in questo caso, si perde la precisione del calcolo!

Stiamo parlando del corretto confronto di prezzi, fermate, lotti

Qui c'è bisogno di una certa precisione.