Question to the MQL4 masters. Again about Double Compare. - page 6

 
VBAG:
...
The beauty of Irtron's code is its compactness (absolutely nothing extra - even variables are saved!)
...


Here, look at the method proposed by Irtron

int ComparePrice(double a, double b, double digit)
{
     a -= b;
     b = digit;
     if (a > b)
         return (1);
     if (a < -b)
         return (-1);
     return (0);
 }

It's both compact and faster than mine, but even at first glance looks suspicious, because the comparison involves two variables double!!!!

In this scheme, only digit acts as a constant and can be compared, while variable a, which is also compared, remained unnormalized double!
Does this arouse suspicion? (Under constant I understand usual constants - "#define" and those variables which were not involved in the operations).

Also in other branches developers themselves wrote that even constants double better not to compare!!!
This is also not correct to do NormalizeDouble(a) ! NormalizeDouble(b), !OC! - comparison operator!

All the more, in the original version instead of constant digits was so b = Point / 2 - here already two of two non-normalized variables?

I'd like to believe that this variant is genius, but first dispel my doubts!

Maybe someone will find errors in my variant too?
 
gravity001:

Here's a look at the method Irtron suggested

int ComparePrice(double a, double b, double digit)
{
     a -= b;
     b = digit;
     if (a > b)
         return (1);
     if (a < -b)
         return (-1);
     return (0);
 }
I suggested a different method.
Look more closely, please.


Especially since in the original version instead of the digits constant it was so b = Point / 2 - here already two of the two non-normalised variables?

What versions are we talking about?

I've already told you about normalisation. First, tell me why to apply it, and then how and where.

For example, maybe you know, why we should compare prices with accuracy of 14 digits, that is mentioned as some achievement in discussion above? :) Let me remind you, the function I suggested is called ComparePrice :)
 

Irtron писал (а):
...
I suggested a different method.
Look more carefully, please.
...

What versions are we talking about?

I've already told you about normalization. First, tell me why it should be applied, and then how and where.

For example, maybe you know, why we should compare prices with accuracy of 14 digits, that is mentioned as some kind of achievement in discussion above? :) Let me remind you, the function I suggested is called ComparePrice :)
Here, is this yours? Am I quoting correctly now?
Irtron 10.09.2007 04:07

...

int ComparePrice(double a, double b)
{
a -= b;
b = Point / 2;
if (a > b)
return (1);
if (a < -b)
return (-1);
return (0);
}
...
Just a reminder, the function I suggested is called ComparePrice. :)

If you noticed, I also quoted function called ComparePrice. It's just that yours has already been modified by VBAG. That's why I've referred to the pristine version meaning the original one, i.e. your function!
I have tested both functions myself. Yes, they turned out to be faster. But how to check reliability of comparison? I'm very much confused by comparison of two variables double. Although all must be correct because an interval is taken! But still there are suspicions that it will not always work correctly!

I have already talked about normalisation. First tell me why to apply it, and then how and where.

Here is the key question, right? I myself thought about it for a long time: "You type double and get double ".
I haven't found the exact answer. But I can imagine it this way

double a = 2.000000000000
double b = 2.000000000001
double c = 1.99999999999999

All these variables are different and are stored in memory accurate to the last digit!
In this case, we ourselves define the signs (digits). Everything that is not defined is filled with zeros.

If we had defined double a = 2.0, and it is stored in memory as 2.0000001 or 1.9999999, it is clear that NormalizeDouble() would not help, because it would return an inaccurate value!
I think such an error occurs almost never when memorizing a variable value. Besides, I don't think number 2.0 is stored as 1.999999999999999, because each character (digit or point) is stored with a specific bit in the bit-string! Therefore, the number 2.0 is safely stored as 2.00000...00.

The other case is when we do not determine the signs ourselves:

a = 4.0;
b = 2.0;
c = a / b // - the "division" operation is done by the processor, or rather by the co-processor, and it fills the premenent with characters (digits).

After the operation it can be:
Most commonly:
с = 2.000...0
с= 1.99999999...
с= 2.00000001...

i.e. the result often differs from the true value by a small amount.

Large errors occur very rarely:
с = 2.3

Here, there are two explanations:
1) part of the bit string was affected in memory when calling a or b, i.e. variables a and b were changed.
2) an error occurred during the "divide" operation.

I think 2) occurs most often. Why I don't know. I think it has to do with the fact that the co-processor is intended to be highly optimized to the detriment of uselessness.

When comparing a variable to number 2.000...00, equality will obviously fail. Not all the bits will be equal.

Now, NormalizeDouble() is here to help!
NormalizeDouble() will "correct" this small error!
Since the error is often very small, rounding with a small precision will always give the correct result.

Look at it this way:
Round the number a = 2.111...11 to the second digit.
NormalizeDouble() will write 2.11 into a new variable and fill in the remaining bits with zeros, not ones!
I think it will look like this:

double MyNormalizeDouble(double value, int digits)
{
    int factor = MathRound( MathPow(10, digits) ); // factor - это множитель,
                                                      с помощью которого мы из VALUE сделаем целое число
    double result = MathRound(factor * value) / factor;
    
    return(result);
}
Here, I tried my best to explain why NormalizeDouble() is needed.

Until recently I was completely satisfied with this explanation, but have recently got convinced myself that this scheme does not always work

NormalizeDouble(a, 2) !OC! NormalizeDouble(b, 2) where !OC! - is a comparison operator.
Although according to my understanding it must always work!
Therefore, I will be glad to receive any reasoned and understandable criticism!
 
gravity001:

Also, in other threads the developers themselves have written that even double constants are better not to be compared!!!
This is news to me! This is what they call a substantive question!
If you can, please give me a link!

I have a question for the developers:

Please explain what are the limitations or possible problems when comparing doubles using constants:
1.
double a=1.23456789;
double b;

if(a>b) or if(a<b)

And in this form:
2.
#define a 1.23456789;

double b;

if(a>b) or if(a<b)
 
gravity001:

Especially since the original version had b = Point / 2 instead of constant digits - here already two of two non-normalized variables?

That's why I replaced b = Point / 2 with constant (1.fewer operations - faster speed 2.explicit constant transfer - higher reliability)

But in light of your statement about unreliability of double constant comparison, the whole point is lost. We need to look into this issue more closely.

I wonder what the developers will say.
 
VBAG писал (а):
...
Now that's news to me! That's what they call a substantive question!
If you can, please give me a link!
...
Yes, I was looking for the link, wanted to paste it immediately, but I couldn't find it! I remember seeing it somewhere, but there were so many such topics. I've also read a bunch of topics on other forums, and from books on the subject.
I remember someone writing somewhere, but can't remember where(((((. So, probably, it was not correct of me to write: "in other threads the developers themselves wrote"!
I apologize.
But if I find the link be sure to post.

I think I read it in a book on C++. It described how to compare real numbers and said that it's best to go to integers!
 
gravity001:
VBAG wrote (a):
...
This is news to me! That's what they call a substantive question!
If you can, please give me a link!
...
Yes, I was looking for the link, wanted to insert it immediately, but did not find it! I remember seeing it somewhere, but there were so many such topics. I've also read a bunch of topics on other forums, and from books on the subject.
I remember someone writing somewhere, but can't remember where(((((. Therefore, probably, it was not correct of me to write: "in other threads the developers themselves wrote"!
I apologize.
But if I find the link be sure to post.

I think I read it in a book on C++. It described how to compare real numbers and said that it's best to go to integers!
Thank you for your participation and help. Unfortunately, I don't have an academic background in programming. So I have to listen and memorize more. And hope the developers will respond and clarify my question.
I have a question for the developers:

Please clarify what are the limitations or possible problems when comparing dubs using constants:
1.
double a=1.23456789;
double b;

if(a>b) or if(a<b)

And in this form:
2.
#define a 1.23456789;

double b;

if(a>b) or if(a<b)
 
Such problems - 1.3333+0.0004 != 1.3337
 

This conversation seems to go on indefinitely. By the time a new user has gained proper experience and knowledge, he usually manages to bump into normalisation several times.

Maybe, in MT5 it makes sense to forcibly limit the accuracy of real numbers in comparison operations to, say, 8 decimal places (i.e. to forcibly execute NormalizeDouble() with digit=8). And only if NormalizeDouble() is explicitly specified, perform normalization in accordance with the parameters specified in it. In this case, the issue will arise much less often, namely only when the user needs exactly the specified accuracy. In my opinion, this dick is a little bit, but still sweeter than a radish.

 
VBAG:
Hello!
As you know, not only the correctness of calculations, but also reliability of the code you wrote depends on the style of programming and accuracy in code.
We do not write toys and therefore operation reliability of the written program is the very first requirement. Most calculations are carried out in dubles and a correct comparison in the code of
of two real numbers in the program code requires a certain approach and accuracy.
I'm trying to figure out the "right" programming style, hence the question:

For an expression

double a;
double b;

if(a==b) or if(a!=b)
{......} {.... ..}

the developers recommend this
//+------------------------------------------------------------------+
//| Function for comparing two real numbers. |
//+------------------------------------------------------------------+
bool CompareDouble(double Number1, double Number2)
{
bool Compare = NormalizeDouble(Number1 - Number2, 8) == 0;
return(Compare);
}
//+------------------------------------------------------------------+


Is this code correct?

double a;
double b;

if(a>b) if(a<b)
{......} {......}


Most likely not in the general case. What is the correct way to check it?
In general, what style of working with dubles is more appropriate?
Thank you in advance to everyone who responds.

You've made a mess of things... :)

Comparison of floating numbers is done by comparing the modulus of difference with a small threshold.

Return (fabs(d1-d2) < 1e-10) for example.

What's the point of muddling the waters... The NormalizeDouble(...) function is just for nice-looking reports.