:) ... Осторожно ! Ошибки в МТ ( достало - Проложение II ) Уже смешно. :) - страница 2

 
Scriptong:

Да вроде в цикле...

Ведь в самом цикле есть еще одна открывающая скобка:

if ( i3 != 0 ){

Верно, признаюсь в своей невнимательности. Теперь понятен смысл этого цикла. Как бы еще понять смысл всего кода в целом?

 

Ну ведь сказано же - сделайте скрипт и удивитесь. :)

Только вот что-то никто не удивляется...

 

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

int start() {
  int fH = FileOpen("etest.log", FILE_WRITE|FILE_CSV, "\t");  
  double dbl_i; int int_i_right, int_i_wrong; 
  string msg[2] = {"", "ОШИБКА!"}; int is_error;
  
  for (double d=0.0; d<=1.0; d+=Point){                
    dbl_i = d/Point;      
    int_i_wrong = dbl_i; //НЕПРАВИЛЬНО!!!
      // Реально dbl_i представляет собой не целое число,
      // а, например, число вида 7,999999999999 (там, где казалось бы должно быть ровно 8).
      // При присвоении переменной типа int значения переменной типа double
      // отбрасывается дробная часть и в данном примере int_i_wrong будет равно 7.
      // Возможен и случай, когда число представлено в виде 8,000000000001,
      // в таких случаях int_i_wrong как и ожидалось будет равен 8.
    int_i_right = MathRound(dbl_i); 
      // Чтобы получать 8 в обоих случаях - надо округлять значение типа double
    is_error = (int_i_right != int_i_wrong);
    FileWrite(fH, d, int_i_right, int_i_wrong, msg[is_error]);      
  }
  
  FileClose(fH);
  return(0);
}

На Delphi в таком случае (int_i_wrong = dbl_i) компилятор вообще выдаст ошибку:

[Error] Project1.dpr(17): Incompatible types: 'Integer' and 'Extended'

Может стоит сделать также в MQL5, чтобы избежать подобных ситуаций?

В примере автора ошибочный результат получится намного больше раз, чем 200 из 17000: для вычисления i2 используется значение i (уже неверное). i3 равно 0, но i и i2 - оба на единицу меньше :)

Кстати, вопрос разработчикам:

Почему для функций MathCeil, MathFloor, MathRound в справочнике указан тип возвращаемого значения double? Ведь тогда округление с помощью MathRound не решало бы проблему?

 
Дабл приведется к инту и округлится, это же очевидно.
 
Ritter:

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

int start() {
  int fH = FileOpen("etest.log", FILE_WRITE|FILE_CSV, "\t");  
  double dbl_i; int int_i_right, int_i_wrong; 
  string msg[2] = {"", "ОШИБКА!"}; int is_error;
  
  for (double d=0.0; d<=1.0; d+=Point){                
    dbl_i = d/Point;      
    int_i_wrong = dbl_i; //НЕПРАВИЛЬНО!!!
      // Реально dbl_i представляет собой не целое число,
      // а, например, число вида 7,999999999999 (там, где казалось бы должно быть ровно 8).
      // При присвоении переменной типа int значения переменной типа double
      // отбрасывается дробная часть и в данном примере int_i_wrong будет равно 7.
      // Возможен и случай, когда число представлено в виде 8,000000000001,
      // в таких случаях int_i_wrong как и ожидалось будет равен 8.
    int_i_right = MathRound(dbl_i); 
      // Чтобы получать 8 в обоих случаях - надо округлять значение типа double
    is_error = (int_i_right != int_i_wrong);
    FileWrite(fH, d, int_i_right, int_i_wrong, msg[is_error]);      
  }
  
  FileClose(fH);
  return(0);
}

На Delphi в таком случае (int_i_wrong = dbl_i) компилятор вообще выдаст ошибку:

[Error] Project1.dpr(17): Incompatible types: 'Integer' and 'Extended'

Может стоит сделать также в MQL5, чтобы избежать подобных ситуаций?

В примере автора ошибочный результат получится намного больше раз, чем 200 из 17000: для вычисления i2 используется значение i (уже неверное). i3 равно 0, но i и i2 - оба на единицу меньше :)

Кстати, вопрос разработчикам:

Почему для функций MathCeil, MathFloor, MathRound в справочнике указан тип возвращаемого значения double? Ведь тогда округление с помощью MathRound не решало бы проблему?

