Может ли цена != цена ? - страница 7

 

WHRoeder: этот код хорош (особенно проверка "добавлено" и "по умолчанию")? Это также может послужить легкой последней ссылкой для тех, кто посетил эту тему и просто перешел на последнюю страницу (как это сделал я)

#define LT    0
#define GT    1
#define GTE   2
#define LTE   3
#define EQ    4
#define NEQ   5

bool doublecomp(double a,int type,double b){
  // See https://forum.mql4.com/45053/page4
  // 0 compare doesn't need this function
  switch(type){
    case LT: return(b-a>Point/2.);
    case GT: return(a-b>Point/2.);
    case GTE: return(a-b>-Point); // Added
    case LTE: return(b-a>-Point); // Added
    case EQ: return(!(MathAbs(a-b)>Point/2.));
    case NEQ: return(MathAbs(a-b)>Point/2.);
    default: return(-1); // Added - needed to avoid compile error about not all control paths returning a value
  }
}
 

Этот код не является точным.

Как можно использовать if( !MathAbs( a - b ) > Point/2) для сравнения на равенство? Это скажет вам, что 1.4999 == 1.5000.

 
SDC: Как можно использовать if( !MathAbs( a - b ) > Point/2) для сравнения на равенство? Это скажет вам, что 1.4999 == 1.5000.
  1. Это не так.
    if( ! (MathAbs( a     -  b    ) > Point/2) ) be used to compare for equality? That would tell you 1.4999 == 1.5000
    if( ! (MathAbs(1.4999 - 1.5000  > 0.00005  )
    if( ! (0.0001                   > 0.00005  )
    if( ! (true                                )
    if( false                                  ) 1.4999 is NOT equal to 1.5000
  2. И я указал Roel13 в PM, что GEQ/LEQ должны быть -Point/2, но он не отредактировал сообщение.
  3. И как я уже писал ранее, вам стоит беспокоиться о такой ерунде только в том случае, если равенство/неравенство имеет значение. Если вы хотите открыться выше максимума свечи, имеет ли значение, что (из-за округления) он может сработать именно на максимуме? Если нет, просто используйте bid > high[].
 

Я использую

if(NormalizeDouble(price1-price2,Digits)==0)


или для двойных значений, которые не являются фактическими ценами, более высокая точность

if(NormalizeDouble(value1-value2,8)==0)
 
SDC: Я использую
if(NormalizeDouble(price1-price2,Digits)==0)
Прочитайте самое первое сообщение и вы узнаете, почему это не очень хорошая идея.
 

Сообщение Raptors об этом коде

double TestValue = iClose(NULL, 0, 0);
   
if(TestValue != NormalizeDouble(TestValue, Digits) ) //not equal

Так что если вы используете,

double TestValue = iClose(NULL, 0, 0);

if(NormalizeDouble(TestValue - iClose(NULL,0,0),Digits)==0) // they are considered equal

Я тестировал этот метод различными способами и не нашел сценария, в котором он не вернул бы ожидаемый или желаемый результат.
 

Окончательный код... Спасибо WHRoeder

#define LT    0
#define GT    1
#define GTE   2
#define LTE   3
#define EQ    4
#define NEQ   5

bool ComparePrice(double a,int type,double b){
  // See https://forum.mql4.com/45053/page4
  // 0 compare doesn't need this function
  switch(type){
    case LT: return(b-a>Point/2.);
    case GT: return(a-b>Point/2.);
    case GTE: return(a-b>-Point/2.);
    case LTE: return(b-a>-Point/2.);
    case EQ: return(!(MathAbs(a-b)>Point/2.));
    case NEQ: return(MathAbs(a-b)>Point/2.);
  }
  return(-1);
}


И, возможно, вторичная функция для сравнения всех других двойных чисел, которые не являются ценами...

bool CompareNormal(double a,int type,double b){
  // With thanks https://forum.mql4.com/45053/page4
  // 0 compare doesn't need this function
  switch(type){
    case LT: return(b-a>0.0000000000000000000000000000001);
    case GT: return(a-b>0.0000000000000000000000000000001);
    case LTE: return(b-a>-0.0000000000000000000000000000001);
    case GTE: return(a-b>-0.0000000000000000000000000000001);
    case EQ: return(!(MathAbs(a-b)>0.0000000000000000000000000000001));
    case NEQ: return(MathAbs(a-b)>0.0000000000000000000000000000001);
  }
  return(-1);
}


Смотрите также "Справочник MQL4 > Основы языка > Типы данных > Вещественные типы (double, float)" в части использования малого числа для сравнения.

Возможно, кто-то знает, как лучше написать 0.00...1 в expon

 
Roel13: Возможно, кто-то знает, как лучше написать 0.00...1 в expon.
// case LT: return(b-a>0.0000000000000000000000000000001);
// case LT: return(b-a>1.0e-30);
Смотрите Вещественные типы (double, float) - Документация MQL4
Замечено, что значение epsilon в приведенном выше примере не может быть меньше предопределенной константы DBL_EPSILON. Значение этой константы равно 2.2204460492503131e-016.
Опять же, все это не нужно, за исключением случаев, когда важно равенство/не равенство. Например, открываясь выше предыдущего максимума, вы не хотите открываться на максимуме из-за округления.
 

Есть еще кое-что интересное, что я нашел, потенциально связанное с "// 0 compare не нуждается в этой функции".

Возможно, это ошибка только в последних версиях, не уверен. Сравнение с 0 больше не работает корректно. Мне пришлось прибегнуть к чему-то недружелюбному, например;

outcome=(int(outcome*100)/100.0); // Разрешение 2 цифры

Только для того, чтобы убедиться, что 0-значения действительно закончились как 0-значения.

WHRoeder, спасибо. Нужно больше исследований :)

 

Я думаю, что в этой теме слишком много ненужной сложности.

Постарайтесь максимально облегчить жизнь программиста. Напишите определения (или перейдите к методам, если это действительно необходимо) в тех классах, где вам нужны двойные сравнения:

// add more floating point zeros if you need a higher precision
#define  isZero(x) (fabs(x) < 0.000000001)
#define  isEqual(x,y) (fabs(x-y) < 0.000000001)

Когда вам нужно сравнить два двойных числа, используйте это в условии, подобном этому:

if (isEqual(myFirstDouble, mySecondDouble))
{
  // first and second doubles are considered equal
  // do something
}

Если вы хотите проверить, является ли двойка нулем (или очень, очень близка к нулю), используйте условие, подобное этому:

if (isZero(myDouble))
{
  // myDouble is considered zero
  // do something
}


В качестве примечания, поскольку я вижу много сообщений, говорящих о делениях:

При инкапсуляции мы склонны забывать об издержках кода, который "отдан на аутсорсинг" некоторым вспомогательным методам. Напомните себе, чтоделения очень дороги с вычислительной точки зрения! Особенно, когда, завернув их в красивые утилитарные методы где-нибудь в утилитарных классах, мы начинаем использовать их повсюду в индикаторах или советниках и уже давно забыли, какие вычислительные действия они выполняют. При использовании тестера стратегий мы платим за свою неаккуратность большим количеством ненужного времени.

Эмпирическое правило: Сложение и вычитание выполняются гораздо быстрее, чем умножение и деление. Операция деления занимает больше всего времени.Оптимизируйте деление- везде, где это возможно! Если знаменатель фиксированный, как в этом цикле...

for(int i=0; i < rates_total; i++)
{
    // ...
    double fraction = someNumeratorValue / 100;
    // ...
}

то замените знаменатель x на его инвертированное значение 1/x:

for(int i=0; i < rates_total; i++)
{
    // ...
    double fraction = 0.01 * someNumeratorValue; // replace a denominator with it's inverted value, if possible.
    // ...
}

Также, если результат деления всегда один и тот же, выполните вычисления один раз и сохраните результат в переменной, чтобы использовать его везде в коде (например, в циклах):

double tradesPerDay = totalTradesPerYear/365;

for(int i=0; i < rates_total; i++)
{
    // use precomputed tradesPerDay rather than computing the division here.
}

Будьте здоровы,

A.T.