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

 
void OnStart()
  {
//---
   Print("-----------------------------   ");
   Print("DBL_MAX= ", DBL_MAX);
   Print("IntegerToString(int(DBL_MAX) )= ", IntegerToString(int(DBL_MAX) ) );
   Print("IntegerToString(uint(MathAbs(DBL_MAX) ) )= ", IntegerToString(uint(MathAbs(DBL_MAX) ) ) );
  }

Запускаю вот такой скриптик

и получаю

DBL_MAX= 1.797693134862316e+308

IntegerToString(int(DBL_MAX) )= -2147483648

IntegerToString(uint(MathAbs(DBL_MAX) ) )= 0 

------

Вопрос - а почему собственно при  переводе положительного double числа  в  int получаем отрицательное?

 
Print("-----------------------------   ");
   Print("DBL_MAX= ", DBL_MAX);
   Print("IntegerToString(int(DBL_MAX) )= ", IntegerToString(int(DBL_MAX) ) );
   Print("IntegerToString(uint(MathAbs(DBL_MAX) ) )= ", IntegerToString(uint(MathAbs(DBL_MAX) ) ) );
   Print("---");
   Print("int(DBL_MAX)= ", int(DBL_MAX) );
   Print("uint(DBL_MAX)= ", uint(DBL_MAX) );
Или так все равно тоже самое.
 
fxsaber:
Заявку оформил, хоть и задолбало это делать столь часто.
Ответили и сразу закрыли

Автор индикатора сознательно закодировал ссылку на самого себя. 

Можно либо запретить этот "хак", либо оставить на совести того кто его использует.

Пока вы первый кому такая возможность мешает пользоваться терминалом, за несколько лет.

Это сколько же может индикаторов выполняться вот так в холостую, а мы о них ни слухом, ни духом?! Контроля нет совсем.

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

1) Только специально, осознанно можно написать индикатор с указанным поведением. Кто вас заставляет писать такой код и запускать такой индикатор? Или вы запускаете чужие программы не зная их кода?

2) Вредоносность такого индикатора не больше чем многих других с менее явными логическими ошибками.

3) При перезагрузке терминала индикатор выгружается и повторно не запускается. Если вы случайно запустили такой индикатор - перегрузите терминал. И не запускайте больше.

Мне нужно было иметь возможность удалить себя (индикатор) на тот случай, если запущена хоть одна копия, пусть и с другими входными параметрами. Для этого требовалось выяснить handle самого себя. К сожалению, на тот момент еще не знал, что это невозможно в MQL в 100% случаев. Поэтому решил пойти на не очень хитрый прием.

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

Именно из этих соображений был написан столь безобидный код, который вызвал такую неоднозначную, но, очевидно, негативную реакцию разработчиков. Видите ли, так делать нельзя. Что незаконного сделал-то? Ну прочел значение своего буфера через CopyBuffer. Это незаконно?!

Пусть сообщество будет в курсе, что вот таким образом возможно создать фоновое никак не контролируемое исполнение любого кода даже на терминале без чартов. Вот такой лайфхак. А считать это багом или нет - вопрос терминологии, видимо. Понимаю так, что архитектурно изменить здесь разработчики что-либо не в состоянии. Поэтому такой гнев. По другому объяснить такую реакцию себе не могу.

Никто все равно не выскажется. Такую граблю хорошо бы в Справке отразить.

 
Если вы случайно запустили такой индикатор - перегрузите терминал. И не запускайте больше.
Это невозможно узнать. Никак!
 
Dmytro Zelenskyy:
Или так все равно тоже самое.

Тип int имеет размер 4 байта. Тип double имеет размер 8 байтов. Нельзя так делать - пытаться из 8 байтов получить 4 байта - в итоге может получится ерунда - особенно в данном случае, когда значение DBL_MAX лежит вне пределов значений int.

Если взять число double d=123456.1258 и попытаться из него получить int - тогда номер пройдёт, но всё равно, так делать нельзя.

 
Karputov Vladimir:

Тип int имеет размер 4 байта. Тип double имеет размер 8 байтов. Нельзя так делать - пытаться из 8 байтов получить 4 байта - в итоге может получится ерунда - особенно в данном случае, когда значение DBL_MAX лежит вне пределов значений int.