Нда! Что-то тупит народ... Обьясняю. Мне плевать на отбрасывания дробной части. Мне и надо было присвоить только целую часть.

int i;

i=1.2;

БУДЕТ один. Это очевидно. И нормально.

:))) Но когда i=1.2*10;

равно 11 это бред.

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

i=1.346599999 * 1000;

Сколько будет? Правильно, 13465.99999.... И мне плевать на эти 0.99999 пусть они пропадут. Но ведь в результате мы имеем 1.3593*1000 равным 13592

Надеюсь теперь понятнее

1.3593 * 1000 равно 13592 а должно быть 13593....

А вы говорите про то что 1.35927777 * 1000 равно видите ли 13592 а не 13592.77777 да наплевать :-)) на эти мелкие семерки...

 
MProgrammer:
Ritter:

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

int start() {
  int fH = FileOpen("etest.log", FILE_WRITE|FILE_CSV, "\t");  
  double dbl_i; int int_i_right, int_i_wrong; 
  string msg[2] = {"", "ОШИБКА!"}; int is_error;
  
  for (double d=0.0; d<=1.0; d+=Point){                
    dbl_i = d/Point;      
    int_i_wrong = dbl_i; //НЕПРАВИЛЬНО!!!
      // Реально dbl_i представляет собой не целое число,
      // а, например, число вида 7,999999999999 (там, где казалось бы должно быть ровно 8).
      // При присвоении переменной типа int значения переменной типа double
      // отбрасывается дробная часть и в данном примере int_i_wrong будет равно 7.
      // Возможен и случай, когда число представлено в виде 8,000000000001,
      // в таких случаях int_i_wrong как и ожидалось будет равен 8.
    int_i_right = MathRound(dbl_i); 
      // Чтобы получать 8 в обоих случаях - надо округлять значение типа double
    is_error = (int_i_right != int_i_wrong);
    FileWrite(fH, d, int_i_right, int_i_wrong, msg[is_error]);      
  }
  
  FileClose(fH);
  return(0);
}

На Delphi в таком случае (int_i_wrong = dbl_i) компилятор вообще выдаст ошибку:

[Error] Project1.dpr(17): Incompatible types: 'Integer' and 'Extended'

Может стоит сделать также в MQL5, чтобы избежать подобных ситуаций?

В примере автора ошибочный результат получится намного больше раз, чем 200 из 17000: для вычисления i2 используется значение i (уже неверное). i3 равно 0, но i и i2 - оба на единицу меньше :)

Кстати, вопрос разработчикам:

Почему для функций MathCeil, MathFloor, MathRound в справочнике указан тип возвращаемого значения double? Ведь тогда округление с помощью MathRound не решало бы проблему?

Нда! Что-то тупит народ... Обьясняю. Мне плевать на отбрасывания дробной части. Мне и надо было присвоить только целую часть.

int i;

i=1.2;

БУДЕТ один. Это очевидно. И нормально.

:))) Но когда i=1.2*10;

равно 11 это бред.

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

i=1.346599999 * 1000;

Сколько будет? Правильно, 13465.99999.... И мне плевать на эти 0.99999 пусть они пропадут. Но ведь в результате мы имеем 1.3593*1000 равным 13592

Надеюсь теперь понятнее

1.3593 * 1000 равно 13592 а должно быть 13593....

А вы говорите про то что 1.35927777 * 1000 равно видите ли 13592 а не 13592.77777 да наплевать :-)) на эти мелкие семерки...



По поводу ошибок округления уже было:

https://forum.mql4.com/ru/10632

 
MProgrammer:

Нда! Что-то тупит народ... Обьясняю. Мне плевать на отбрасывания дробной части. Мне и надо было присвоить только целую часть.

int i;

i=1.2;

БУДЕТ один. Это очевидно. И нормально.

:))) Но когда i=1.2*10;

равно 11 это бред.

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

i=1.346599999 * 1000;

Сколько будет? Правильно, 13465.99999.... И мне плевать на эти 0.99999 пусть они пропадут. Но ведь в результате мы имеем 1.3593*1000 равным 13592

Надеюсь теперь понятнее

1.3593 * 1000 равно 13592 а должно быть 13593....

