Tente remover a restrição
E tente tornar os operadores de comparação "estáticos".
Os operadores não podem ser declarados "estáticos".
Pode haver mais de uma operação aritmética (de sobrecarga) por instrução, desde que cada conjunto de dois operandos seja envolvido por parênteses na ordem correta. Eu ainda não recomendo isso.
CDouble foo = 3, bar = 4, spam = 3; CDouble error = foo+bar+spam; //ERRORCDouble error_too = (pi2 + pi5)+pi2; //ERROR
CDouble correct = foo+(bar+spam);// OK!
Para esclarecer qualquer possível confusão, a maneira correta de lidar com a aritmética para declarações com mais de um operador é não usar os operadores sobrecarregados, mas, em vez disso, usar um dos métodos de obtenção de valor aplicáveis.
CDouble sum, foo=3, bar=2, spam=1; sum = foo.AsRawDouble() + bar.AsRounded() + spam.AsRoundedTick(); Print(sum.ToString()); //6
Os operadores não podem ser declarados "estáticos".
Pode haver mais de uma operação aritmética (de sobrecarga) por instrução, desde que cada conjunto de dois operandos seja envolvido por parênteses na ordem correta. Eu ainda não recomendo isso.
class CDouble2 : public CDouble { private: static CDouble2 TmpDouble; public: const CDouble2* const operator +( const double Value ) const { CDouble2::TmpDouble = this.m_value + Value; return(&CDouble2::TmpDouble); } const CDouble2* const operator +( const CDouble2 &Other ) const { return(this + Other.m_value); } static CDouble2* const Compare2( const double Value ) { CDouble2::TmpDouble = Value; return(&CDouble2::TmpDouble); } static CDouble2* const Compare2( const CDouble2 &Other ) { CDouble2::TmpDouble = Other; return(&CDouble2::TmpDouble); } }; static CDouble2 CDouble2::TmpDouble; #define _CP(A) CDouble2::Compare2(A) #define PRINT(A) Print(#A + " = " + (string)(A)); void OnStart() { CDouble2 foo = 3, bar = 4, spam = 3; CDouble2 error = foo+bar+spam + foo+bar+spam; //OK! PRINT(error.ToString()); // 10 PRINT(_CP(foo + error + 5) > 2); PRINT(_CP(25) > foo + bar + 7 +spam); PRINT((foo + bar + spam + 9).ToString()); PRINT((_CP(9) + foo).ToString()); PRINT(foo + 7 > 11) }
Resultado
error.ToString() = 20 _CP(foo+error+5)>2 = true _CP(25)>foo+bar+7+spam = false (foo+bar+spam+9).ToString() = 19 (_CP(9)+foo).ToString() = 12 foo+7>11 = false
Resultado
Isso é muito inteligente e eu gosto muito, mas é inteligente demais para a maioria dos usuários... (nós dois já fomos acusados disso nos fóruns;) Vou confirmar suas alterações na minha biblioteca pessoal, e outros também podem fazê-lo, mas para o benefício de uma base maior de usuários, vou mantê-lo simples e seguir a recomendação oficial de chamar um dos métodos getter. (por exemplo, num1.AsRounded() * num2.AsRounded() + num3.AsRounded())
Para sua informação, eu pessoalmente gosto de (num1*num2+num3).AsRounded()
Desafios com o CDouble2 conforme proposto:
void Func(double param) { } void OnStart() { CDouble2 foo = 2, bar = 3; double number = foo+bar; //ERROR Func(foo+bar); //ERROR }
* Versão 1.01:
- Corrigido o erro em que os operadores aritméticos não retornavam valores arredondados.
- Adicionado o método symbol setter para definir o símbolo após a chamada do construtor
Olá, nicholishen. Testei sua biblioteca por algum tempo. Ela é excelente e facilita o arredondamento de preços e lotes.
Porém, tenho algumas preocupações com relação à precisão de seus métodos de arredondamento. Encontrei muitos erros de arredondamento nas funções RoundToStep(), RoundToStepUp(), RoundToStepDown() e RoundToTick(). Esses erros sempre ocorrem em números de borda que terminam em 5 (como 1,12345).
Por exemplo, CDouble::RoundToStep(1.700605, 0.00001) retorna 1.70060, em vez do resultado correto 1.70061
A equação round(number / point) * point deve ser corrigida para round(number * power) / power, em que tanto o point quanto o power são derivados do número de dígitos decimais que você deseja arredondar.
Como o valor de 1 ponto, que supostamente = 0,00001, é na verdade codificado como 0,0000100000000000000008180305391403130954586231382563710 como um ponto flutuante de precisão dupla de 64 bits. Isso faz com que o resultado final do seu método de arredondamento, round(number / point) * point, se desvie do resultado correto em 1 ponto (0,00001), com muita frequência.
Além disso, para fazer um arredondamento "aritmético" adequado (arredondamento do ponto médio para longe do zero), um bom método é adicionar ou subtrair meio épsilon como correção. (Isso compensará qualquer arredondamento da metade para o par que tenha sido aplicado pelo processador, conforme exigido pelas especificações IEEE-754, especialmente nos casos extremos do ponto médio).
A função NormalizeDouble() do mql lida com todos esses problemas corretamente, e você deve usá-la para fazer o arredondamento "aritmético" adequado.
Aqui também está o código-fonte de uma função que escrevi para fazer o arredondamento aritmético, que você mesmo pode testar. Essa função tem exatamente os mesmos resultados que NormalizeDouble(). Minha função é executada ainda mais rapidamente e suporta um nível mais alto de precisão de arredondamento. (A NormalizeDouble() do MQL é limitada a 8 dígitos decimais).
/** * MidpointRounding away from zero (arredondamento "aritmético") * Usa um meio épsilon para correção. (Isso compensa o arredondamento IEEE-754 * da metade para o par que foi aplicado nos casos extremos). */ double RoundCorrect(double num, int precision) { double c = 0.5 * DBL_EPSILON * num; // double p = MathPow(10, precision); //slow double p = 1; while (precision--> 0) p *= 10; if (num < 0) p *= -1; return MathRound((num + c) * p) / p; }
Além disso, aqui está um script que você pode usar para depurar a precisão do arredondamento na biblioteca CDouble. Espero que seja útil para você.
#property strict #define PRINT(A) Print(#A + " = ", (A)) #define forEach(element, array) for (int __i = 0, __max = ArraySize((array)); __i < __max && ((element) = array[__i]) == (element); __i++) #include "CDouble.mqh" //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ string DoubleToFixed(double number, int decimals = 55) { return StringFormat(StringFormat("%%#.%if", decimals), number); } //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ void OnStart() { // teste de arredondamento de alguns casos extremos double numbers_3[] = {1.005, 2.175, 5.015, 16.025}; double numbers_6[] = {1.011885, 1.113325, 1.143355, 1.700605}; double num; forEach (num, numbers_3) { Print("----------------------------------------------"); PRINT( num ); // comparar 3 funções (arredondar para 2 dígitos) PRINT( CDouble::RoundToStep(num, 0.01) ); PRINT( NormalizeDouble(num, 2) ); PRINT( RoundCorrect(num, 2) ); } forEach (num, numbers_6) { Print("----------------------------------------------"); PRINT( num ); // comparar 3 funções (arredondar para 5 dígitos) PRINT( CDouble::RoundToStep(num, 0.00001) ); PRINT( NormalizeDouble(num, 5) ); PRINT( RoundCorrect(num, 5) ); } // A causa dos problemas de arredondamento na biblioteca CDouble Print("----------------------------------------------"); PRINT( DoubleToFixed(0.01, 55) ); // 0.0000100000000000000008180305391403130954586231382563710 PRINT( DoubleToFixed(0.00001, 55) ); // 0.0100000000000000002081668171172168513294309377670288086 // comparar NormalizeDouble e RoundCorrect por igualdade exata Print("----------------------------------------------"); PRINT( NormalizeDouble(numbers_6[0], 5) == RoundCorrect(numbers_6[0], 5) ); // verdadeiro PRINT( NormalizeDouble(numbers_6[0], 4) == RoundCorrect(numbers_6[0], 4) ); // verdadeiro PRINT( NormalizeDouble(numbers_6[0], 3) == RoundCorrect(numbers_6[0], 3) ); // verdadeiro PRINT( NormalizeDouble(numbers_6[0], 2) == RoundCorrect(numbers_6[0], 2) ); // verdadeiro PRINT( NormalizeDouble(numbers_6[0], 1) == RoundCorrect(numbers_6[0], 1) ); // verdadeiro }
Olá, nicholishen. Testei sua biblioteca por algum tempo. Ela é excelente e facilita o arredondamento de preços e lotes.
Porém, tenho algumas preocupações com relação à precisão de seus métodos de arredondamento. Encontrei muitos erros de arredondamento nas funções RoundToStep(), RoundToStepUp(), RoundToStepDown() e RoundToTick(). Esses erros sempre ocorrem em números de borda que terminam em 5 (como 1,12345).
Por exemplo, CDouble::RoundToStep(1.700605, 0.00001) retorna 1.70060, em vez do resultado correto 1.70061
A equação round(number / point) * point deve ser corrigida para round(number * power) / power, em que tanto o point quanto o power são derivados do número de dígitos decimais que você deseja arredondar.
Como o valor de 1 ponto, que supostamente = 0,00001, é de fato codificado como 0,0000100000000000000008180305391403130954586231382563710 como um ponto flutuante de precisão dupla de 64 bits. Isso faz com que o resultado final do seu método de arredondamento, round(number / point) * point, se desvie do resultado correto em 1 ponto (0,00001), com muita frequência.
Além disso, para fazer um arredondamento "aritmético" adequado (arredondamento do ponto médio para longe do zero), um bom método é adicionar ou subtrair meio épsilon como correção. (Isso compensará qualquer arredondamento da metade para o par que tenha sido aplicado pelo processador, conforme exigido pelas especificações IEEE-754, especialmente nos casos extremos do ponto médio).
A função NormalizeDouble() do mql lida corretamente com todos esses problemas; você deve usá-la para fazer o arredondamento "aritmético" adequado.
Aqui também está o código-fonte de uma função que escrevi para fazer o arredondamento aritmético, que você mesmo pode testar. Essa função tem exatamente os mesmos resultados que NormalizeDouble(). Minha função é executada ainda mais rapidamente e suporta um nível mais alto de precisão de arredondamento. (A NormalizeDouble() do MQL é limitada a 8 dígitos decimais).
Obrigado por apontar isso. Atualizarei o código para usar NormalizeDouble em vez de round.
step * NormalizeDouble(number_to_round / step, 0)
Olá, nicholishen. Testei sua biblioteca por algum tempo. Ela é excelente e facilita o arredondamento de preços e lotes.
Porém, tenho algumas preocupações com relação à precisão de seus métodos de arredondamento. Encontrei muitos erros de arredondamento nas funções RoundToStep(), RoundToStepUp(), RoundToStepDown() e RoundToTick(). Esses erros sempre ocorrem em números de borda que terminam em 5 (como 1,12345).
Por exemplo, CDouble::RoundToStep(1.700605, 0.00001) retorna 1.70060, em vez do resultado correto 1.70061
A equação round(number / point) * point deve ser corrigida para round(number * power) / power, em que tanto o point quanto o power são derivados do número de dígitos decimais que você deseja arredondar.
Como o valor de 1 ponto, que supostamente = 0,00001, é de fato codificado como 0,0000100000000000000008180305391403130954586231382563710 como um ponto flutuante de precisão dupla de 64 bits. Isso faz com que o resultado final do seu método de arredondamento, round(number / point) * point, se desvie do resultado correto em 1 ponto (0,00001), com muita frequência.
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso
CDouble & CDoubleVector:
Uma biblioteca para métodos de arredondamento comuns usados no desenvolvimento MQL, classe wrapper primitiva para "type" (double) e vetor para objetos CDouble. MQL5 e MQL4 são compatíveis!
Autor: nicholi shen