Если взять число double d=123456.1258 и попытаться из него получить int - тогда номер пройдёт, но всё равно, так делать нельзя.

Ок, а как корректно перевести double в int  с сохранением знака (число не важно, если уходит за пределы то ограничить пределом int)

 
Dmytro Zelenskyy:

Ок, а как корректно перевести double в int  с сохранением знака (число не важно, если уходит за пределы то ограничить пределом int)

int

Целый тип int имеет размер 4 байта (32 бита). Минимальное значение -2 147 483 648, максимальное значение 2 147 483 647. Исходя из этого, 

   int A=(int)2147483647.0;
   int B=(int)2147483646.2;
   int C=(int)2147483647.2;
   int D=(int)2147483648.0;
   Print("A: ",IntegerToString(A),", B: ",IntegerToString(B),", C: ",IntegerToString(C),", D: ",IntegerToString(D));

посмотрите что возвращается:

A: 2147483647, B: 2147483646, C: 2147483647, D: -2147483648

 

Думаю принцип понятен. 


 
Понятно. Спасибо.
 
Dmytro Zelenskyy:

Ок, а как корректно перевести double в int  с сохранением знака (число не важно, если уходит за пределы то ограничить пределом int)

Приводите к long.
 
fxsaber:
Ответили и сразу закрыли

Мне нужно было иметь возможность удалить себя (индикатор) на тот случай, если запущена хоть одна копия, пусть и с другими входными параметрами. Для этого требовалось выяснить handle самого себя. К сожалению, на тот момент еще не знал, что это невозможно в MQL в 100% случаев. Поэтому решил пойти на не очень хитрый прием.

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

Именно из этих соображений был написан столь безобидный код, который вызвал такую неоднозначную, но, очевидно, негативную реакцию разработчиков. Видите ли, так делать нельзя. Что незаконного сделал-то? Ну прочел значение своего буфера через CopyBuffer. Это незаконно?!

Нет ничего подобного на "так делать нельзя" в ответе разработчиков. Нигде не сказано, что это "незаконно".

Если вы считаете, что этот "безобидный код" вам безусловно необходим - используйте его. Только добавьте IndicatorRelease(handle)) в OnCalculate() после чтения буфера. Вы же не имеете необходимость на каждом тике проверять что это "ваш" индикатор?

Вот так индикатор решает вашу задачу и перестает быть "невидимкой":

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1

double Buffer[];

int handle=INVALID_HANDLE;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnInit()
  {
   ::SetIndexBuffer(0,Buffer,INDICATOR_DATA);
   handle=ChartIndicatorGet(0,1,ChartIndicatorName(0,1,0));
  }

#define TOSTRING(A) #A + " = " + (string)A + "\n"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   if(handle!=INVALID_HANDLE)
     {
      Buffer[rates_total-1]=MathRand();

      double BufferCopy[];

      if(CopyBuffer(handle,0,0,1,BufferCopy)>0)
         Print(TOSTRING(BufferCopy[0])+TOSTRING(Buffer[rates_total-1]));
         
      if(IndicatorRelease(handle)) 
         handle=INVALID_HANDLE;
     }

   return(rates_total);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int Reason)
  {
   if(handle!=INVALID_HANDLE)
      IndicatorRelease(handle);
   return;
  }


Пусть сообщество будет в курсе, что вот таким образом возможно создать фоновое никак не контролируемое исполнение любого кода даже на терминале без чартов. Вот такой лайфхак. А считать это багом или нет - вопрос терминологии, видимо. Понимаю так, что архитектурно изменить здесь разработчики что-либо не в состоянии. Поэтому такой гнев. По другому объяснить такую реакцию себе не могу.

Нет "гнева" в ответе сервисдеска. Есть непонимание вашей мотивации регулярно преувеличивать проблемы с которыми вы сталкиваетесь.

Разработчики в состоянии изменить. Но обычно очень осторожно относятся к предложениям "отнять и запретить" даже недокументированное поведение, если оно не является однозначно вредным. Данный "хак" довольно специфичен, но возможно кто-то им пользуется.

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

Никто все равно не выскажется. Такую граблю хорошо бы в Справке отразить.

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

На этом данный вопрос закроем. Технические подробности все обсудили, а эмоции в этой ветке лишние.