А вы говорите про то что 1.35927777 * 1000 равно видите ли 13592 а не 13592.77777 да наплевать :-)) на эти мелкие семерки...

Да не стоит так разоряться-то.

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

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

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

Если в MQL4 принята концепция, которая не устраивает какого-то конкретного программиста, то это не значит, что концепция ошибочна.

А значит, что программист привык к другим правилам, поэтому фактическое положение дел не отвечает его ожиданиям.

--

Сами правила в MQL4 довольно просты и очевидны.

1. В процессе вычисления выражения, содержащего значения разных типов, выражение приводится к типу с бОльшим приоритетом.

2. При выполнении операции присваивания происходит приведение к целевому типу.

d1 = 1.2;

d2 = 10;

i = d1*d2;

Порядок такой:

1. Вычисление выражения в правой части от знака равенства. 1.2*10 = ?

1.1. В обычной школьной арифметике это было бы просто = 12.

1.2. В программировании перемножение действительных чисел сопровождается наличием некоторой ошибки.

Вариант 12а. = 11.99999999

Вариант 12b. = 12.00000001

С точки зрения практики программирования оба варианта допустимы и вероятны.

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

Вариант 12а даст конечный результат i = 11, т.к. при преобразовании в целое дробная часть просто отбрасывается.

Вариант 12b даст конечный результат i = 12 по той же причине.

Что должен сделать программист, чтобы избежать подобной ошибки? Использовать функцию NormalizeDouble().

А именно, составить программную строку так:

int i = NormalizeDouble( d1*d2).

При исполнении такого кода результат всегда будт соответствовать ожидаемому, а именно, =12.

Вот и всё :)

 
MProgrammer:

мы имеем 1.3593*1000 равным 13592

Надеюсь теперь понятнее

1.3593 * 1000 равно 13592 а должно быть 13593....

Все-таки умножать наверно планировалось на 10000?))

В этом конкретном случае получится, как и ожидалось 13593

Но, например, если разделить int i = 0.0024/0.0001 получится 23, хотя кажется что должно быть 24. Потому что полученные при делении 23.999999... округлятся вниз до 23 (если не применять MathRound или NormalizeDouble). Поэтому я и написал, что в твоем первом примере уже i в отдельных случаях считается неверно...

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

Почему для функций MathCeil, MathFloor, MathRound в справочнике указан тип возвращаемого значения double?

Вот что написано в учебнике Сергея Ковалева:

Обратите внимание, значение, возвращаемое функцией, является действительным числом (типа double), в то же время в назначении функции указано, что функция возвращает целое число. Это нужно понимать так, что функция возвращает действительное число, у которого во всех разрядах после разделительной точки указаны нули. Например, функция MathFloor() может вернуть 37.0 (положительное число типа double) или -4.0 (отрицательное число типа double).

 
Чё вы впрариваете MProgrammer'у !? Он сам все знает и умеет! Он же профессиональный программист, разве вам это не известно?
 
Ritter:

Вот что написано в учебнике Сергея Ковалева:

Обратите внимание, значение, возвращаемое функцией, является действительным числом (типа double), в то же время в назначении функции указано, что функция возвращает целое число. Это нужно понимать так, что функция возвращает действительное число, у которого во всех разрядах после разделительной точки указаны нули. Например, функция MathFloor() может вернуть 37.0 (положительное число типа double) или -4.0 (отрицательное число типа double).

Вы по моему не понимаете сути того что я говорю.... Вернее не понимаете что проблема не в том, что что-то как-то отбрасыаетеся из-за того что не 1 а 0.999999999999999999... В языке программирования так быть не должно. Вы видимо тоже не очень четко понимаете, что ошибка в нашем случае 0.9999999999999999 не 0.000000000000001 а "1"!!!!! .... Это очень много!

Зачем мне плавающая точка с высокой точностью в финнансовых расчетах. Разработчики явно схалтурили. И просто присобачили сюда дабл, который тут нужен как зайцу спички. Вместо того, чтобы сделать нормальную нецелочисленную арифметику... И ведь все просто, надо было просто хранить инт и степень ... И все, и небыло бы подобных ошибок ... Либо просто использоали бы упакованную двоично-десятичную арифметику...

Вы не понимаете, что если ты работаешь в даблах то в них надо делать все. Только даблы. Но цена она по сути не дабл она инт!!! Вот чего вы не понимаете.

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

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

Пока!