trying to get the number of decimal digits from a number (not a symbol)

To add comments, please log in or register
Sujana Lius
16
Sujana Lius  

Hi,

I'm trying to get the number of decimal digits from a number.

for example

0.1234 ---> 4

0.465 ---> 3

0.51 ---> 2 

 So far, I can only a similar function from this function

MarketInfo(Symbol(),MODE_DIGITS);

But that doesn't really help me. I need to get the number of decimal digits which I get from

MarketInfo(Symbol(),MODE_LOTSTEP);

So if I get '0.01' the output will be '2'

Any suggestion will be greatly appreciated. 

Thank you in advance

William Roeder
20207
William Roeder  
sliu152: I'm trying to get the number of decimal digits from a number.
  1. Try:
    Not compiled, not tested.
    #define LOTS double
    string   lots_as_string(LOTS lots){   
       static int  lotDigits = EMPTY;   if(EMPTY == lotDigits)
          lotDigits   = digits_in(MarketInfo(_Symbol, MODE_LOTSTEP) );   
       return DoubleToStr(lots, lotDigits);
    }
    int digits_in(double d){
       int digits = 0;
       while(d - int(d) > 1.E-8){
          d *= 10.0; ++digits;
       }
      return digits;
    }
    Not compiled, not tested.
  2. If you just want to print a number without trailing zeros:
    string  to_variable(double value){
       return StringFormat("%g", value);
    }
Marcel Fitzner
319
Marcel Fitzner  

Sadly, the digits_in method cannot be used readily for doubles as they occur during runtime.

For debugging purposes I have rewritten the code like this:

int DigitsIn(double d){
        double tempDouble = d;
        
        if (tempDouble > 1.0)
                tempDouble -= int(tempDouble);

        int digits = 0;
        double subtract = tempDouble - int(tempDouble);
        
        while(subtract > 1.E-8)
        {
                tempDouble *= 10.0;
                subtract = tempDouble - int(tempDouble);
                ++digits;
        }
        return digits;
}

If you have an incoming double value that is e.g. "1.11544" you need to first reduce it it so the double becomes "0.11544"

But during debugging the incoming double has an actual representation of: "0.115439999999999987" which leads to an endless loop of that code.

Not sure if this can be solved in an elegant way, other than managing the number of digits manually?

lippmaje
1032
lippmaje  

This is what I use. There's a maximum of 8 to keep it at a reasonable level.

int CountDigits(double val)
  {
   int digits=0;
   while(NormalizeDouble(val,digits)!=NormalizeDouble(val,8)) digits++;
   return digits;
  }

Probably a bit more time consuming than calculating the remainder.

JC
1646
JC  
lippmaje:

Probably a bit more time consuming than calculating the remainder.

This becomes an interesting illustration of interpreted versus compiled languages. In MQL4 (interpreted), the following function is - to my surprise - slightly faster on average than the use of NormalizeDouble():

int CountDigits(double val)
{
   // If precision can be reduced, e.g. to 6, then the function 
   // becomes slightly faster on average.
   int precision = 8;

   val = MathAbs(val);
   string x = DoubleToString(val - MathFloor(val), precision);
   int pos = StringFind(x, "0", 2);
   return (pos > 0 ? pos - 2 : precision);
}

But in MQL5 (compiled), this processing via string conversion is massively slower than the use of NormalizeDouble(). 

Marcel Fitzner
319
Marcel Fitzner  

Works like a charm @lippmaje - thanks for sharing!

A small recommendation here: If you improve the signature it allows some client code to adjust the precision - if necessary:

int CountDigits(double val, int maxPrecision = 8)
{
        int digits = 0;
        while(NormalizeDouble(val,digits) != NormalizeDouble(val, maxPrecision))
                digits++;
        return digits;
}

JC: Thanks for measuring the computational time! Good to know that NormalizeDouble doesn't perform too bad in MQL5.

lippmaje
1032
lippmaje  

