unexpected behavor mql4 double values

 

double aprice =NormalizeDouble(1.33083,4);
double bprice =NormalizeDouble(1.3312,4);
double abdiff = aprice-bprice;

if(abdiff == -0.0004)
Print("Equal -0.0004");
else
Print("Not equal -0.0004");

Output: Not equal -0.0004


Expected output should be "Equal -0.0004"
It works only if I normalize abdiff again, but why is this needed?

 

You should not compare doubles. See here for explanations -> https://www.mql5.com/en/articles/1561.

(and next time please search, questions about double arithmetic 'problems' are asked weekly).

 
seizu:

double aprice =NormalizeDouble(1.33083,4);
double bprice =NormalizeDouble(1.3312,4);
double abdiff = aprice-bprice;

if(abdiff == -0.0004)
Print("Equal -0.0004");
else
Print("Not equal -0.0004");

Output: Not equal -0.0004


Expected output should be "Equal -0.0004"
It works only if I normalize abdiff again, but why is this needed?

Always compare doubles using < > and not ==
 

I often use code like

double epsilon = Point * 0.001;
...
// are value1 and value2 the same?
if(MathAbs(value1 - value2) < epsilon)
   Alert("We have a match");
 
int aprice_in_points =NormalizeDouble(1.33083,4)/Point;
int bprice_in_points =NormalizeDouble(1.3312,4)/Point;
int abdiff_in_points = aprice_in_points-bprice_in_points;

double delta=-0.0004;

if(abdiff_in_points == MathFloor(delta/Point)) Print("Equal ",DoubleToStr(delta*Point,4));
else Print("Not equal ",DoubleToStr(delta*Point,4));


 
seizu:

[...] It works only if I normalize abdiff again, but why is this needed?

Answering your actual question about why it's needed, rather than suggesting alternatives, 1.1312 cannot be precisely represented in a double. Therefore, the difference between a double containing 1.3312 and a double containing 1.3308 is not exactly -0.0004.

In addition, the value -0.0004 also cannot be precisely represented in a double. However, the calculation of abdiff (which gives -0.000399999999999955950) is different to the best-possible representation of -0.0004. Therefore, "abdiff == -0.0004" does not evaluate to true.

One way or another, when working with doubles you need to recognise the inherent imprecision, and specify to what degree of accuracy you are comparing results. All the suggestions made above are variants on that theme, including your own original suggestion of using NormalizeDouble() on abdiff. For confirmation, "NormalizeDouble(abdiff, 4) == -0.0004" does not mean "is abdiff equal to -0.0004 when truncated to 4 decimal places?" It actually means "is abdiff, when truncated to four decimal places, equal to the least-inaccurate floating point representation of -0.0004?"
 
jjc:
Answering your actual question about why it's needed, rather than suggesting alternatives, 1.1312 cannot be precisely represented in a double. Therefore, the difference between a double containing 1.3312 and a double containing 1.3308 is not exactly -0.0004.

In addition, the value -0.0004 also cannot be precisely represented in a double. However, the calculation of abdiff (which gives -0.000399999999999955950) is different to the best-possible representation of -0.0004. Therefore, "abdiff == -0.0004" does not evaluate to true.

One way or another, when working with doubles you need to recognise the inherent imprecision, and specify to what degree of accuracy you are comparing results. All the suggestions made above are variants on that theme, including your own original suggestion of using NormalizeDouble() on abdiff. For confirmation, "NormalizeDouble(abdiff, 4) == -0.0004" does not mean "is abdiff equal to -0.0004 when truncated to 4 decimal places?" It actually means "is abdiff, when truncated to four decimal places, equal to the least-inaccurate floating point representation of -0.0004?"

...and there was light !

thx!!

Reason: