Essas são três funções úteis para comparação e arredondamento de números de ponto flutuante e formatação de dinheiro:
1. `bool DoubleEquals(double x, double y, double eps)` compara dois valores duplos `x` e `y` com um determinado valor de epsilon `eps` e retorna um valor booleano que indica se eles são iguais dentro da tolerância determinada.
2. `double RoundTo(double value, int digits)` arredonda um valor duplo `value` para o número de `dígitos` decimais fornecido.
3. `string FormatMoney(double amount)` formata um valor duplo `amount` como uma string que representa um valor monetário. Ele formata o valor com duas casas decimais, substitui o ponto decimal por uma vírgula e insere espaços a cada três dígitos para facilitar a leitura. Ele também adiciona o símbolo de moeda obtido de `AccountInfoString(ACCOUNT_CURRENCY)` no final.
Muito obrigado por isso. Entretanto, essas funções já estão implementadas na biblioteca (inclusive com resultados mais robustos do que os seus), mas com nomes diferentes.
// Verificar se dois números são iguais até "n" dígitos de precisão.int Compare(constdouble a, constdouble b, constint digits);
bool EqualDoubles(double a, double b, int significantDigits = 15);
bool IsClose(constdouble a, constdouble b, constint maxDifferentSignificantDigits = 2)
// arredondamento decimal preciso para evitar resultados inesperados.double Round(constdouble v);
double Round(constdoublevalue, constint digits);
double Round(constdoublevalue, constdouble step);
// Formata double com separador de milhares e decimais especificados.string FormatDouble(constdouble number, constint digits, conststring separator=",");
Eu esperava que a segunda impressão fosse "0,0001".
Se for um bug, como corrigi-lo? Caso contrário, o que há de errado em meu código?
Muito obrigado.
Imprima as representações hexadecimais e você entenderá que o spread está longe do valor real verdadeiro de 0,0001 (isso se deve a erros de arredondamento durante a subtração).
Portanto, você precisa usar procedimentos de arredondamento.
jonlinper #: Eu esperava que a segunda impressão fosse "0,0001".
O ponto flutuante tem um número infinito de casas decimais. O problema é que você não entende o que é ponto flutuante e que alguns números não podem ser representados exatamente. (como 1/10.) Formato de ponto flutuante de precisão dupla - Wikipedia
O ponto flutuante tem um número infinito de casas decimais. O problema é que você não entende o que é ponto flutuante e que alguns números não podem ser representados exatamente. (como 1/10.) Formato de ponto flutuante de precisão dupla - Wikipedia
Caro William, obrigado pelo esclarecimento, mas não concordo com você no que diz respeito ao "número infinito de casas decimais". Na verdade, os números FP têm um número finito de dígitos decimais. (Por exemplo, 0,1 tem exatamente 52 dígitos após o ponto decimal).
Por favor, use DoubleToStringExact(0.1) da minha biblioteca para imprimir todos eles. Além disso, você pode verificar a cadeia decimal completa usando esta calculadora aqui: https://www.exploringbinary.com/floating-point-converter/
Observe também que a cadeia decimal completa deve sempre terminar com o dígito "5".
Qual é a maneira mais otimizada de imprimir apenas dígitos significativos com duplas.
double Trunc(constdoublevalue, constint digits);
Essa função funciona muito bem para 99,9% dos números, mas tem problemas com números redondos como 1.0000000000
Meu problema é que preciso remover os dígitos não significativos e, por algum motivo, não consigo fazer isso usando apenas @Trunc,
então acabei usando algo como:
string Normalize_Double_ToString(double n, int d)
{
// Etapa 1 - ajuda a excluir os zeros finais
n = Round(n, d);
// Etapa 2 - contar o número de casas decimais significativasint sd = GetSignificantDecimals(n);
// Etapa 3 - não queremos mais do que o especificado em @dif (sd > d){ sd = d; }
// Etapa 4 - remover decimais indesejados sem o arredondamento aleatório negativo double t = Trunc(n, sd);
// Depurar//PrintFormat("%s [%d] [%d] :: %s", DoubleToString(n, DBL_DIG), d, sd, DoubleToString(t, sd));// Etapa 5 - definir a precisãostring s = DoubleToString(t, sd);
return s;
}
Ele funciona exatamente como necessário, fornecendo a menor cadeia de caracteres possível para todos os números, mas gostaria de saber se ele pode ser otimizado e ainda obter a menor cadeia de caracteres com números redondos como 1.00000000
Cristian Dan Fechete números redondos como 1.0000000000
Meu problema é que preciso remover os dígitos não significativos e, por algum motivo, não consigo fazer isso usando apenas @Trunc,
então acabei usando algo como:
Ele funciona exatamente como necessário, fornecendo a menor cadeia de caracteres possível para todos os números, mas gostaria de saber se ele pode ser otimizado e ainda obter a menor cadeia de caracteres com números redondos como 1,00000000
Obrigado pela atenção
Desculpe, mas você precisa entender o que são dígitos significativos, pois acho que seu código está confundindo os conceitos básicos.
O que está tentando fazer? Explique em palavras simples, sem código. Dê um exemplo do que você acha que está errado e quais são suas expectativas.
amrali #: Desculpe, mas você precisa entender o que são dígitos significativos, pois acho que seu código está confundindo os conceitos básicos.
O que você está tentando fazer? Explique em palavras simples, sem código. Dê um exemplo do que você acha que está errado e quais são suas expectativas.
Obrigado pelo seu tempo e, sim, não tenho certeza se entendi "dígitos significativos
Basicamente, preciso "imprimir" o menor número possível. Por exemplo:
1.0000000 -> 1
1.0090000 -> 1.009
123.00100 -> 123.001
Para mim, "dígitos significativos" significa: dígito que altera o valor de um número se for removido, portanto, os zeros à direita não são significativos.
A propósito, desde a última atualização do Windows, a função Round(double, int) está causando o bloqueio do MT4. O primeiro código que postei estava funcionando perfeitamente e, desde ontem à noite, ele congela completamente o cliente MT4.
Obrigado pelo seu tempo e, sim, não tenho certeza se entendi bem o que são "dígitos significativos
Basicamente, preciso "imprimir" o menor número possível. Por exemplo:
1.0000000 -> 1
1.0090000 -> 1.009
123.00100 -> 123.001
Para mim, "dígitos significativos" significa: dígito que altera o valor de um número se for removido, portanto, zeros à direita não são significativos.
A propósito, desde a última atualização do Windows, a função Round(double, int) está causando o bloqueio do MT4. O primeiro código que postei estava funcionando perfeitamente e, desde ontem à noite, ele congela completamente o cliente MT4.
A função Print() ou a conversão de double em string como (string)dbl obterá o menor número possível de dígitos significativos, sem necessidade de manipular o número primeiro. Esse é um recurso incorporado no MQL. (Já propus uma correção para a equipe de desenvolvedores, e ela foi incorporada ao código).
Tudo o que você precisa fazer é:
string num_str = string(number).
ou, Print(number);
É por isso que não é necessária uma função dedicada para imprimir ou formatar números na menor string possível dentro da biblioteca, pois a funcionalidade já é compatível com a linguagem MQL.
Use DoubleToString() somente se precisar controlar o número de dígitos após o ponto decimal. Se o parâmetro digits for maior que os dígitos decimais em seu número, os 0s serão anexados à string retornada, por exemplo
DoubleToString(1.09, 5) retorna a cadeia de caracteres "1.09000".
Se o parâmetro digits for menor que os dígitos decimais do número, o número será aproximado, como DoubleToString(1.12345, 2) que retorna a string "1.12". Sua confusão decorre da incapacidade de diferenciar números de cadeias de caracteres.
Observe que os números que terminam em zeros, como 1,09, 1,090, 1,0900, 1,09000 e 1,090000, são armazenados como o mesmo número fp de precisão dupla em variáveis. Isso só pode ser obtido por meio da entrada direta do usuário como entradas manuais. Dentro do programa, todos esses números são armazenados como o mesmo número, que é 1,09, e os 0s finais não são armazenados.
double a = 1,09;
double b = 1,090000;
Print(a); // "1.09"
Print(b); // "1.09"
Funções de arredondamento como round, ceil e floor alteram (aproximam) o número de entrada para outro número que é o número duplo mais próximo com a contagem especificada de dígitos decimais após o ponto decimal ou o número que contém o número total especificado de dígitos significativos no caso de RoundToSignificantDigits().
Espero que isso tenha esclarecido a confusão sobre a conversão de números fp de precisão dupla em string.
3. `string FormatMoney(double amount)` formata um valor duplo `amount` como uma string que representa um valor monetário. Ele formata o valor com duas casas decimais, substitui o ponto decimal por uma vírgula e insere espaços a cada três dígitos para facilitar a leitura. Ele também adiciona o símbolo de moeda obtido de `AccountInfoString(ACCOUNT_CURRENCY)` no final.
Muito obrigado por isso. Entretanto, essas funções já estão implementadas na biblioteca (inclusive com resultados mais robustos do que os seus), mas com nomes diferentes.
Olá @amrali, obrigado por sua contribuição.
Talvez isso seja um bug?
Eu esperava que a segunda impressão fosse "0,0001".
Se for um bug, como corrigi-lo? Caso contrário, o que há de errado em meu código?
Muito obrigado.
Olá @amrali, obrigado por sua contribuição.
Talvez isso seja um bug?
Eu esperava que a segunda impressão fosse "0,0001".
Se for um bug, como corrigi-lo? Caso contrário, o que há de errado em meu código?
Muito obrigado.
Imprima as representações hexadecimais e você entenderá que o spread está longe do valor real verdadeiro de 0,0001 (isso se deve a erros de arredondamento durante a subtração).
Portanto, você precisa usar procedimentos de arredondamento.
Há diferenças sutis que você deve observar:
StripError() arredonda para o 16º dígito significativo 0,00009999999999998899 (0's não são contados).
Round(x, 16) arredonda para o 16º dígito após o ponto decimal 0,00009999999999998899
O ponto flutuante tem um número infinito de casas decimais. O problema é que você não entende o que é ponto flutuante e que alguns números não podem ser representados exatamente. (como 1/10.)
Formato de ponto flutuante de precisão dupla - Wikipedia
Veja também o operando ==. - Fórum de programação MQL4 (2013)
Se você quiser ver o número correto de dígitos, converta-o em uma string com a precisão correta/desejada.
question about decima of marketinfo() - MQL4 programming forum (2016)
O ponto flutuante tem um número infinito de casas decimais. O problema é que você não entende o que é ponto flutuante e que alguns números não podem ser representados exatamente. (como 1/10.)
Formato de ponto flutuante de precisão dupla - Wikipedia
Veja também o operando ==. - Fórum de programação MQL4 (2013)
Se você quiser ver o número correto de dígitos, converta-o em uma string com a precisão correta/desejada.
pergunta sobre decima de marketinfo() - Fórum de programação MQL4 (2016)
Qual é a maneira mais otimizada de imprimir apenas dígitos significativos com duplas.
Essa função funciona muito bem para 99,9% dos números, mas tem problemas com números redondos como 1.0000000000
Meu problema é que preciso remover os dígitos não significativos e, por algum motivo, não consigo fazer isso usando apenas @Trunc,
então acabei usando algo como:
Ele funciona exatamente como necessário, fornecendo a menor cadeia de caracteres possível para todos os números, mas gostaria de saber se ele pode ser otimizado e ainda obter a menor cadeia de caracteres com números redondos como 1.00000000
Obrigado pela atenção
Acabei de perceber que estou usando
Uma versão ligeiramente modificada do seu
e este é o código
Meu problema é que preciso remover os dígitos não significativos e, por algum motivo, não consigo fazer isso usando apenas @Trunc,
então acabei usando algo como:
Ele funciona exatamente como necessário, fornecendo a menor cadeia de caracteres possível para todos os números, mas gostaria de saber se ele pode ser otimizado e ainda obter a menor cadeia de caracteres com números redondos como 1,00000000
Obrigado pela atenção
Desculpe, mas você precisa entender o que são dígitos significativos, pois acho que seu código está confundindo os conceitos básicos.
Obrigado pelo seu tempo e, sim, não tenho certeza se entendi "dígitos significativos
Basicamente, preciso "imprimir" o menor número possível. Por exemplo:
1.0000000 -> 1
1.0090000 -> 1.009
123.00100 -> 123.001
Para mim, "dígitos significativos" significa: dígito que altera o valor de um número se for removido, portanto, os zeros à direita não são significativos.
A propósito, desde a última atualização do Windows, a função Round(double, int) está causando o bloqueio do MT4. O primeiro código que postei estava funcionando perfeitamente e, desde ontem à noite, ele congela completamente o cliente MT4.
Obrigado pelo seu tempo e, sim, não tenho certeza se entendi bem o que são "dígitos significativos
Basicamente, preciso "imprimir" o menor número possível. Por exemplo:
1.0000000 -> 1
1.0090000 -> 1.009
123.00100 -> 123.001
Para mim, "dígitos significativos" significa: dígito que altera o valor de um número se for removido, portanto, zeros à direita não são significativos.
A propósito, desde a última atualização do Windows, a função Round(double, int) está causando o bloqueio do MT4. O primeiro código que postei estava funcionando perfeitamente e, desde ontem à noite, ele congela completamente o cliente MT4.