MT5/mql5 reported and confirmed bugs. - page 3

 

Build 3180 but this is not specific to this build, it's an old one.

On indicators, MT5 can set automatically a level "0" depending of the buffer values. There is no way to disable this behaviour or to customize the level line drawing.

Forum on trading, automated trading systems and testing trading strategies

Custom Indicator showing ZERO level, though not defined anywhere in the code

Alain Verleyen, 2022.01.27 17:56

Actually it's buggy, as this automatic 0 line doesn't respect what is defined in the code (style, color...).



 
Comments that do not relate to this topic, have been moved to "Off Topic Posts".
 

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

Build 3182 but this is not specific to this build, it's an old one.

A bug is found in string() function where wrong conversion of double -> string.

If you convert an arbitrary double-precision floating-point number to a decimal string, and then convert that back to floating-point, you should recover the original floating-point number. In other words, the conversion will round-trip.

The string() function may return wrong string representation of double numbers that cannot round-trip into the same numeric value.

This also affects any implicit cast inside Print(), Alert(), Comment(), FileWrite().

This a sample script to reproduce the bug:

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   int fails = 0;
   int count = 1000;

   for(int i = 0; i < count && !IsStopped(); i++)
     {
      double number = (MathRand() / 32768.0) * (1 + DBL_EPSILON);

      // Bug in string() function. wrong conversion of double -> string.
      string str = (string)number;

      // If the original number cannot be recovered, this confirms the bug.
      if(number != StringToDouble(str))
         fails++;
     }

   printf("Tested %d values", count);
   printf("MQL5 string() conversion failures: %d", fails);

  }
//+------------------------------------------------------------------+

// Sample output:
// Tested 1000 values
// MQL5 string() conversion failures: 366

 
amrali #:

If you convert an arbitrary double-precision floating-point number to a decimal string, and then convert that back to floating-point, you should recover the original floating-point number. In other words, the conversion will round-trip.

This is an incorrect statement. The following expression is not an identity.

(double)(string)Num == Num;
 
amrali #:

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

Build 3182 but this is not specific to this build, it's an old one.

A bug is found in string() function where wrong conversion of double -> string.

If you convert an arbitrary double-precision floating-point number to a decimal string, and then convert that back to floating-point, you should recover the original floating-point number. In other words, the conversion will round-trip.

The string() function may return wrong string representation of double numbers that cannot round-trip into the same numeric value.

This also affects any implicit cast inside Print(), Alert(), Comment(), FileWrite().

This a sample script to reproduce the bug:

That's not a bug. There are some rounding to 15/16 digits when converting to string, which is mandatory.
 
amrali #: Bug in MQL string() function. Wrong conversion of double -> string

Build 3182 but this is not specific to this build, it's an old one. A bug is found in string() function where wrong conversion of double -> string.

If you convert an arbitrary double-precision floating-point number to a decimal string, and then convert that back to floating-point, you should recover the original floating-point number. In other words, the conversion will round-trip.

The string() function may return wrong string representation of double numbers that cannot round-trip into the same numeric value. This also affects any implicit cast inside Print(), Alert(), Comment(), FileWrite().

This a sample script to reproduce the bug:

The maximum precision that DoubleToString supports is 16 digits, but a double has much more than that. So there is no guarantee the the round-trip conversion will return to the original. Also, given that some numbers can actually have a recurring pattern after the decimal point, there will never be a string conversion that can guarantee a round-trip conversion to the original.

So, it's not a bug but a simple limitation of the conversion function between something that is represented in base 2 and another that a representation of base 10.

 
fxsaber #:

This is an incorrect statement. The following expression is not an identity.

In JavaScript: Number.toString()  --> round-trips

In Python: Repr()  --> round-trips

In C #: Double.ToString("R")  --> round-trips

In C: printf("%.17g", str) --> round-trips

Recently, this identity became a rule that should be fulfilled in major programming languages, as a trade-off between readibility and correctness.

