Bibliotecas: Math Utils - página 6

 
Se você precisar de uma função personalizada para obter exatamente a mesma string mais curta que o cast (string)dbl, use a função Repr() da biblioteca:

string shortest_str = Repr(dbl) .

Essa função já foi necessária antes de os desenvolvedores de MQL corrigirem o erro com string e Print() para estar em conformidade com o padrão ieee-754.
 

Gostaria que você estivesse certo e que fosse tão simples assim. Eu não estaria aqui se fosse tão fácil e definitivamente não estaria perdendo tantas horas de trabalho com isso.


É verdade que eu preciso:

1. controlar o número de dígitos após o ponto decimal

2. ajustar dinamicamente o número de dígitos e torná-lo o mais curto possível


Meus dígitos duplos vêm de

Tickvalue -> SYMBOL_TRADE_TICK_VALUE

TickSize -> SYMBOL_TRADE_TICK_SIZE

e

LotValue = ((TickValue / TickSize) * lot);


Nada de estranho, valores padrão, tudo certo, mas LotValue parece ser difícil de formatar e mostrar na tela.


O GRANDE problema é que minhas duplas aparecem como 1.000000000, mas na verdade são 1.000000001

(Eu sei como funcionam as duplas e entendo que isso é normal)


Print(), DoubleToString(), NormalizeDoubles() e StringFormat() basicamente arredondam o número e o número resultante está terrivelmente errado; nada funcionou, a precisão desejada simplesmente não foi alcançada com as funções MQL4 incorporadas porque elas arredondam o número, e 1.000000000 acabou sendo igual a 1.1

(não consigo pensar em nenhuma circunstância em que seja conveniente para um aplicativo que mostra constantemente os preços ver um número "falso" transformado de 1,04966 para 1,0497, mas essa é uma discussão para outro dia)


É por isso que, no início, eu estava usando uma fórmula simples para obter a precisão desejada

int p = 5; // precisão desejada

double n = 1.000000000;

double p10 = (p * 10);

double(long(n * p10) / p10);

Mas a situação se complica quando, em vez de Forex, eu uso criptomoedas, onde preciso de uma precisão maior, de 9 a 10, e, acima disso, não consegui remover os zeros finais, então cheguei às suas funções.

E todo esse problema ocorre porque preciso enviar ao usuário o máximo de informações possível e o espaço na tela é limitado, por isso preciso comprimir o número em um espaço fixo.


Sua função Trunc() dá conta do recado para 99,9% dos números, mas há alguns que não cooperam e precisam de um tratamento especial.

Eu esperava que você pudesse fornecer uma fórmula reduzida para fazer isso.


E agora, aumentando meus problemas, a função Round(double, int) interrompe a execução do MT4 com alguns números duplos. Não consigo entender por que, pois o double não é tão grande, sendo 100000.0000000000

É um número comum que representa o valor de 1 lote para EURUSD e, se eu escrever o valor à mão, tudo fica bem, mas se ele vier da matemática LotValue = ((TickValue / TickSize) * lot); o MT4 bloqueia.


É uma tarefa tão simples e já gastei mais de 40 horas nisso. Isso está me matando!

 
Cristian Dan Fechete #:

É verdade que eu preciso:

1. controlar o número de dígitos após o ponto decimal

2. ajustar dinamicamente o número de dígitos e torná-lo o mais curto possível


Eu lhe disse
double n = 1.000000000;
É o mesmo que:
double n = 1.0;

Seu requisito:
decimais na string <= dígitos_especificados

Se o seu único requisito for formatar o número em uma cadeia de caracteres tão curta quanto possível, sem 0s à direita (enquanto controla o número máximo de dígitos decimais):

string s1 = (string) Round(number, digits);

string s2 = (string) NormalizeDouble(number, digits);

string s3 = StringFormat("%.5f", number);
Escolha qualquer uma dessas formas.

Round e NormalizeDouble controlarão o máximo de dígitos decimais. Em seguida, a conversão para string (string)dbl obterá a string mais curta possível sem os zeros finais. StringFormat() faz a mesma coisa, mas parece ser um pouco mais lento se for chamado milhões de vezes em seu código.

No seu caso, DoubleToString() não é aconselhável, pois ele preencherá as cadeias de caracteres mais curtas < dígitos com 0s finais para manter um número fixo de dígitos decimais. Não é isso que você está pedindo. Você está solicitando um número dinâmico de dígitos decimais (o mais curto).

Editar:
Você calcula a precisão de forma errada como
int p = 5; // precisão desejada
double p10 = (p * 10);

Ela deve ser calculada como:
int p = 5; // precisão desejada
double p10 = MathPow(10, p);

 

Parece que, depois de quatro mensagens, não consegui fazer com que você entendesse meu problema, e estou muito decepcionado com meu fracasso.

E o estilizador deste site está completamente danificado, por isso é muito demorado escrever uma mensagem corretamente aqui

double n = 1.000000000; 
should be the same as:
double n = 1.0;
but it is NOT

Não sei explicar o motivo, mas devemos presumir que 1.000000000; tem um decimal diferente de 0 em algum lugar, embora graficamente eu não tenha conseguido gerar isso.

Mas os resultados são esses:

string s1 = (string) Round(number, digits);  -> blocks MT4

string s2 = (string) NormalizeDouble(number, digits); -> returns a 'faked' string where a rounding is done on last digit

string s3 = StringFormat("%.5f", number); -> same as NormalizeDouble()

para números como 19,65400

string s = (string) Trunc(number, digits);

funciona perfeitamente. E se eu inserir manualmente 1,0000000, ele ainda funcionará perfeitamente.

Para que você me entenda, eu uso a função em mais de 400 parâmetros diferentes e cada um deles tem um valor diferente em cada tick e Trunc() funciona perfeitamente.

Mas para:

double lotValue = ((_TickValue / _TickSize) * lot);

não funciona, e é por isso que também incluí a função Round(number, digits); e ela costumava fazer o truque, e decidi simplesmente perguntar se havia uma fórmula para combinar minha função Normalize_Double_ToString() em um código mais simples e otimizado.

E você me respondeu algo muito diferente (presumo que a culpa seja inteiramente minha por não ter explicado corretamente)

Mas desde ontem o Round() bloqueia o MT4 e, sem o Round, não consigo contar corretamente os dígitos significativos no lado dos decimais.

O problema parece ser o typecasting to long. Se eu removê-lo de Round(double, int); o MT4 executa sem problemas, mas não consigo entender como um double com 6 dígitos inteiros, multiplicado por 10.000, atinge os limites de long.


Acho que, neste ponto, minha pergunta é:

Onde está a saída?


De qualquer forma, vou ter que deixar isso de lado e voltarei ao assunto em algumas semanas.

 

Tente isso:

string Normalize_Double_ToString(double n, int d)
{
   n = Round(n, d);
   d = MathMin(d, GetDigits(n);

   return DoubleToString(n, d);
}

No entanto, ele não será muito melhor do que os três métodos mais curtos da postagem anterior.

Observação,

Eu uso Round() da minha biblioteca, não o método errado que você postou antes, ou uso:

n = NormalizeDouble(n, d);

Mas duvido que você tenha dito que Round() tenha erros.
 
Cristian Dan Fechete #:

Parece que, depois de quatro mensagens, não consegui fazer com que você entendesse meu problema, e me sinto terrivelmente decepcionado com meu fracasso.

Além disso, o estilizador deste site está completamente danificado, por isso é muito demorado escrever uma mensagem corretamente aqui

Não sei explicar o motivo, mas devemos presumir que 1.000000000; tem um decimal diferente de 0 em algum lugar, embora graficamente eu não tenha conseguido mostrar isso.

Tenho certeza de que entendi a causa de seus problemas no MT4.

O principal motivo pelo qual você não consegue obter os resultados esperados é um erro na string(dbl) da MQL4 que ainda não foi corrigido no MT4.

Erro na função string() da MQL4. Conversão incorreta de double -> string.

Isso também afeta a forma como os duplos são exibidos (por meio da conversão implícita para string) por Print(), Alert(), Comment(), FileWrite().

O erro foi corrigido no MT5, mas não no MT4. Veja aqui: https: //www.mql5.com/en/forum/367839/page3#comment_27477157 e a correção aqui: https: //www.mql5.com/en/forum/367839/page5#comment_27613205

Minha recomendação:

Se você quiser se aprofundar ou depurar suas duplas como string no MT4, sempre force a conversão explícita para string por meio da função Repr() do math_utils.mqh

#include "math_utils.mqh"

//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnStart()
  {
   double a = 1.0000000000000002;
   Print(a);         // 1.0 (bug na conversão implícita double -> string)
   Print(Repr(a));   // 1.0000000000000002

   double b = 100.00000000000003;
   Print(b);         // 100,0 (erro na conversão implícita double -> string)
   Print(Repr(b));   // 100.00000000000003
  }
MT5/mql5 reported and confirmed bugs. - Custom ZERO Level Showing ZERO level, bug in MML. String(MQ)
MT5/mql5 reported and confirmed bugs. - Custom ZERO Level Showing ZERO level, bug in MML. String(MQ)
  • 2022.02.01
  • Alain Verleyen
  • www.mql5.com
On indicators, mt5 can set automatically a level "0" depending of the buffer values. Custom indicator showing zero level, though not defined anywhere in the code. Wrong conversion of double -> string. Then test the same example in your browser js pad or any online javascript pad and check the difference