Ошибки, баги, вопросы - страница 2160

 
Andrey Khatimlianskii:

С точки зрения MQ, видимо, правильно. Как всегда, решили за нас, как удобнее.

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

В профиле исчезли сообщения.

Renat Fatkhullin, 2018.03.08 10:31

Убрали временно, чтобы уменьшить объем функционала, работающего в режиме совместимости.

Как закончим процесс переноса, добавим новые возможности.

Это новая очень большая и многофункциональная система.


Внедряются новые чаты.

 
Andrey Khatimlianskii:

С точки зрения MQ, видимо, правильно. Как всегда, решили за нас, как удобнее.

Переходим на уровень телепат... )))))

 

Непонятный баг в основном индикаторе. Возникает только на таймфреймах ниже H1, и только в момент запуска терминала. Текст ошибки «S-v5 (EURUSD,M10) array out of range in 'S-v5.mq5' (211,54)». Отрисовка происходит корректно, но в обратном порядке, хотя для всех буферов установлен флаг таймсерии.

Состав шаблона – основной индикатор (№1) (в котором возникает ошибка), дополнительный индикатор (№2) (объединение нескольких хендлов основного индикатора с различными параметрами (период просмотра)), индикатор (№3) выводящий стрелки на основной график по сигналам с индикатора №1), индикатор (№4) выводящий стрелки на основной график по сигналам с индикатора №2.

Переключении таймфрейма, повторное применение шаблона, если убрать любые 2 индикатора с 2 по 4 или только под номером 1, вывод нового символа из обзора рынка и применение данного шаблона – ошибка не воспроизводиться и отрисовка всех индикаторов происходит корректно.  

 

Ошибка при компиляции

#import "Test1.ex5"
       void f1();
#import "Test2.dll"
       void f2();
#import
typedef void (*fn)();
void OnStart()
{
    fn fn1 =        f1; //нормально
    fn fn2 =        f2; //Error: 'f2' - pointer to this function type is not supported yet
    fn fn3 = Test2::f2; //нормально
}
 

Сообщение об ошибке не позволяет понять причину в обширном коде

struct A {
    void f( int    ) {}
    void g( int fn ) { f( fn ); } //Error: ')' - unexpected token ???
};
typedef void (*fn)();

ниже понятно

struct A {
    void f( int    ) {}
    void g( int fn ) { f( fn ); } //Error: 'fn' - identifier already used
};
struct fn {};
 

Нет сообщения об ошибке

typedef void (*fn)();
void f( int i ) { Print( __FUNCTION__, ":", i ); }
void OnStart()
{
    f( fn() );
}

более того - выполняется и даже результат есть (!)

В таком варианте:

typedef int (*fn)();
void OnStart() { Print( fn() ); }

не работает переход к строке ошибки (по Enter)


 

Ошибка при компиляции

    void g(  int ) {}
    void g( uint ) {}
#import "Test.ex5"
    void f(  int );
    void f( uint );
#import
typedef void (*fn1)(  int );
typedef void (*fn2)( uint );
void OnStart()
{
    fn1 g1 = g; /*нормально и результат*/ g1( 1 ); //совпадает с ожидаемым
    fn2 g2 = g; /*нормально и результат*/ g2( 1 ); //совпадает с ожидаемым
    fn1 f1 = f; //Error: 'f' - cannot resolve function address
    fn2 f2 = f; /*нормально и результат*/ f2( 1 ); //совпадает с ожидаемым
                                                   //при наличии Test.ex5
}
 

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

И сейчас, когда я попытался разобраться с этой странностью, запутался еще больше. 

Итак, в расчете я использую функцию квадратного корня sqrt(), которую я решил обойти путем создания double массива.

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

   double SQRT[];
   int ss=Width*Width+Height*Height;
   ArrayResize(SQRT,ss);
   for(double w=0;w<ss;w++) SQRT[(int)w]=sqrt(w);

Логично предположить, что считывание из массива SQRT[x] выполняется быстрее, чем функция sqrt(x).
И это подтверждается проверочным кодом:

   double Sum1=0,Sum2=0;
   ulong t=GetMicrosecondCount();
   for(int i=0;i<ss;i++) Sum1+=sqrt(double(i));   // Находим сумму квадратных корней всех целых чисел от 0 до ss
   t=GetMicrosecondCount()-t;
   Print("Время на сумму "+IntegerToString(ss)+" значений функций = "+IntegerToString(t)+" мкс, Сумма = "+DoubleToString(Sum1));
   t=GetMicrosecondCount();
   for(int i=0;i<ss;i++) Sum2+=SQRT[(int)(i)];    // Находим сумму квадратных корней всех целых чисел от 0 до ss через сложение элементов массива SQRT[]
   t=GetMicrosecondCount()-t;
   Print("Время на сумму "+IntegerToString(ss)+" значений массива = "+IntegerToString(t)+" мкс, Сумма = "+DoubleToString(Sum2));

результат свидетельствует о выигрыше скорости ~ 1.5 раза:

Но когда я заменяю в коде функцию sqrt() на считывание элементов массива SQRT[], вместо ускорения работы, я получаю жуткие тормоза.

Считывание элемента из массиваа SQRT[] происходит в разы, может быть даже на порядок дольше, чем выполнение функции sqrt().

И я не понимаю, где происходит утечка скорости. Ведь вышеуказанный  проверочный код говорит об обратном.

Можно предположить, что компилятор каким-то странным образом осуществляет доступ к большому массиву и на каждом витке цикла словно "забывает" о массиве и каждый раз проводит свою какую-то служебную индексацию. 

Но тогда это внутренний логический или стратегический баг компилятора. Причем с этим нужно явно что-то делать, т.к. эта утечка скорости очень существенна и ее трудно обнаружить, т.к. она не очевидна.

Прилагаю код скрипта для демонстрации этой странности.

При запуске по умолчанию (arr=false) вычисляются функции sqrt(), а при изменении arr на true значение квадратного корня берется из массива.

ЧТО НЕ ТАК? ОТКУДА ТОРМОЗА?

Файлы:
Swirl.mq5  11 kb
 
Nikolai Semko:

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


Логично предположить, что считывание из массива SQRT[x] выполняется быстрее, чем функция sqrt(x).

Из динамического массива не факт.

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


И это подтверждается проверочным кодом:

результат свидетельствует о выигрыше скорости ~ 1.5 раза:

Сомневаюсь, что подтверждается.

Код такого вида прям как из учебника по оптимизации циклов. Оптимизатор кода из него просто конфетку может сделать, так как случай очень простой:

   for(int i=0;i<ss;i++) 
      Sum2+=SQRT[i];

То есть, замер производительности в случае применения заведомо идеально оптимизируемых случаев нужно четко соотносить с целями теста.

В данном случае тест неправильный.

Считывание элемента из массиваа SQRT[] происходит в разы, может быть даже на порядок дольше, чем выполнение функции sqrt().

И я не понимаю, где происходит утечка скорости. Ведь вышеуказанный  проверочный код говорит об обратном.

Не видя финального ассемблерного кода, я склоняюсь к:

  1. sqrt на самом деле быстро работает (у нас очень эффективный генератор в нативный код, sqrt превращается в чистый SQRTSD)
  2. проверочный код слишком прост и компенсирует задержки оптимизацией


Код весь проверим внимательно. Интересно найти, в чем реальная причина.

SQRTSD — Compute Square Root of Scalar Double-Precision Floating-Point Value
  • www.felixcloutier.com
Computes square root of the low double-precision floating-point value in xmm3/m64 and stores the results in xmm1 under writemask k1. Also, upper double-precision floating-point value (bits[127:64]) from xmm2 is copied to xmm1[127:64].
 
Renat Fatkhullin:

Из динамического массива не факт.


Не видя финального ассемблерного кода, я склоняюсь к:

  1. sqrt на самом деле быстро работает (у нас очень эффективный генератор в нативный код, sqrt превращается в чистый SQRTSD)
  2. проверочный код слишком прост и компенсирует задержки оптимизацией

Пробовал статический массив - тоже самое. 

Как бы sqrt не был бы быстр, но мне сложно поверить в то, что эта функция может быть в 10 раз быть быстрее простого чтения элемента массива.

Причем, если в моем примере уменьшить размер канваса, скажем 50х50 ( для этого существует входной параметр Size, нужно вместо 0 установить 50), 

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

Но мне не понятно, разве от размера массива зависит скорость доступа к его элементам?

А насчет простоты проверочного кода, пожалуй, Вы правы.

Попробовал чуть усложнить и результат совсем другой:

for(int i=0;i<ss;i++) Sum1+=i*sqrt(double(i));
....
for(int i=0;i<ss;i++) Sum2+=i*SQRT[(int)(i)];


Причина обращения: