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

 
fxsaber:

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

Откуда вам это известно?  Ведь даже если цены не нормализованы, то проверка элементарно делается и без всякой нормализации:

 if (fabs(price-limitprice) < ticksize/2)

учитывая, что цены кратны ticksize

 
Nikolai Semko:
ЗЫ причем нормализация через int получается еще и точнее (это можно увидеть по количеству девяток после последней цифры нормализации - выделено синим.)

Тест некорректный.  Почему вы делите на 100000.0 только один раз в конце?  Оно должно выполняться на каждой итерации, и потом суммироваться.  Вот тогда это будет честное сравнение.  А так у вас никакая не нормализация, а вы просто оптимизировали свой тестовый алгоритм. Естественно так будет и быстрее, и точнее (т.к. уменьшается накопленная ошибка)

 
Alexey Navoykov:

Откуда вам это известно?

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

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

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

Так вот Тестер не сравнивает напрямую. А делает это либо через NormalizeDouble, либо через ticksize, либо еще как-то. Но точно не прямым сравнением даблов. И это совсем нерационально.

 
fxsaber:

Конечно, можно и иногда даже нужно сравнивать double напрямую между собой.

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

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

Не на ровном месте MQL-кастомный Тестер уделывает нативный штатный Тестер по производительности.

решил проверить бредовую версию по быстродействию.
И результат удивил. 
Сравнение даже предварительно нормализованных double происходит в среднем даже более медленее, чем если double сравнивать через эпсилон или через преобразование в int

#define  SIZE 1000000

int Ceil (double x) {return (x-(int)x>0)?(int)x+1:(int)x;}
int Round(double x) {return (x>0)?(int)(x+0.5):(int)(x-0.5);}
int Floor(double x) {return (x>0)?(int)x:((int)x-x>0)?(int)x-1:(int)x;}

bool is_equal(double d1, double d2, double e=0.000000001) {return fabs(d1-d2)<e;}

void OnStart()
  {
   double a[SIZE], a_norm[SIZE];
   int s1=0,s2=0, s3=0;
   for (int i=0;i<SIZE;i++)  {
     a[i]=(rand()-16384)/1641.1452;
     a_norm[i]=NormalizeDouble(a[i],2);
   }
   double test = 1.11;
   
   ulong t1=GetMicrosecondCount();
   for (int i=0;i<SIZE;i++) if (a_norm[i]==test) s1++;
   t1=GetMicrosecondCount()-t1;  
   
   ulong t2=GetMicrosecondCount();
   for (int i=0;i<SIZE;i++) if (is_equal(a[i],test,0.005)) s2++;
   t2=GetMicrosecondCount()-t2; 
   
   ulong t3=GetMicrosecondCount();
   int test_int = test*100;
   for (int i=0;i<SIZE;i++) if (Round(a[i]*100)==test_int) s3++;
   t3=GetMicrosecondCount()-t3; 
   
   
   Print("простое сравнение предварительно нормализированых double - " + string(t1)+ " микросекунд, всего совпадений = "+ string(s1));
   Print("сравнение double через эпсилон                           - " + string(t2)+ " микросекунд, всего совпадений = "+ string(s2));
   Print("сравнение double через преобразование в int              - " + string(t3)+ " микросекунд, всего совпадений = "+ string(s3));  
  }

Результат:

2020.08.10 14:31:39.620 TestCompareDouble (USDCAD,H4)   простое сравнение предварительно нормализированых double - 900  микросекунд, всего совпадений = 486
2020.08.10 14:31:39.620 TestCompareDouble (USDCAD,H4)   сравнение double через эпсилон                           - 723  микросекунд, всего совпадений = 486
2020.08.10 14:31:39.620 TestCompareDouble (USDCAD,H4)   сравнение double через преобразование в int              - 805  микросекунд, всего совпадений = 486
2020.08.10 14:31:42.607 TestCompareDouble (USDCAD,H4)   простое сравнение предварительно нормализированых double - 1533 микросекунд, всего совпадений = 488
2020.08.10 14:31:42.607 TestCompareDouble (USDCAD,H4)   сравнение double через эпсилон                           - 758  микросекунд, всего совпадений = 488
2020.08.10 14:31:42.607 TestCompareDouble (USDCAD,H4)   сравнение double через преобразование в int              - 790  микросекунд, всего совпадений = 488
2020.08.10 14:31:44.638 TestCompareDouble (USDCAD,H4)   простое сравнение предварительно нормализированых double - 986  микросекунд, всего совпадений = 472
2020.08.10 14:31:44.638 TestCompareDouble (USDCAD,H4)   сравнение double через эпсилон                           - 722  микросекунд, всего совпадений = 472
2020.08.10 14:31:44.638 TestCompareDouble (USDCAD,H4)   сравнение double через преобразование в int              - 834  микросекунд, всего совпадений = 472

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