I posted before Repr() function which adopts a shortest round-trip conversion, with similar results to David M. Gay's dtoa.c library (Dragon4).

How to Print Floating-Point Numbers Accurately (1990) https://lists.nongnu.org/archive/html/gcl-devel/2012-10/pdfkieTlklRzN.pdf 

Test this in mql

void OnStart(void)
  {
      double a = 0.1 + 0.2;
      Print(a);
      Print(a == StringToDouble(string(a)));
  }

Then test the same example in your browser js pad or any online javascript pad and check the difference.

 
Правильный.
void OnStart()
{
  double Num = 1.0 / 7 ;
  double Num2 = (string)(double)(string)Num;
  
  Print((double)(string)Num == Num); // false
  Print((double)(string)Num2 == Num2); // true
}
 
amrali #:

In JavaScript: Number.toString()  --> round-trips

In Python: Repr()  --> round-trips

In C #: Double.ToString("R")  --> round-trips

In C: printf("%.17g", str) --> round-trips

Recently, this identity became a rule that should be fulfilled in major programming languages, as a trade-off between readibility and correctness.

I posted before Repr() function which adopts a shortest round-trip conversion, with similar results to David M. Gay's dtoa.c library (Dragon4).

Please pay attention to what was stated. The MQL5 function has a limitation of 16 digits, but a double has more precision. Round-trip is not guaranteed.

Even in the other languages with more precision, there are still numbers that will fail if they have a repeating pattern when converted from binary to decimal.

 

Binary-to-decimal conversion with minimal number of digits

Converting a double-precision binary floating-point number to a decimal string is a common operation,

but an algorithm producing results that are both accurate and minimal did not appear in print until
1990, with Steele and White's Dragon4. Some of the improvements since then include:

 - David M. Gay's dtoa.c, a practical open-source implementation of many ideas in Dragon4.

 - Grisu3, with a 4x speedup as it removes the use of bignums. Must be used with a fallback, as it fails for ~0.5% of cases.

 - Errol3, a complete algorithm similar to, but slower than, Grisu3.

 - Ryu, a complete algorithm that is faster and simpler than Grisu3.

Many modern language runtimes use Grisu3 with a Dragon4 fallback.


MQL5 implements a bad historic algorithm for conversion double -> str. That is why the forum is full of questions about floating point numbers weirdness.

Here is a proof of my point of view that it is as bug in the implementaion

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   int fails = 0;
   int count = 1000;

   for(int i = 0; i < count && !IsStopped(); i++)
     {
      double number = (MathRand() / 32768.0) * (1 + DBL_EPSILON);

      // Bug in string() function. wrong conversion of double -> string.
      //string str = (string)number;

      // Correct conversion
      string str = Repr(number);

      // If the original number cannot be recovered, this confirms the bug.
      if(number != StringToDouble(str))
         fails++;
     }

   printf("Tested %d values", count);
   printf("MQL5 string() conversion failures: %d", fails);

  }
//+------------------------------------------------------------------+

// Sample output:
// Tested 1000 values
// MQL5 string() conversion failures: 0


//+------------------------------------------------------------------+
//| Converting numeric value into the shortest string representation |
//| that round-trips into the same numeric value. The result can     |
//| contain up to 17 significant digits, discarding trailing zeros.  |
//| The round-trip ("%.17g") format specifier ensures that a numeric |
//| value converted to a string is always parsed back into the same  |
//| numeric value, StringToDouble(Repr(f)) == f.                     |
//| Note: results are consistent with David M. Gay's dtoa.c library. |
//+------------------------------------------------------------------+
// toString()
string Repr(double value)
  {
   string repr = "";
//--- First format with 15 spaces of precision. If round-trip fails,
//--- format with 16 or 17 spaces of precision.
   if(value == StringToDouble(repr = StringFormat("%.15g", value)))
      return repr;
   if(value == StringToDouble(repr = StringFormat("%.16g", value)))
      return repr;
   return StringFormat("%.17g", value);
  }
Reason: