Pergunta para os mestres da MQL4. Novamente sobre Double Compare. - página 6

 
VBAG:
...
A beleza do código Irtron é sua compacidade (absolutamente nada a mais - até mesmo variáveis são salvas!)
...


Aqui, veja o método proposto pela Irtron

int ComparePrice(double a, double b, double digit)
{
     a -= b;
     b = digit;
     if (a > b)
         return (1);
     if (a < -b)
         return (-1);
     return (0);
 }

É compacto e mais rápido que o meu, mas mesmo à primeira vista parece suspeito, pois a comparação envolve duas variáveis, a dupla

Neste esquema, apenas um dígito age como uma constante e pode ser comparado, enquanto a variável a, que também é comparada, permaneceu dupla não normalizada!
Isto suscita suspeitas? (Sob constante entendo as constantes habituais - "#define" e aquelas variáveis que não estavam envolvidas nas operações).

Também em outros ramos os próprios desenvolvedores escreveram que mesmo as constantes dobram melhor para não se comparar!!!
Isto também não é correto para fazer NormalizeDuplo(a) ! NormalizeDuplo(b), !OC! - operador de comparação!

Ainda mais, na versão original em vez de dígitos constantes era assim b = Ponto / 2 - aqui já duas de duas variáveis não-normalizadas?

Eu gostaria de acreditar que esta variante é genial, mas primeiro desfaça minhas dúvidas!

Talvez alguém encontre erros em minha variante também?
 
gravity001:

Veja aqui o método sugerido pela Irtron

int ComparePrice(double a, double b, double digit)
{
     a -= b;
     b = digit;
     if (a > b)
         return (1);
     if (a < -b)
         return (-1);
     return (0);
 }
Eu sugeri um método diferente.
Veja mais de perto, por favor.


Especialmente porque na versão original em vez dos dígitos constantes era tão b = Ponto / 2 - aqui já duas das duas variáveis não-normalizadas?

De que versões estamos falando?

Já lhe falei sobre a normalização. Primeiro, diga-me por que aplicá-lo, e depois como e onde.

Por exemplo, talvez você saiba, por que devemos comparar os preços com a precisão de 14 sinais, que é mencionada como alguma conquista na discussão acima? :) Deixe-me lembrá-lo, a função que sugeri se chama ComparePrice :)
 

Irtron писал (а):
...
Eu sugeri um método diferente.
Veja com mais cuidado, por favor.
...

De que versões estamos falando?

Já lhe falei sobre a normalização. Primeiro, diga-me por que deve ser aplicado, e depois como e onde.

Por exemplo, talvez você saiba, por que devemos comparar preços com precisão de 14 dígitos, que é mencionado como algum tipo de conquista na discussão acima? :) Deixe-me lembrá-lo, a função que sugeri se chama ComparePrice :)
Aqui, isto é seu? Estou citando corretamente agora?
Irtron 10.09.2007 04:07

...

int Comparação de preços(duplo a, duplo b)
{
a -= b;
b = Ponto / 2;
se (a > b)
retornar (1);
se (a < -b)
retorno (-1);
retorno (0);
}
...
Apenas um lembrete, a função que sugeri se chama ComparePrice. :)

Se você notou, eu também citei a função chamada ComparePrice. É que o seu já foi modificado pela VBAG. É por isso que me referi à versão pura que significa a original, ou seja, a sua função!
Eu mesmo já testei ambas as funções. Sim, eles se revelaram mais rápidos. Mas como verificar a confiabilidade da comparação? Estou muito confuso com a comparação de duas variáveis, o dobro. Embora tudo deva estar correto, pois é preciso um intervalo! Mas ainda existem suspeitas de que nem sempre funcionará corretamente!

Já falei sobre a normalização. Primeiro me diga por que aplicá-lo, e depois como e onde.

Esta é a pergunta chave, não é? Eu mesmo pensei por muito tempo: "Você digita o dobro e recebe o dobro ".
Ainda não encontrei a resposta exata. Mas eu posso imaginar desta forma

duplo a = 2.000000000000
duplo b = 2.000000000001
duplo c = 1,99999999999999

Todas estas variáveis são diferentes e são armazenadas na memória com precisão até o último dígito!
Neste caso, nós mesmos definimos os sinais (dígitos). Tudo o que não é definido é preenchido com zeros.

Se tivéssemos definido o dobro a = 2,0, e ele é armazenado na memória como 2,0000001 ou 1,9999999, é claro que NormalizeDouble() não ajudaria, pois devolveria um valor impreciso!
Acho que tal erro ocorre quase nunca ao memorizar um valor variável. Além disso, não acho que o número 2.0 seja armazenado como 1.9999999999999999999 de propósito, já que cada caractere (dígito ou ponto) é armazenado com um bit específico no fio de bits! Portanto, o número 2.0 é armazenado com segurança como 2.00000...00.

O outro caso é quando nós mesmos não determinamos os sinais:

a = 4.0;
b = 2.0;
c = a / b // - a operação de "divisão" é feita pelo processador, ou melhor, pelo co-processador, e preenche o pré-menu com caracteres (dígitos).

Após a operação, pode ser:
Mais comumente:
с = 2.000...0
с= 1.99999999...
с= 2.00000001...

ou seja, o resultado muitas vezes difere do valor real por uma pequena quantidade.

Grandes erros ocorrem muito raramente:
с = 2.3

Aqui, há duas explicações:
1) parte da cadeia de bits foi afetada na memória ao chamar a ou b, ou seja, as variáveis a e b foram alteradas.
2) um erro ocorreu durante a operação de "dividir".

Eu acho que 2) ocorre com mais freqüência. Por que eu não sei. Acho que tem a ver com o fato de que o co-processador tem a intenção de ser altamente otimizado em detrimento da inutilidade.

Ao comparar uma variável com a número 2.000....00, a igualdade obviamente falhará. Nem todos os bits serão iguais.

Agora, a NormalizeDouble() está aqui para ajudar!
NormalizeDouble() irá "corrigir" este pequeno erro!
Como o erro é freqüentemente muito pequeno, arredondamentos com uma pequena precisão sempre darão o resultado correto.

Veja as coisas desta maneira:
Arredondar o número a = 2.111...11 para o segundo dígito.
NormalizeDouble() irá escrever 2,11 em uma nova variável e preencher os pedaços restantes com zeros, não uns!
Acho que será parecido com isto:

double MyNormalizeDouble(double value, int digits)
{
    int factor = MathRound( MathPow(10, digits) ); // factor - это множитель,
                                                      с помощью которого мы из VALUE сделаем целое число
    double result = MathRound(factor * value) / factor;
    
    return(result);
}
Aqui, eu tentei o melhor para explicar porque NormalizeDouble() é necessário.

Até recentemente eu estava completamente satisfeito com esta explicação, mas recentemente me convenci de que este esquema nem sempre funciona.

NormalizeDuplo(a, 2) !OC! NormalizeDuplo(b, 2) onde !OC! - é um operador de comparação.
Embora, de acordo com meu entendimento, isso sempre deve funcionar!
Portanto, ficarei feliz em receber qualquer crítica fundamentada e compreensível!
 
gravity001:

Além disso, em outros tópicos os próprios desenvolvedores escreveram que mesmo as constantes duplas são melhores para não serem comparadas!!!
Isto é novidade para mim! Isto é o que eles chamam de uma questão substantiva!
Se você puder, por favor, me dê um link!

Tenho uma pergunta para os desenvolvedores:

Favor explicar quais são as limitações ou possíveis problemas quando se comparam as duplas usando constantes:
1.
duplo a=1,23456789;
duplo b;

if(a>b) ou if(a<b)

E sob esta forma:
2.
#define a 1.23456789;

duplo b;

if(a>b) ou if(a<b)
 
gravity001:

Especialmente porque a versão original tinha b = Ponto / 2 ao invés de dígitos constantes - aqui já duas de duas variáveis não-normalizadas?

É por isso que substituí b = Ponto / 2 por constante (1,menos operações - velocidade mais rápida 2,transferência constante explícita - maior confiabilidade)

Mas à luz de sua afirmação sobre a falta de confiabilidade da dupla comparação constante, o ponto inteiro se perde. Precisamos analisar esta questão mais de perto.

O que será que os desenvolvedores vão dizer?
 
VBAG писал (а):
...
Agora isso é novidade para mim! Isso é o que eles chamam de uma questão substantiva!
Se você puder, por favor, me dê um link!
...
Sim, eu estava procurando o link, queria colá-lo imediatamente, mas não consegui encontrá-lo! Lembro-me de ver isso em algum lugar, mas havia tantos temas assim. Também li uma série de tópicos sobre outros fóruns, e de livros sobre o assunto.
Eu me lembro de alguém escrevendo em algum lugar, mas não consigo lembrar onde(((((. Portanto, provavelmente, não foi correto da minha parte escrever: "em outras linhas os próprios desenvolvedores escreveram"!
Peço desculpas.
Mas se eu encontrar o link, não deixe de postar.

Acho que o li em um livro sobre C++. Ele descreveu como comparar números reais e disse que é melhor ir para inteiros!
 
gravity001:
VBAG escreveu (a):
...
Isto é novidade para mim! Isso é o que eles chamam de uma questão substantiva!
Se você puder, por favor, me dê um link!
...
Sim, eu estava procurando o link, queria inseri-lo imediatamente, mas não o encontrei! Lembro-me de ver isso em algum lugar, mas havia tantos temas assim. Também li uma série de tópicos sobre outros fóruns, e de livros sobre o assunto.
Eu me lembro de alguém escrevendo em algum lugar, mas não consigo lembrar onde(((((. Portanto, provavelmente, não foi correto da minha parte escrever: "em outros tópicos os próprios desenvolvedores escreveram"!
Peço desculpas.
Mas se eu encontrar o link, não deixe de postar.

Acho que o li em um livro sobre C++. Ele descreveu como comparar números reais e disse que é melhor ir para inteiros!
Obrigado por sua participação e ajuda. Infelizmente, eu não tenho formação acadêmica em programação. Portanto, tenho que ouvir e memorizar mais. E espero que os desenvolvedores respondam e esclareçam minha pergunta.
Tenho uma pergunta para os desenvolvedores:

Favor esclarecer quais são as limitações ou possíveis problemas ao comparar dublagens usando constantes:
1.
duplo a=1,23456789;
duplo b;

if(a>b) ou if(a<b)

E sob esta forma:
2.
#define a 1.23456789;

duplo b;

if(a>b) ou if(a<b)
 
Tais problemas - 1,3333+0,0004 != 1,3337
 

Esta conversa parece durar indefinidamente. Quando um novo usuário adquire experiência e conhecimento adequados, ele geralmente consegue se deparar com a normalização várias vezes.

Talvez, no MT5 faça sentido limitar à força a precisão dos números reais em comparação com as operações a, digamos, 8 casas decimais (ou seja, executar à força NormalizeDouble() com dígito=8). E somente se NormalizeDouble() for explicitamente especificado, realize a normalização de acordo com os parâmetros especificados nele. Neste caso, a questão surgirá com muito menos freqüência, ou seja, somente quando o usuário precisar exatamente da precisão especificada. Na minha opinião, esta piça é um pouco mais doce, mas ainda assim mais doce do que um rabanete.

 
VBAG:
Olá!
Como você sabe, não apenas a exatidão dos cálculos, mas também a confiabilidade do código que você escreveu depende do estilo de programação e precisão no código.
Nós não escrevemos brinquedos e, portanto, a confiabilidade operacional do programa escrito é o primeiro requisito. A maioria dos cálculos é feita em rublos e uma comparação correta de dois reais
de dois números reais no código do programa requer uma certa abordagem e precisão.
Estou tentando descobrir o estilo de programação "certo", daí a pergunta:

Para uma expressão

duplo a;
duplo b;

if(a==b) ou if(a!=b)
{......} {.... ..}

os desenvolvedores recomendam isto
//+------------------------------------------------------------------+
//| Função para comparar dois números reais. |
//+------------------------------------------------------------------+
bool CompareDuplo(duplo Número1, duplo Número2)
{
bool Compare = NormalizeDuplo(Number1 - Number2, 8) == 0;
retornar(Comparar);
}
//+------------------------------------------------------------------+


Este código está correto?

duplo a;
duplo b;

if(a>b) if(a<b)
{......} {......}


Muito provavelmente não no caso geral. Qual é a maneira correta de verificá-lo?
Em geral, que estilo de trabalho com rublos é mais apropriado?
Agradecemos antecipadamente a todos que responderem.

Você fez uma bagunça... :)

A comparação dos números flutuantes é feita comparando o módulo de diferença com um pequeno limiar.

Retorno (fabs(d1-d2) < 1e-10) por exemplo.

De que adianta baralhar as águas... A função NormalizeDouble(...) é apenas para relatórios de boa aparência.