Arredondamento de números em MT4 via NormalizeDouble - página 16

 
fxsaber:
Obsoleto

A biblioteca padrão tem uma função de normalização de preço granular

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

A biblioteca padrão tem uma função de normalização de preço granular

Estou ciente desta implementação extremamente lenta. Tratava-se de afinar o NormalizeDouble (e Ajuda) para as realidades atuais. Cada um pode escrever suas próprias granularidades.
 
transcendreamer:
Eu estava começando a adivinhar que NormalizeDouble(new_lot-sum_lots,Lots_Digits); ele não sai exatamente 0 e armazena alguma cauda

Se as variáveis new_lot e sum_lots são iguais, então a diferença é exatamente 0. Mas não se sabe como calculá-las, elas podem de fato ser desiguais quando calculadas, daí a diferença não-zero. Faça a mesma coisa assim:

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

Se as variáveis forem iguais dentro de um número especificado de dígitos, então a diferença será estritamente 0.

 
Sergei Vladimirov:

Se as variáveis new_lot e sum_lots são iguais, então a diferença é exatamente 0. Mas não se sabe como calculá-las, elas podem de fato ser desiguais quando calculadas, daí a diferença não-zero. Faça a mesma coisa assim:

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

Se as variáveis forem iguais dentro do número especificado de dígitos, a diferença será estritamente 0.

oh, obrigado!
 
transcendreamer:

Novamente sobre arredondamento......

Por favor, informe sobre a situação (não jogue tomates, eu sou um humanitário),

existe tal variável:

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

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

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

O delta é originalmente normalizado,

A OrderLots provavelmente deveria retornar dublagens normalizadas,

mas de alguma forma, às vezes, em raras ocasiões eu recebo números como 2,77555557561561562891e-17

Portanto, é quase zero, mas não zero.......

primeira pergunta - isto é normal?

...


Li novamente com atenção. Não é normal. Se NormalizarDa operação de função dupla:

  1. A parte inteira é selecionada - I
  2. A parte fracionária é selecionada - F
  3. F = F * 10^digits
  4. F = F (+ ou - dependendo do sinal) 0,5
  5. F = (parte inteira de F) / 10^digitos
  6. resultado = I + F
então também o resultadoNormalizeDouble(new_lot - sum_lots, Lots_Digits) deve ser estritamente zero se new_lot e sum_lots forem iguais dentro do número especificado de dígitos. Em casos raros pode haver uma diferença de 1 no último dígito (o motivo está nos itens 4 e 5), mas o resultado 2,775557561561562891e-17 é estranho, não deveria ser.
 

Eu escrevi um pequeno código tutorial (eu estava interessado em me espreitar) que revela as entranhas de um número flutuante. Se alguém estiver interessado, você pode executá-lo (código C++, você pode usar algum compilador online. Aqui https://goo.gl/tP691X, por exemplo)

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

A saída a f == 0,5 + 1/(2^24). 1/(2^24) é o dígito menos significativo da mantissa em um determinado grau:

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

Grau = 126 - 127 = -1

mantissa = 1.0000000000000000000000001

Deslocar a mantissa para o grau -1 = 0,1000000000000000000001 = 1^(-1) + 1^(-24) = 1/(2^1) + 1/(2^24) = 0,5 + 0,00000005960464478 = 0,50000005960464478


Como uma teoria https://habrahabr.ru/post/112953/.

SZZ: este compilador online é mais agradável que http://rextester.com/l/cpp_online_compiler_gcc

 
pavlick_:

Eu escrevi um pequeno código tutorial (eu estava interessado em me espreitar) que revela as entranhas de um número flutuante. Se alguém estiver interessado, você pode executá-lo (código C++, você pode usar algum compilador online. Aqui https://www.tutorialspoint.com/compile_cpp11_online.php, por exemplo)

Você também pode executá-lo em MQL5 - substitua c[Pos] por _R(f)[(char)Pos] (ou _R(f).Bytes[Pos]) conectando esta biblioteca.

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

O que aconteceu com a mantissa?

32 é o código ascii do problema. Parece que a biblioteca com o erro não tem uma versão em char. Acho que precisamos remover os problemas entre os valores da mantissa. Ou talvez ao invés de '' escrever ''?

 
pavlick_:

O que aconteceu com a mantissa?

32 é o código ascii do problema. Parece uma biblioteca com um bug. Acho que precisamos remover os problemas entre os valores da mantissa. Ou talvez ao invés de '' escrever ''?

O fmtprntl.mqh não é meu, portanto, não posso dizer com certeza.

Não quero incomodar, portanto, para seus valores de bytes impressos

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:

Um efeito colateral relacionado.

Acabou se revelando conveniente. Mas não se destinava originalmente a ser usado desta forma.

Existem funções especiais para imprimir números reais com a precisão necessária.

Diga-me por que você precisa arredondar números reais no processo de cálculo? Porque, neste caso, você perde a precisão do cálculo!

Estamos falando sobre a correta comparação de preços, paradas, lotes

Você precisa de uma certa precisão aqui.