@JC @Marcel, great.

We could write it like this to make it a tad faster:

int CountDigits(double val, int maxPrecision = 8)
  {
   int digits = -1;
   double maxp = NormalizeDouble(val, maxPrecision);
   while(NormalizeDouble(val, ++digits) != maxp);
   return digits;
  }
Alain Verleyen
38646
Alain Verleyen  
Sujana Lius:

Hi,

I'm trying to get the number of decimal digits from a number.

for example

0.1234 ---> 4

0.465 ---> 3

0.51 ---> 2 

 So far, I can only a similar function from this function

But that doesn't really help me. I need to get the number of decimal digits which I get from

So if I get '0.01' the output will be '2'

What to do ?

https://www.mql5.com/en/forum/192896#comment_5113218

Alain Verleyen
38646
Alain Verleyen  
JC:

This becomes an interesting illustration of interpreted versus compiled languages. In MQL4 (interpreted), the following function is - to my surprise - slightly faster on average than the use of NormalizeDouble():

But in MQL5 (compiled), this processing via string conversion is massively slower than the use of NormalizeDouble(). 

What allow you to say mql4 is interpreted ? As far as I know since build 600, it's compiled like mql5.
JC
1646
JC  
Alain Verleyen:
What allow you to say mql4 is interpreted ? As far as I know since build 600, it's compiled like mql5.

It's more of a continuum than a pair of binary categories, but if MQL4 is truly "compiled" then it's clearly a different class of compilation to MQL5.

  1. .ex4 files are much smaller than the .ex5 equivalents
  2. MetaEditor builds/compiles .ex4 much faster than .ex5, suggesting that it's doing much more complex work with MQL5.
  3. The compiler is much cleverer in MQL5.

As an example of 3, take the following function which I initially used to compare speeds between MQL4 and MQL5:

   int res;
   double y = 1.11354;
   for (int i = 0; i < 1000000; i++) {
      res = CountDigits(y);
   }

In MQL5, the timings clearly indicate that the compiler collapses this into a single call rather than 1,000,000 iterations of the loop. It is clearly detecting that the calculation inside the loop is constant, and only runs it once. But in MQL4 it does run the loop 1,000,000 times.

If you add the following line inside the loop...

   y += 0.00001;

... then it makes, as expected, almost no difference to the speed of the MQL4 code, but does massively increase the time taken by the MQL5 code - because it's now presumably doing 1,000,000 loop iterations rather than 1. 

Similarly, lippmaje's CountDigits() function is so much faster on MQL5 than MQL4 that it looks very much like the difference between native code vs p-code.

Alain Verleyen
38646
Alain Verleyen  
JC:

It's more of a continuum than a pair of binary categories, but if MQL4 is truly "compiled" then it's clearly a different class of compilation to MQL5.

  1. .ex4 files are much smaller than the .ex5 equivalents
  2. MetaEditor builds/compiles .ex4 much faster than .ex5, suggesting that it's doing much more complex work with MQL5.
  3. The compiler is much cleverer in MQL5.

As an example of 3, take the following function which I initially used to compare speeds between MQL4 and MQL5:

In MQL5, the timings clearly indicate that the compiler collapses this into a single call rather than 1,000,000 iterations of the loop. It is clearly detecting that the calculation inside the loop is constant, and only runs it once. But in MQL4 it does run the loop 1,000,000 times.

If you add the following line inside the loop...

... then it makes, as expected, almost no difference to the speed of the MQL4 code, but does massively increase the time taken by the MQL5 code - because it's now presumably doing 1,000,000 loop iterations rather than 1. 

Similarly, lippmaje's CountDigits() function is so much faster on MQL5 than MQL4 that it looks very much like the difference between native code vs p-code.

Ok thanks for your answer, I will not argue as anyway we will never know what is really behind the scene.

By the way, mql5 compiler optimizations can be disabled.

To add comments, please log in or register