Bug in MetaEditor Build 3566: Wrong display of double floating point numbers in the debugger window - page 4

 
fxsaber #:
That is what I said before, NormalizeDouble() does not round numbers exactly. It always has a round off error of 1 epsilon (one wrong decimal digit on the far right). That means if you pass an exactly rounded number (like 1.14 from your test case) to the function,  you should expect to get the same number. What happens is that ND will bias the input number!

ND was implemented in a wrong way, but I don't think they'll fix it for backward compatibility. Actually, the round off error is so tiny that it is always ignored by the trading server. So, this is not a big problem for the trading platform.

The combination of bad NormalizeDouble(), the wrong display of doubles by string() or Print() in builds before 3210, in addition to the fp format weirdness itself made debugging floating point numbers like a hell, becuase you did not have the correct functions to track what was going wrong with your calculations.

Now, at least we have the correct string display of doubles 😉 

And as a result of the correct string display, it becomes so easy to detect such small errors in ND. Before that, it was attributed to some weird behavior of fp format! Infinite number of digits :-) and actually these are only 17 s.f, according to my understanding.

As a side note, mql still displays 32 bits float type wrongly, they fixed only the double type. Use Repr(float) from my library if you have issues. 

Edit:

If you are interested, you could retest your example with the function MathRound(value, digits) from my library math_utils. It rounds exactly without any tiny round off errors. 

Edit 2:

Try a dialog box that uses a float type to see what I mean.

#property script_show_inputs
input float lots = 1.2f;
void OnStart()
  {
  }


Edit 3:

The function DoubleToString(value, digits) also has some issue, that's the direction of rounding applied to half-way decimal numbers is not consistent and cannot be predicted:

void OnStart()
  {
   Print( DoubleToString(3.15, 1) );  // floored
   Print( DoubleToString(4.15, 1) );  // ceiled
  }
// 3.1
// 4.2
The PrintFormat() has exactly the same issue as above. You can check that PrintFormat("%.1f", 3.15) => "3.1", but PrintFormat("%.1f", 4.15) => "4.2". When I need to display the string of a number rounded to the specified digits in a consistent way, I use: DoubleToString(NormalizeDouble(v, d), d) or just (string)MathRound(v, d). This works because MathRound(v, d) from math_utils library does not add round off errors, while string() displays the shortest string. The advantage of DoubleToString() is that it pads the output string with zeros on the right, if necessary. 
 
The main task of a financial application when working with prices is a single price normalization algorithm. If all prices are normalized according to a single algorithm, then everything is in order. The link is proof that this is exactly what happens in the MT5.
 
fxsaber #:
The main task of a financial application when working with prices is a single price normalization algorithm. If all prices are normalized according to a single algorithm, then everything is in order. The link is proof that this is exactly what happens in the MT5.

Exactly, this is a proof that prices are rounded by NormalizeDouble(). But, it is not a proof that NormalzieDouble() itself is correct.

For example, if I code the function round(num, digits) to round numbers. If the last decimal place is 3 or below, it gets rounded to 0. If it is 4 and above, it gets rounded to 1.

Surely, using round(1.4, 1) => 2.0 as you proved it, but do you think this is the correct way to round?

The issue here, why prices gets rounded as long as it is supposed to be received in the raw state from the inter-bank network. Do they also have NomralizeDouble function, there?

Edit:

I did not check before how cTrader or other tarding platforms receive their raw quote prices.

 
amrali #:

it is not a proof that NormalzieDouble() itself is correct.

If this word is removed from the description of the function, then it becomes correct for its use.

NormalizeDouble

Rounding floating point number to a specified accuracy.

 
fxsaber #:

If this word is removed from the description of the function, then it becomes correct for its use.

Even the word normalize have a specific meaning in the context of fp, other than what the function means. It specifically means unifying the exponents when adding or subtracting two fp numbers. Google floating point arithmetic in IEEE 754.

 
fxsaber, please refer to this link on Wikipedia: https://en.m.wikipedia.org/wiki/Floating-point_arithmetic#Binary-to-decimal_conversion_with_minimal_number_of_digits
It discusses the algorithms for shortest precise roundtrip strings + the correct meaning of normalization. 

The real algorithms for a correct shortest toString() function are complex. You can check the codes at https://github.com/abolz/Drachennest/tree/master/src

 

For a proof of the correctness of NormalizeDouble(), you can run this script to compare how it performs against the Decimal.Round() Method from the Microsoft .Net Framework library. The Decimal value type (128-bits) is appropriate for financial calculations that require large numbers of significant integral and fractional digits and no round-off errors. https://learn.microsoft.com/en-us/dotnet/api/system.decimal.round?view=net-7.0

Please install "Ron's CSV Editor" on your computer to open files\rounding_errors.csv automatically. It is free. https://www.ronsplace.ca/Products/RonsEditor/Download
Download - Rons CSV Editor
Download - Rons CSV Editor
  • Aaron Stewart
  • www.ronsplace.ca
Download the latest version of Rons CSV Editor
 

In this MT4, the function works the way you want. But there must be a balance between accuracy and execution speed.

If all prices are normalized according to a single algorithm, albeit not an ideal one, then the normalization task for comparing prices is 100% complete.

 
fxsaber #:

In this MT4, the function works the way you want. But there must be a balance between accuracy and execution speed.

If all prices are normalized according to a single algorithm, albeit not an ideal one, then the normalization task for comparing prices is 100% complete.

So, do not complain!

  Print(1.14 == NormalizeDouble(1.14, 2)); // MT5-false, MT4-true.
 
amrali #:

So, do not complain!

This is not a complaint, but a warning that normalization is not exactly what most users think.