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

 
sergeev:
пользуйтесь классами.

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

Вот так получилось:

struct Buff { double b[]; };
//---
Buff lbuff[];
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   int i=2,j=1000;
//---
   ArrayResize(lbuff,i);
   ArrayResize(lbuff[0].b,j);
   ArrayResize(lbuff[1].b,j);
  }
Rosh:
Посмотрите в разделе Перегрузка операций пример для класса CMatrix, возможно, это Вам это поодойдет.
Спасибо, буду изучать.
 
Rosh:

Дело в том, что вещественное число хранится в памяти с не более чем 17 значащих цифр.

Попробуйте такой пример, чтобы почувствовать разницу:

Описание в справке поправим.

Да, Ренат уж пояснил выше, что Print() выводит данные типа  double  с точностью до 4, а не до 16 десятичных цифр после точки. В этом и была вся загвоздка с точки зрения пользователя.

 
Yedelkin:

Да, Ренат уж пояснил выше, что Print() выводит данные типа  double  с точностью до 4, а не до 16 десятичных цифр после точки. В этом и была вся загвоздка с точки зрения пользователя.

Нет, Print() выводит в формате %.16G, это означает, что будет сделана попытка вывести число с точкой и 16 значимых цифр. В данном случае хранится число 199.99999999999997, у которого 17 значимых чисел (3 цифры перед запятой + 14 после запятой). При попыке вывести 16 цифр начинаетя округление , 7 округляется до 10, единица переходит к более старшему разряду, а там 9.  И начинается принцип домино - выводимое число округляется до 200.

Вот попробуйте пример:

void OnStart()
  {
   double a,b;

   a=7.0/200.0;
   b=7.0/a;
   Print("Print(b)=",b);
   Print("Print(DoubleToString(b,16))=",DoubleToString(b,16));
   double epsilon=MathPow(10,-13);
   Print("-------- После вычитания ",epsilon,"---------");
   b=b-epsilon;
   Print("Print(b)=",b);
   Print("Print(DoubleToString(b,16))=",DoubleToString(b,16));

   
  }

Посмотрите PrintFormat().

 
Rosh:

Нет, Print() выводит в формате %.16G, это означает, что будет сделана попытка вывести число с точкой и 16 значимых цифр. В данном случае хранится число 199.99999999999997, у которого 17 значимых чисел (3 цифры перед запятой + 14 после запятой). При попыке вывести 16 цифр начинаетя округление , 7 округляется до 10, единица переходит к более старшему разряду, а там 9.  И начинается принцип домино - выводимое число округляется до 200.

Посмотрите PrintFormat().

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

...Но если  вещественное   число хранится в памяти с не более чем 17 значащих цифрами (в нашем случае - число 199.99999999999997), то откуда появляются значащие разряды при таком обращении:

MP 0 victorg2 (EURUSD,M1) 11:04:42 Print(DoubleToString(b,16))=199.9999999999999716 

? (Насчитал 19 разрядов)
 

"В боевых условиях число пи может достигать четырёх"

DoubleToString работает несколько иначе, чем форматирование в принте (там оно отдано на откуп CRT)

В DoubleToString целая и дробная части отдельно преобразовываются в строки и по несколько более быстрому алгоритму, чем стандартное форматирование.

Документация по MQL5: Основы языка / Типы данных / Вещественные типы (double, float)
Документация по MQL5: Основы языка / Типы данных / Вещественные типы (double, float)
  • www.mql5.com
Основы языка / Типы данных / Вещественные типы (double, float) - Документация по MQL5
 
stringo:

В DoubleToString целая и дробная части отдельно преобразовываются в строки и по несколько более быстрому алгоритму, чем стандартное форматирование.

Но тогда получается, что хранится в памяти несколько больше, чем 17 значащих цифр. Иначе откуда взяться целой и дробной   части для преобразований в строки? Т.е независимо, Print() это или DoubleToString(), откуда-то они берут свои данные (если уж речь зашла именно о хранении "в памяти с не более чем 17 значащих цифрами").

...Может, конечно, я зацепился за фразу "хранение в памяти", и не совсем верно её понимаю в силу незнания природы хранения вещественных чисел.

 
Yedelkin:

Но тогда получается, что хранится в памяти несколько больше, чем 17 значащих цифр. Иначе откуда взяться целой и дробной   части для преобразований в строки? Т.е независимо, Print() это или DoubleToString(), откуда-то они берут свои данные (если уж речь зашла именно о хранении "в памяти с не более чем 17 значащих цифрами").

...Может, конечно, я зацепился за фразу "хранение в памяти", и не совсем верно её понимаю в силу незнания природы хранения вещественных чисел.

Бывает, что хранится и до 20 значащих цифр, но негарантированно. И вообще, чем больше число в целой части, тем менее оно точно в дробной части.

Зачем Вам 16 знаков после запятой? Академический интерес?

Документация по MQL5: Основы языка / Типы данных / Вещественные типы (double, float)
Документация по MQL5: Основы языка / Типы данных / Вещественные типы (double, float)
  • www.mql5.com
Основы языка / Типы данных / Вещественные типы (double, float) - Документация по MQL5
 
stringo:

Бывает, что хранится и до 20 значащих цифр, но негарантированно. И вообще, чем больше число в целой части, тем менее оно точно в дробной части.

Зачем Вам 16 знаков после запятой? Академический интерес?

:) Чтобы не играть в испорченный телефон, посмотрим предысторию.

Вот здесь victorg задал вопрос, касающийся работы функции Print() и выдаваемых ею неожиданных для него значений

Вот здесь я ему показал, в чём причина.

Поскольку косяками функции Print() он не хотел заниматься,  

я взял на себя наглость и указал, что  в описании функции Print() сказано, что "Данные типа  double выводятся с точностью до 16 десятичных цифр после точки". На самом деле оказалось, что функция Print() выводит несколько округлённые данные, с приложением конкретного примера.

Потом пошло бурное обсуждение, в итоге пример мой никто опровергнуть не смог, а Ренат изложил первую версию и сообщил, что справочник скорректируют

Через несколько дней Рош высказал вторую версию, где и появилось упоминание про число 17. Здесь он продолжил.

Подключившись к обсуждению, Вы предложили третью версию, а именно: "В DoubleToString целая и дробная  части отдельно преобразовываются в строки и по несколько более быстрому алгоритму, чем стандартное форматирование" Т.е. дело уже оказалось в скорости алгоритмов.

Тогда я обратил Ваше внимание, что, в общем-то, речь шла о размере хранимого числа из второй версии Роша.

stringo:

Зачем Вам 16 знаков после запятой? Академический интерес?

 Теперь можно ответить на эти вопросы. Я привёл пример, когда функция Принт() выводит округлённые данные.  О причинах такого поведения - не спрашивал. Пример мой не опровергли, просто посоветовали пользоваться другой функцией и стали объяснять причины. Среди этих объяснений и появилось упоминание про 16(17) знаков после запятой.  Посколько в этих объяснениях мне было не всё понятно, задавал вопросы "по ходу". - Так что это даже не академический интерес с моей стороны, а просто стремление понять, каую же мысль до меня пытались донести.

 
Yedelkin:

. . . Так что это даже не академический интерес с моей стороны, а просто стремление понять, каую же мысль до меня пытались донести.

Полностью согласен. Академический интерес тут совершенно не причем.

Читаем в документации "вещественное число". Стандарт IEEE 754, в таблице для double – 15 значащих цифр. С учетом этого уже набралось четыре варианта – 15, 16, 17 значащих цифр и вариант когда целая часть и дробная хранятся отдельно. Но ведь так не бывает! При чем здесь академический интерес? Тут скорее элементарная формальная логика, на которой, кстати, и базируется данный язык программирования.

Мне кажется, что программист должен писать программы, а не исследовать компилятор.

PS

Пользуясь случаем, хочу уточнить:

Если увеличить размер динамического массива функцией ArrayResize(), то будут ли гарантированно сохранены ранее размещенные в нем данные? Наверное, этот момент нужно однозначно отразить в документации (в описании функции ArrayResize()).  Если кто знает, подскажите, пожалуйста.

 
victorg:

Если увеличить размер динамического массива функцией ArrayResize(), то будут ли гарантированно сохранены ранее размещенные в нем данные? Наверное, этот момент нужно однозначно отразить в документации (в описании функции ArrayResize()).  Если кто знает, подскажите, пожалуйста.

Будут при увеличении размера, иначе нет смысла в такой функции.