Библиотеки: Math Utils - страница 6

 
Если вам нужна пользовательская функция для получения точно такой же кратчайшей строки, как и приведенная (string)dbl, воспользуйтесь функцией Repr() из библиотеки:

string shortest_str = Repr(dbl) .

Эта функция была необходима до того, как разработчики MQL исправили ошибку в string и Print() для соответствия стандарту ieee-754.
 

Хотелось бы, чтобы вы были правы и все было так просто. Если бы все было так просто, меня бы здесь не было, и я бы точно не тратил на это столько рабочих часов.


Это правда, что мне нужно:

1. контролировать количество цифр после запятой

2. динамически регулировать количество цифр и делать их как можно короче.


Мои удвоения происходят из

Tickvalue -> SYMBOL_TRADE_TICK_VALUE

TickSize -> SYMBOL_TRADE_TICK_SIZE

и

LotValue = ((TickValue / TickSize) * lot);


Ничего странного, стандартные значения, все хорошо, но LotValue, кажется, трудно отформатировать и показать на экране.


Основная проблема заключается в том, что мои удвоения отображаются как 1.000000000, но на самом деле они 1.000000001.

(Я знаю, как работают удвоения, и понимаю, что это нормально)


Print(), DoubleToString(), NormalizeDoubles() и StringFormat() в основном округляют число, и в результате получается ужасно неправильное число; ничего не помогло, желаемая точность просто недостижима с помощью встроенных функций MQL4, потому что они округляют число, и 1.000000000 в итоге оказывается равным 1.1

(не могу придумать обстоятельств, при которых приложению, постоянно показывающему цены, было бы удобно видеть "поддельное" число, преобразованное из 1.04966 в 1.0497, но это уже тема для другого дня)


Поэтому сначала я использовал простую формулу, чтобы получить желаемую точность.

int p = 5; // желаемая точность

double n = 1.000000000;

double p10 = (p * 10);

double(long(n * p10) / p10);

Но все усложнилось, когда вместо Форекса появилась Криптовалюта, где мне нужна более высокая точность 9-10, а сверх этого я не смог убрать задние нули, поэтому я обратился к вашим функциям.

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


Ваша функция Trunc() справляется с задачей для 99,9 % чисел, но есть и такие, которые не поддаются и требуют особого подхода.

Я надеялся, что вы сможете дать сокращенную формулу для этого.


А теперь к моим проблемам добавилась функция Round(double, int), которая останавливает выполнение MT4 с некоторыми двойными числами. Не могу понять почему, двойное число не такое уж и большое, 100000.0000000000.

Это обычное число, представляющее стоимость 1 лота для EURUSD, и если я пишу значение вручную, то все в порядке, но если оно приходит из математики LotValue = ((TickValue / TickSize) * lot); MT4 блокирует.


Такая простая задача, а я уже потратил на нее 40+ часов. Это убивает меня!!!

 
Cristian Dan Fechete #:

Это правда, что мне нужно:

1. контролировать количество цифр после десятичной точки

2. динамически регулировать количество цифр и делать его как можно короче


Я же говорил
double n = 1.000000000;
То же самое, что:
double n = 1.0;

Ваше требование:
десятичные цифры в строке <= указанные_цифры

Если единственное требование - отформатировать число в строку, как можно более короткую, без 0 (при этом контролируя максимальное количество десятичных цифр):

string s1 = (string) Round(number, digits);

string s2 = (string) NormalizeDouble(number, digits);

string s3 = StringFormat("%.5f", number);
Выбирайте любую форму из них.

Round и NormalizeDouble будут контролировать максимальное количество десятичных цифр. Затем, приведя к строке (string)dbl, вы получите максимально короткую строку без нулей в конце. StringFormat() делает то же самое, но кажется, что она будет немного медленнее, если вызывается миллионы раз в вашем коде.

В вашем случае не рекомендуется использовать DoubleToString(), так как она будет заполнять более короткие строки < цифрами, оставляя за ними 0, чтобы сохранить фиксированное количество десятичных цифр. Это не то, о чем вы просите. Вы просите динамическое количество десятичных цифр (самое короткое).

Редактировать:
Вы неправильно вычисляете точность
int p = 5; // желаемая точность
double p10 = (p * 10);

Это должно быть рассчитано как:
int p = 5; // желаемая точность
double p10 = MathPow(10, p);

 

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

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

