![Working with Doubles in MQL4](https://c.mql5.com/i/articles/overlay.png)
Working with Doubles in MQL4
Introduction
The MQL programming opens new opportunities for the automated trading, many people all over the world already have appreciated it.When we are writing an Expert Advisor for trading, we must be sure that it will work correctly.
Many newbies often have some questions when
the results of some mathematical calculations differ from those
expected. The program is compiled and can work, but not as it should. They are checking the code again and again, finding the new "mistakes" in language, in implementation, in functions, etc.
In the most of cases, the careful analysis shows that the language and compiler work correctly, but code has a small error, and it can take a long time to find and correct it.
In this note we will consider a typical programming errors, that occurs while working with double numbers in MQL4 programs.
1. Verifying the numerical values
To
verify the calculation results and to debug you can use the function DoubleToStrMorePrecision(double number, int precision) of
standard library stdlib.mq4, which allows you to control the numerical
values of double numbers to the specified precision.
It will allow to save time in searching for possible errors.
An example:
#include <stdlib.mqh> int start() { double a=2.0/3; Alert("Standard output:",a,", 8 digits precision:",DoubleToStr(a,8),", 15 digits precision:", DoubleToStrMorePrecision(a,15)); return(0); }
Result:
Standard output:0.6667, 8 digits precision:0.66666667, 15 digits precision:0.666666666666667
For example:
#include <stdlib.mqh> int start() { double a=2.0/100000; Alert("Standard output=",a,", More precise output=",DoubleToStrMorePrecision(a,15)); return(0); }
returns: "Standard output=0, More precise output=0.000020000000000".
2. Accuracy of the decimal digits precision
Because of the double precision floating-point format there is a limited accuracy of their storage.
For example, if we assume that we have an unlimited precision, as in theory, for any double numbers A and B, the following expressions are always valid:
(A/B)*(B)=A,
A-(A/B)*B=0,
(A/B)*(B/A)=1 etc.
The accuracy of the decimal digits storage in computer is dependent on the fraction size and limited by 52 bits. To illustrate this fact, let's consider the following example.
In the first cycle (i) we are calculating the factorial of 23 (product of the integers from 2 to 23), and the result is: 23!=25852016738884976640000. The result is stored in the variable a of double type.
In the next cycle (j), we are dividing the resulted value a by all of the integers from 23 to 2. It seems that finally we can expect that a=1.
#include <stdlib.mqh> int start() { int maxfact=23; double a=1; for (int i=2; i<=maxfact; i++) { a=a*i; } for (int j=maxfact; j>=2; j--) { a=a/j; } Alert(" a=",DoubleToStrMorePrecision(a,16)); return(0); }
Instead it we have:
a=1.0000000000000002
As we see we have got an inaccurancy in 16th digit.
If we increase the calculation to 35!, we will get a=0.9999999999999998.
The MQL language has a function NormalizeDouble, which allows to round the double number to the specified precision.
The constants of the double type are stored in memory in a similar way as double variables, therefore it is necessary to take into account the limit of 15 significant digits in their definition.
But do not confuse the accuracy of the decimal digits precision with the calculation precision for the double numbers.
The range of possible values for the double numbers is much wider: from -1.7*e-308 to 1.7*e308.
Let's try to estimate the smallest exponent of the double number.int start() { double R=1; int minpwr=0; while (R>0) {R=R/10; minpwr--;} Alert(minpwr); return(0); }
The program will print -324, but we have to take into account the decimal digits in fraction (+15) and we will get an approximate value for the exponent of the smallest double number.
3. Function NormalizeDouble
The function NormalizeDouble (double value, int digits) rounds the floating point value to the given precision. Returns normalized value of the double type.For example:
int start() { double a=3.141592653589; Alert("a=",DoubleToStr(NormalizeDouble(a,5),8)); return(0); }
the result is:
a=3.14159000
Note that in trading operations it is impossible to use the unnormalized prices, whose accuracy exceeds at least by one digit demanded by a trading server.
The StopLoss, TakeProfit and Price values for the pending orders should be normalized with the accuracy, which value is stored in predetermined variable Digits.
4. Check for equality of two double numbers
It is recommended to compare two double numbers using the function CompareDoubles(double number1,double number2) of the stdlib.mq4 library, which looks as:
//+------------------------------------------------------------------+ //| correct comparison of 2 doubles | //+------------------------------------------------------------------+ bool CompareDoubles(double number1,double number2) { if(NormalizeDouble(number1-number2,8)==0) return(true); else return(false); }
This function compares number1 and number2 of double type with an accuracy of up to 8 decimal digits.
The example:
#include <stdlib.mqh> int start() {double a=0.123456781; double b=0.123456782; if (CompareDoubles(a,b)) {Alert("They are equal");} else {Alert("They are different");} }
will output:
They are equal
because the are differ only in the 9th digit.
If necessary, you can write your own compare function (with the desired accuracy) in a similar way.
5. Dividing integers
It is necessary to remember, that if we are dividing two integers, we will get an integer number as result.
That's why the code:
int start() { Alert(70/100); return(0); }
will output 0, because 70 and 100 are integers.
As well as C/C++ language, in MQL the result of division of two integers will be an integer, in this case it is 0.
However, if the numerator or denominator is double (i.e. has a fractional part), the result will be a double. Therefore Alert (70/100.0);
will output the right value 0.7.
int start() { double a=1/3; double b=1.0/3; Alert("a=",a,", b=",b); return(0); }
will output "a=0, b=0.3333"
6. Typecasting for integer and double numbers
Let's consider the code:double xbaseBid=1.2972; double xBid=1.2973; double xPoint=0.0001; int i = 100 + (xBid - xbaseBid)/xPoint; Alert(i);
We will get 100, but it seems that it should be 101, because of the evident equity: 0.0001/0.0001=1
The same example in C/C++:double baseBid=1.2972,Bid=1.2973,Point=0.0001; int i = 100 + (Bid - baseBid)/Point; printf("%d\n",i);
also gives 100.
To determine the reason of this fact, let's consider the code:
double a=0.99999999999999; int i = 100 + a; Alert(i);
which gives i=100.
However, if we perform some accuracy improvement for a:
double a=0.999999999999999; int i = 100 + a; Alert(i);
then we will get 101.
The reason of this fact is the use of integer and double numbers, complicated by low accuracy values.
Therefore, using the operations of such type it is recommended to perform the rounding of the similar expressions using the function MathRound(double value)
which returns the rounded double value to the nearest integer:
double baseBid=1.2972; double xBid=1.2973; double xPoint=0.0001; int i = 100 + MathRound((xBid - baseBid)/xPoint); Alert(i);
In such case we will get the right value 101.
There is a common error in using the function OrderModify, especially for the Trailing Stop programming. The function OrderModify returns an error № 1: ERR_NO_RESULT in the case if the new values for the orders are the same as already defined. So it is necessary to perform a careful check for the equality (use NormalizeDouble) and a careful points size calculations.
Remember that the client terminal allows to change the order parameters only if the new values differ from already defined at least in 1 point.
7. Features of function MathMod
In MQL the MathMod (double v1, double v2) function completely corresponds to the function fmod (double v1, double v2) of MSVC6, because of the direct call for the fmod function from C Runtime Library has used.
In some cases the function fmod of MSVC6 (and also MathMod) gives wrong results.
If you are using the function MathMod in your programs, please replace it to the following function:double MathModCorrect(double a, double b) { int tmpres=a/b; return(a-tmpres*b); }
Note that this remark is for MQL4 only, MQL5 calculates this function by its mathematical definition.
Conclusion
Note that the above list is not exhaustive, if you have found something new, which hasn't been described here, look at the comments.
If you haven't found a solution, describe it in the comments, add your code and MQL community professionals will help you.
Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/1561
![Trader's Kit: Decorating Indicators](https://c.mql5.com/2/17/799_33.jpg)
![Interaction between MеtaTrader 4 and MATLAB Engine (Virtual MATLAB Machine)](https://c.mql5.com/2/16/782_20.gif)
![Auto-Generated Documentation for MQL5 Code](https://c.mql5.com/2/0/ava.png)
![Superposition and Interference of Financial Securities](https://c.mql5.com/2/17/800_14.gif)
![MQL5 - Language of trade strategies built-in the MetaTrader 5 client terminal](https://c.mql5.com/i/registerlandings/logo-2.png)
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
I am new to mql programming and the issue 1 discussed here( Verifying the numerical numbers) was a show stopper for me. Lucky I saw this within 6 months after starting mql programming. This I hope is sorted in mql5 and never heard of in any other high level languages that I am familiar with.
I am new to mql programming and the issue 1 discussed here( Verifying the numerical numbers) was a show stopper for me. Lucky I saw this within 6 months after starting mql programming. This I hope is sorted in mql5 and never heard of in any other high level languages that I am familiar with.
put the link of what I put in the forum, where I explain what I need, thank you very much aid they can offer me
https://www.mql5.com/en/forum/160483
I hope you can help me.
put the link of what I put in the forum, where I explain what I need, thank you very much aid they can offer me
https://www.mql5.com/en/forum/160483
I hope you can help me.
You can not do that that way (double has 15 significant digits)
If you need only the string you can declare it as a string right away and then you will not lose information - like this :
But any conversion to and from a double will leave you with only 15 accurate digits result
You can also check this : https://en.wikipedia.org/wiki/List_of_arbitrary-precision_arithmetic_software for arbitrary precision arithmetic libraries and software capable of doing it
The function double MathModCorrect(double a, double b) generates an error if the "a" and "b" parameters are below one (1). To be able to work with numbers below one (1) you can use the following function: