Libraries: Math Utils - page 5

 
FXAI #:
These are three handy functions for comparison and rounding of floating-point numbers and formatting money:

1. `bool DoubleEquals(double x, double y, double eps)` compares two double values `x` and `y` with a given epsilon value `eps` and returns a boolean value indicating if they are equal within the given tolerance.

2. `double RoundTo(double value, int digits)` rounds a double value `value` to the given number of decimal `digits`.

3. `string FormatMoney(double amount)` formats a double value `amount` as a string representing a currency amount. It formats the amount with two decimal places, replaces the decimal point with a comma, and inserts spaces every three digits for readability. It also adds the currency symbol obtained from `AccountInfoString(ACCOUNT_CURRENCY)` at the end.

Thank you so much for that. However, these functions are already implemented in the library (even with more robust results than yours), but with different names.

// Check whether two numbers are equal up to "n" digits of precision.
int    Compare(const double a, const double b, const int digits);
bool   EqualDoubles(double a, double b, int significantDigits = 15);
bool   IsClose(const double a, const double b, const int maxDifferentSignificantDigits = 2)

// accurate decimal rounding to avoid unexpected results.
double Round(const double v);                       
double Round(const double value, const int digits); 
double Round(const double value, const double step);

// Formats double with thousands separator and specified decimals.
string FormatDouble(const double number, const int digits, const string separator=",");

 

Hello @amrali, thanks for your contribution.

Maybe this is a bug?

I expected second print to be "0.0001".

If is a bug, how to fix? If not, whats wrong in my code?

Thank you.

double ask = 1.2973;
double bid = 1.2972;
double spread = ask - bid;

Print(spread);// Outputs: 0.00009999999999998899
Print(StripError(spread));// Outputs: 0.000099999999999989


amrali
amrali
  • 2024.04.05
  • www.mql5.com
Trader's profile
 
jonlinper #:

Hello @amrali, thanks for your contribution.

Maybe this is a bug?

I expected second print to be "0.0001".

If is a bug, how to fix? If not, whats wrong in my code?

Thank you.


Print the hexadecimal representations and you will understand that the spread is far from the true real value 0.0001 (that is because round-off errors during subtraction).

So, you have to use rounding procedures.

   double ask = 1.2973;
   double bid = 1.2972;
   double spread = ask - bid;

   Print(spread);                                  // Outputs: 0.00009999999999998899
   Print(StripError(spread));                      // Outputs: 0.000099999999999989

   Print(DoubleToHexadecimal(spread));             // Outputs: 0x3F1A36E2EB1C4000
   Print(DoubleToHexadecimal(StripError(spread))); // Outputs: 0x3F1A36E2EB1C4001
   Print(DoubleToHexadecimal(0.0001));             // Outputs: 0x3F1A36E2EB1C432D

   Print(EQ(spread, 0.0001));                      // Outputs: true
   Print(Round(spread, 16));                       // Outputs: 0.001

There are sublte differences you should notice:

StripError() rounds at the 16th signifiant digit 0.00009999999999998899 (0's are not counted).

Round(x, 16) is rounding at the 16th digits after the decimal point  0.00009999999999998899

 
jonlinper #: I expected second print to be "0.0001".

Floating-point has an infinite number of decimals. It's you, not understanding floating-point and that some numbers can't be represented exactly. (like 1/10.)
          Double-precision floating-point format - Wikipedia

See also The == operand. - MQL4 programming forum (2013)

If you want to see the correct number of digits, convert it to a string with the correct/wanted accuracy.
          question about decima of marketinfo() - MQL4 programming forum (2016)

 
William Roeder #:

Floating-point has an infinite number of decimals. It's you, not understanding floating-point and that some numbers can't be represented exactly. (like 1/10.)
          Double-precision floating-point format - Wikipedia

See also The == operand. - MQL4 programming forum (2013)

If you want to see the correct number of digits, convert it to a string with the correct/wanted accuracy.
          question about decima of marketinfo() - MQL4 programming forum (2016)

Dear William, thanks for the clarification, however I do not agree with you regards "infinite number of decimals". FP numbers actually have finite number of decimal digits. (For example 0.1 has exactly 52 digits after the decimal point). 

Pease use DoubleToStringExact(0.1) from my library to print them all. Also, you can check the complete decimal string using this calculator here: https://www.exploringbinary.com/floating-point-converter/
Also, notice that the complete decimal string must always end with the digit "5".

0.1000000000000000055511151231257827021181583404541015625