double n = 1.000000000; 
should be the same as:
double n = 1.0;
but it is NOT

Я не могу объяснить почему, но мы должны предположить, что 1.000000000; имеет где-то десятичную дробь, отличную от 0, хотя графически я не смог вывести это.

Но результаты таковы:

string s1 = (string) Round(number, digits);  -> blocks MT4

string s2 = (string) NormalizeDouble(number, digits); -> returns a 'faked' string where a rounding is done on last digit

string s3 = StringFormat("%.5f", number); -> same as NormalizeDouble()

для чисел типа 19.65400

string s = (string) Trunc(number, digits);

работает идеально. И если я вручную введу 1.0000000, то все равно будет работать отлично.

Чтобы вы меня поняли, я использую функцию на более чем 400 различных параметрах, и каждый из них имеет разное значение на каждом тике, и Trunc() работает отлично.

Но для:

double lotValue = ((_TickValue / _TickSize) * lot);

это не так, и поэтому я также включил функцию Round(number, digits); и это помогло, и я решил просто спросить вас, есть ли формула, чтобы объединить мою функцию Normalize_Double_ToString() в более простой и оптимизированный код.

И вы ответили мне что-то совсем другое (я предполагаю, что это полностью моя вина в том, что я не объяснил должным образом)

Но со вчерашнего дня Round() блокирует MT4, а без Round я не могу правильно считать значащие цифры на десятичной стороне.

Проблема, похоже, заключается в приставке к long. Если я удалю его из Round(double, int); MT4 выполняется без проблем, но тогда я не могу понять, как двойное число с 6 целыми цифрами, умноженное на 10000, достигает границ long.


Думаю, на данный момент мой вопрос заключается в следующем:

Где выход?


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

 

Попробуйте это:

string Normalize_Double_ToString(double n, int d)
{
   n = Round(n, d);
   d = MathMin(d, GetDigits(n);

   return DoubleToString(n, d);
}

Однако это будет не намного лучше, чем 3 более коротких метода в предыдущем посте.

Примечание,

Я использую Round() из своей библиотеки, а не тот, который вы опубликовали ранее, или вместо него использую Round():

n = NormalizeDouble(n, d);

Но я сомневаюсь в том, что вы сказали, что Round() имеет ошибки.
 
Cristian Dan Fechete #:

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

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

Я не могу объяснить почему, но мы должны предположить, что 1.000000000; имеет где-то десятичную дробь, отличную от 0, хотя графически я не смог вывести ее.

Я уверен, что понимаю причину ваших проблем на MT4.

Основная причина, по которой вы не можете получить ожидаемые результаты, - это ошибка в MQL4 string(dbl), которая до сих пор не исправлена в MT4.

Ошибка в функции MQL4 string(). Неправильное преобразование double -> string.

Это также влияет на то, как двойные значения отображаются (через неявное приведение к строке) в функциях Print(), Alert(), Comment(), FileWrite().

Ошибка была исправлена на MT5, но не на MT4. см. здесь: https: //www.mql5.com/en/forum/367839/page3#comment_27477157 и исправление здесь: https: //www.mql5.com/en/forum/367839/page5#comment_27613205.

Моя рекомендация:

если вы хотите копнуть глубже или отладить работу с дублями как строками в MT4, то всегда принудительно приводите их к строкам через функцию Repr() из math_utils.mqh

#include "math_utils.mqh"

//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnStart()
  {
   double a = 1.0000000000000002;
   Print(a);         // 1.0 (ошибка в неявном приведении double -> string)
   Print(Repr(a));   // 1.0000000000000002

   double b = 100.00000000000003;
   Print(b);         // 100.0 (ошибка в неявном приведении double -> string)
   Print(Repr(b));   // 100.00000000000003
  }
MT5/mql5 reported and confirmed bugs. - Custom ZERO Level Showing ZERO level, bug in MML. String(MQ)
MT5/mql5 reported and confirmed bugs. - Custom ZERO Level Showing ZERO level, bug in MML. String(MQ)
  • 2022.02.01
  • Alain Verleyen
  • www.mql5.com
On indicators, mt5 can set automatically a level "0" depending of the buffer values. Custom indicator showing zero level, though not defined anywhere in the code. Wrong conversion of double -> string. Then test the same example in your browser js pad or any online javascript pad and check the difference