ЗЫ признаться честно - даже не понимаю, почему так происходит. 
Вроде и оптимизировать при сумме случайных чисел компилятору нечего. За скобки округление не вынесешь.
Вроде сравнение double в процессоре - это одна команда
При варианте сравнения через эпсилон(самый быстрый вариант) все равно происходит операция сравнения двух double, но при этом дополнительно происходит вызов функции с передачей трех параметров и одна операция вычитания.
Неужели производительность операции сравнения двух double зависит от значений самых переменных. Сомневаюсь.
Блин, не понимаю. Помогите пожалуйста - чего я не учел или где я ошибся?

 
Nikolai Semko:

решил проверить бредовую версию по быстродействию.
И результат удивил. 
Сравнение даже предварительно нормализованных double происходит в среднем даже более медленее, чем если double сравнивать через эпсилон или через преобразование в int

Результат:

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

Удивительно, функция округления до целого возвращает не целое, а действительное число, надо ещё и тип к целому приводить. Где логика языка?
 
Nikolai Semko:

Неужели производительность операции сравнения двух double зависит от значений самых переменных. Сомневаюсь.

Похоже что да. Весьма странно.
Если заменить строчку в примере выше

double test = 1.11;

на 

double test = NormalizeDouble(1.11,2);

то простое сравнение двух double начинает работать быстрее других вариантов. Хотя что там double, что там double. Казалось бы какая разница? А итоговая производительность выше в два раза. Чудеса какие-то.

2020.08.10 17:40:13.583 TestCompareDouble (USDCAD,H4)   простое сравнение предварительно нормализированых double 1 - 552 микросекунд, всего совпадений = 507
2020.08.10 17:40:13.583 TestCompareDouble (USDCAD,H4)   простое сравнение предварительно нормализированых double 2 - 954 микросекунд, всего совпадений = 507
2020.08.10 17:40:13.583 TestCompareDouble (USDCAD,H4)   сравнение double через эпсилон                             - 778 микросекунд, всего совпадений = 507
2020.08.10 17:40:13.583 TestCompareDouble (USDCAD,H4)   сравнение double через преобразование в int                - 854 микросекунд, всего совпадений = 507
Файлы:
 
Alexey Navoykov:

Тест некорректный.  Почему вы делите на 100000.0 только один раз в конце?  Оно должно выполняться на каждой итерации, и потом суммироваться.  Вот тогда это будет честное сравнение.  А так у вас никакая не нормализация, а вы просто оптимизировали свой тестовый алгоритм. Естественно так будет и быстрее, и точнее (т.к. уменьшается накопленная ошибка)

да, Вы правы. Точность будет такая же, как у NormalizeDouble, если делить на каждой итерации. Но скорость все равно будет выше, чем с NormalizeDouble. 

2020.08.10 21:38:48.652 TestCompareDouble (USDCAD,H4)   простая сумма                            - 1394 микросекунд, сумма = -3604329.1567609389312565
2020.08.10 21:38:48.652 TestCompareDouble (USDCAD,H4)   сумма с NormalizeDouble                  - 5861 микросекунд, сумма = -3604329.1543100476264954
2020.08.10 21:38:48.652 TestCompareDouble (USDCAD,H4)   сумма, нормализированная через int       - 2179 микросекунд, сумма = -3604329.1543100476264954

Спасибо.

 

Вообще конечно после округления до целого возврат не целого числа это не гуд. Ранее в принтах встречал после раунд почти целые числа с нулями после запятой и единицей в конце или с девятками после запятой. Думал баг. Оказывается непонятная позиция разрабов. По хорошему при округлении до целого, после запятой в двоичном виде нужно убрать остаток, но видимо обнулить мантиссу сложно / невозможно. Про нормализацию еще более сложно, даже если перенести запятую на 5 знаков и привести к целому в двоичном виде то обратное приведение к дабл даст разность с целым типом.

Грусть, приходиться костылить при вроде простых операциях сравнения.

Не питон.))))

 
Valeriy Yastremskiy:

Вообще конечно после округления до целого возврат не целого числа это не гуд. Ранее в принтах встречал после раунд почти целые числа с нулями после запятой и единицей в конце или с девятками после запятой. Думал баг. Оказывается непонятная позиция разрабов. По хорошему при округлении до целого, после запятой в двоичном виде нужно убрать остаток, но видимо обнулить мантиссу сложно / невозможно. Про нормализацию еще более сложно, даже если перенести запятую на 5 знаков и привести к целому в двоичном виде то обратное приведение к дабл даст разность с целым типом.

Грусть, приходиться костылить при вроде простых операциях сравнения.

В выражениях после округления могут присутствовать ещё какие-то операции с полученным результатом, и совсем необязательно целочисленные. Тогда придётся из int преобразовывать обратно в double, создавая оверхед на ровном месте.  Зачем оно надо?

Никто не мешает создать свои функции RoundInt или RoundLong, которые будут возвращать требуемый тип.

 

Есть проблема в тестере в маркете.

Если проверяется мультивалютный советник то тестер зависает.

Причина: Советник в процессе анализа финансового инструмента натыкается на инструменты в которых нет истории или инструмент не правильно оформлен.

В стандартном терминале такое вызывает зависание на 29 секунд, это точно и это проверено.

Тестер в маркете пишет слишком долгое тестирование.

Предполагаю что советник натыкается на несколько таких битых финансовых инструментов.

Об этой проблеме писалось несколько раз и год назад, а воз и ныне там....