Redondear números en MT4 mediante NormalizeDouble - página 16

 
fxsaber:
Obsoleto

La biblioteca estándar dispone de una función de normalización de precios que tiene en cuenta la granularidad

//+------------------------------------------------------------------+
//| 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 biblioteca estándar dispone de una función de normalización de precios que tiene en cuenta la granularidad

Soy consciente de la extrema lentitud de esta aplicación. Se trataba de ajustar NormalizeDouble (y Help) a la realidad actual. Cada uno puede escribir sus propias granulaciones.
 
transcendreamer:
Estaba empezando a adivinar que NormalizeDouble(new_lot-sum_lots,Lots_Digits); no da como resultado exactamente 0 y almacena alguna cola

Si las variables nuevo_lote y suma_lote son iguales, entonces la diferencia es exactamente 0. Pero no se sabe cómo se calculan, puede que efectivamente sean desiguales al calcularse, de ahí la diferencia no nula. Haz lo mismo de esta manera:

NormalizarDoble(lote_nuevo, lotes_dígitos) - NormalizarDoble(suma_lotes, lotes_dígitos).

Si las variables son iguales dentro del número de dígitos especificado, la diferencia será estrictamente 0.

 
Sergei Vladimirov:

Si las variables nuevo_lote y suma_lote son iguales, entonces la diferencia es exactamente 0. Pero no se sabe cómo se calculan, puede que efectivamente sean desiguales al calcularse, de ahí la diferencia no nula. Haz lo mismo de esta manera:

NormalizarDoble(lote_nuevo, lotes_dígitos) - NormalizarDoble(suma_lotes, lotes_dígitos).

Si las variables son iguales dentro del número de dígitos especificado, la diferencia será estrictamente 0.

¡Oh, gracias!
 
transcendreamer:

De nuevo sobre el redondeo......

Por favor, asesórese sobre la situación (no tire tomates, soy humanitario),

existe dicha variable:

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

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

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

El delta está originalmente normalizado,

Probablemente, OrderLots debería devolver dubs normalizados,

pero de alguna manera a veces en raras ocasiones obtengo números como 2.775557561562891e-17

Así que es casi cero pero no cero.......

primera pregunta - ¿es esto normal?

...


Lo he vuelto a leer con atención. No es normal. Si la función NormalizeDouble:

  1. Se selecciona la parte entera - I
  2. Se selecciona la parte fraccionaria - F
  3. F = F * 10^dígitos
  4. F = F (+ o - según el signo) 0,5
  5. F = (parte entera de F) / 10^dígitos
  6. resultado = I + F
entonces también el resultado deNormalizeDouble(new_lot - sum_lots, Lots_Digits) debe ser estrictamente cero si new_lot y sum_lots son iguales dentro del número de dígitos especificado. En raros casos puede haber una diferencia de 1 en el último dígito (la razón está en los puntos 4 y 5), pero el resultado 2,775557561562891e-17 es extraño, no debería serlo.
 

Escribí un pequeño código tutorial (me interesaba husmear por mi cuenta) que da a conocer las entrañas de un número flotante. Si alguien está interesado, puede ejecutarlo (código C++, puede utilizar algún compilador online. Aquí https://goo.gl/tP691X, por ejemplo)

#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 salida en f == 0,5 + 1/(2^24). 1/(2^24) es el dígito menos significativo de la mantisa en un grado determinado:

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

mantisa = 1.0000000000000000000000001

Desplazar la mantisa al grado -1 = 0,100000000000000001 = 1^(-1) + 1^(-24) = 1/(2^1) + 1/(2^24) = 0,5 + 0,00000005960464478 = 0,50000005960464478


Como teoría https://habrahabr.ru/post/112953/.

SZZ: este compilador en línea es más agradable que http://rextester.com/l/cpp_online_compiler_gcc

 
pavlick_:

Escribí un pequeño código tutorial (me interesaba husmear por mi cuenta) que da a conocer las entrañas de un número flotante. Si alguien está interesado, puede ejecutarlo (código C++, puede utilizar algún compilador online. Aquí https://www.tutorialspoint.com/compile_cpp11_online.php, por ejemplo)

También puedes ejecutarlo en MQL5 - sustituye c[Pos] por _R(f)[(char)Pos] (o _R(f).Bytes[Pos]) conectando esta librería.

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

Resultado

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é pasó con la mantisa?

32 es el código ascii del problema. Parece que la biblioteca con el error no tiene una versión char. Creo que hay que eliminar los problemas entre los valores de las mantisas. ¿O tal vez en lugar de ' ' escribir " "?

 
pavlick_:

¿Qué pasó con la mantisa?

32 es el código ascii del problema. Parece una biblioteca con un error. Creo que hay que eliminar los problemas entre los valores de las mantisas. ¿O tal vez en lugar de ' ' escribir " "?

El fmtprntl.mqh no es mío, así que no puedo asegurarlo.

No quiero molestar, así que para sus valores de bytes impresos 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 efecto secundario relacionado.

Resultó ser conveniente. Pero originalmente no estaba destinado a ser utilizado de esta manera.

Existen funciones especiales para imprimir números reales con la precisión requerida.

Dígame por qué es necesario redondear los números reales en el proceso de cálculo. Porque en este caso, ¡se pierde precisión de cálculo!

Estamos hablando de la correcta comparación de precios, paradas, lotes

Aquí se necesita cierta precisión.