Libraries: Math Utils - page 6

 
If you need a custom function to get exactly the same shortest string as the cast (string)dbl, please use the Repr() function in the library:

string shortest_str = Repr(dbl) . 

This function was once required before MQL developers fixed the bug with string and Print() to conform to the ieee-754 standard.
 

Wish you were right and it was that simple. I wouldn't be here if it was that easy and definitely not wasting so many work hours on this.


It is true that I need to:

1. control the number of digits after decimal point

2. dynamically adjust the number of digits and make it as short as possible


My doubles come from

Tickvalue -> SYMBOL_TRADE_TICK_VALUE

TickSize  -> SYMBOL_TRADE_TICK_SIZE

and

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


Nothing strange, standard values, all good, but LotValue seems to be hard to format and show on screen.


The BIG issue is that my Doubles show as 1.000000000 but they are actually 1.000000001

(I know how doubles work, and understand that it is normal)


Print(), DoubleToString(), NormalizeDoubles() and StringFormat() basically rounds the number and the resulting number is terribly wrong; nothing worked, the desired precision was simply not achievable with build in MQL4 functions because they round the number, and 1.000000000 ended up equal to 1.1

(can't think of any circumstance where it is convenient for an application that constantly shows Prices to see a 'faked' number transformed from 1.04966 to 1.0497 but that is a discussion for another day)


That is why at first I was using a simple formula to get my desired precision

int p = 5; // desired precision

double n = 1.000000000;

double p10 = (p * 10);

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

But the thing complicates when instead of Forex, is Crypto where I need a higher precision of 9-10, and above that I was not able to remove trailing zeros, so I reached your functions.

And all this trouble because I need to output to the user as much information as possible and screen space is limited, so that is why I need to squeeze the number in a fixed space.


Your function Trunc() does the trick for 99.9% of the numbers, but there are some that fail to cooperate and need a special treatment.

I was hoping you could give a reduced formula to do it.


And now adding to my troubles the function Round(double, int) stops MT4 execution with some doubles. Can't figure out why, the double is not that big, being 100000.0000000000

It is a common number representing the value of 1 Lot for EURUSD, and if I hand write the value everything is ok, but if it comes from the math LotValue = ((TickValue / TickSize) * lot); MT4 blocks.


Such a simple task and I already spent 40+ hours on this. It is killing me!!

 
Cristian Dan Fechete #:

It is true that I need to:

1. control the number of digits after decimal point

2. dynamically adjust the number of digits and make it as short as possible


I told you 
double n = 1.000000000;
Is the same as:
double n = 1.0;

Your requirement:
decimals in the string <= specified_digits

If your only requirement is to format the number to a string as short as possible without trailing 0's (while controlling the max number of decimal digits):

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

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

string s3 = StringFormat("%.5f", number);
Choose any form of them.

Round, and NormalizeDouble will control the max decimal digits. Then, casting to string (string)dbl will get the shortest possible string without the trailing zeros. StringFormat() does the same thing, but it seems to be a little slower if called millions of times in your code.

In your case, DoubleToString() is not advised as it will pad the shorter strings < digits with trailing 0's to keep fixed number of decimal digits. That is not what you ask for. You ask for a dynamic number of decimal digits (the shortest).

Edit:
You calculate precision wrongly as
int p = 5; // desired precision
double p10 = (p * 10);

It should be calculated as:
int p = 5; // desired precision
double p10 = MathPow(10, p);

 

It seems that after 4 messages I wasn't able to make you understand my problem, and I feel terribly disappointed of my failure.

And the stylizer on this site is completely bugged, so it is very time consuming to properly write a message here

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

I can't explain why, but we must assume that 1.000000000; has a decimal other than 0 somewhere, although graphically I was not able to output it.

But the results are that:

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()

for numbers like 19.65400

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

works perfectly. And if I manually input 1.0000000; it will still work perfectly.

Just so you understand me, I use the function on more than 400 different parameters and each of them has a different value on each tick and Trunc() works perfectly.

But for:

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

it doesn't, and that is why I also included the function Round(number, digits); and it used to do the trick, and I decided to simply ask you if there was a formula to combine my function Normalize_Double_ToString() into a simpler and more optimized code.

And you answered me something very very different (I assume that it is entirely my fault for not explaining properly)

But since yesterday Round() blocks MT4, and without Round I can't properly count Significant Digits on the decimals side.

The problem seems to be the typecasting to long. If I remove it from Round(double, int); MT4 executes without problem, but then I can't figure out how a double with 6 integer digits, multiplied by 10000, reaches the limits of long.


I guess at this point my question is:

Where is the exit??


Anyway I will have to let this go, will get back to it in a few weeks.

 

Try this:

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

   return DoubleToString(n, d);
}

however, it won't do much better than the 3 shorter methods in the previous post.

Note,

I use Round() from my library, not the wrong one you posted before, or instead use:

n = NormalizeDouble(n, d);

But, I doubt what you've said that Round() has errors.
 
Cristian Dan Fechete #:

It seems that after 4 messages I wasn't able to make you understand my problem, and I feel terribly disappointed of my failure.

And the stylizer on this site is completely bugged, so it is very time consuming to properly write a message here

I can't explain why, but we must assume that 1.000000000; has a decimal other than 0 somewhere, although graphically I was not able to output it.

I am sure that I understand the cause of your problems on MT4.

The main reason that you cannot get expected results is a bug with MQL4's string(dbl) that is still not fixed on MT4.

Bug in MQL4 string() function. Wrong conversion of double -> string.

This also affects how doubles are displayed (via implicit cast to string) by Print(), Alert(), Comment(), FileWrite().

The bug was fixed on MT5, but not on MT4. see here: https://www.mql5.com/en/forum/367839/page3#comment_27477157 and the fix here: https://www.mql5.com/en/forum/367839/page5#comment_27613205

My recommendation:

if you want to dig deeper or debug your doubles as string in MT4, then always force explicit cast to string via the Repr() function from math_utils.mqh

#include "math_utils.mqh"

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   double a = 1.0000000000000002;
   Print(a);         // 1.0 (bug in implicit cast double -> string)
   Print(Repr(a));   // 1.0000000000000002

   double b = 100.00000000000003;
   Print(b);         // 100.0 (bug in implicit cast 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