Math Utils (MT4) – library MetaTrader 4

Handy functions for comparison of doubles

int  Compare(double a, double b, int digits);

bool EQ(double a, double b, int digits = 8);
bool NE(double a, double b, int digits = 8);
bool GT(double a, double b, int digits = 8);
bool LT(double a, double b, int digits = 8);
bool GTE(double a, double b, int digits = 8);
bool LTE(double a, double b, int digits = 8);

bool AlmostEqual(double a, double b);
bool EqualDoubles(double a, double b, int significantDigits = 15);
bool IsClose(double a, double b, int maxDifferentSignificantDigits = 2);

int  GetEqualDigits(double a, double b);
int  GetEqualSigDigits(double a, double b);


Handy functions for rounding of doubles

double Ceil(const double v);
double Ceil(const double value, const int digits);
double Ceil(const double value, const double step);

double Floor(const double v);
double Floor(const double value, const int digits);
double Floor(const double value, const double step);

double Round(const double v);
double Round(const double value, const int digits);
double Round(const double value, const double step);

double Trunc(const double v);
double Trunc(const double value, const int digits);
double Trunc(const double value, const double step);

double RoundToSignificantDigits(const double value, int digits);
double RoundPrice(double pPrice, string pSymbol = NULL);
double RoundVolume(double pVolume, string pSymbol = NULL);

double StripError(const double value);

Miscellaneous handy functions for doubles

// Determines whether the passed value is an integer.
bool   IsInteger(double value);

// Checks if a number has a specified number of fractional digits.
bool   IsRound(double value, int digits);

// Checks if a number is a whole multiple of some increment.
bool   IsRound(double value, double step);

// Get the decimal part of x (always has the same sign as x)
double Frac(double value);

// Get number of fractional digits after the decimal point.
int    GetDigits(double value);

// Get number of integer digits to the left of decimal point.
int    GetIntegerDigits(double value);

// Get number of significant digits, excluding leading and trailing zeros.
int    GetSignificantDigits(double value);

// Convert value in range [min, max] to y in another range [destMin, destMax].
double Remap(double value, double min, double max, double destMin, double destMax)

// Remap value on a scale [min, max] to normalized scale [0, 1].
double Normalize(const double value, const double min, const double max);

// Remap normalized value [0, 1] to a scale [destMin, destMax].
double Denormalize(const double value, const double destMin, const double destMax)

// Clamping (limiting) a number to boundaries (range).
T      Clamp(T value, T min, T max);

// Wrap a value between min (inclusive) and max (exclusive).
T      Wrap(const T value, const T min, const T max);

// Avoids zero divide error that forces the mql program to stop.
double safeDiv(double a, double b);

// Returns the exponent of the scientific notation of a number.
int    FloorLog10(const double value);

// Returns pow(10, (int)power), uses fast lookup table for powers.
double GetPower10(const int power);

// Computes the sign of a value as 1, 0, -1
double MathSign(const double value);


Handy functions for low-level binary operations on doubles

// Returns the bit representation corresponding to a double value .
long   DoubleToLongBits(double value);

// Returns the double value corresponding to a bit representation.
double LongBitsToDouble(long bits);

// Returns the raw encoding of exponent in the bit representation.
int    RawExponent(double value);

// Returns raw encoding of significand in the bit representation.
long   RawSignificand(double value);

// Returns the unbiased (adjusted) exponent of a double value.
int    GetExponent(double value);

// Returns the significand of a double value.
long   GetSignificand(double value);

// Determine whether number is exactly representable in double.
bool   IsExactDouble(double value);

// Returns the next representable value after x away from zero.
double NextAfter(double value);

// Advances a floating-point number by a specified number of ULPs.
double DoubleAdvance(double value, long distance);

// Returns the size of an ulp of the argument.
double Ulp(double value);

// Returns the difference between two floats expressed in ulp units.
long   UlpDiff(double value1, double value2);

Handy functions for formatting of doubles to string

// Converting numeric value into the raw hexadecimal text string.
string DoubleToHexadecimal(double value);

// Converting numeric value into the hex float constant string.
string DoubleToHexFloatConstant(double value);

// Converting numeric value into the exact decimal text string.
string DoubleToStringExact(double value);

// Converting numeric value into a string in scientific notation.
string DoubleToExponential(const double value, int digits = -1);

// Converting numeric value into the shortest round-trip string representation.
string Repr(double value);
string Repr(float value);

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

Exact comparison of doubles

Sometimes, when comparing two double numbers that assumed to be equal, but reached to via different calculations, the comparison goes wrong. Actually A can differ from B by in very little amount (at the 16th decimal place) due to binary rounding errors, so exact comparisons (==, !=, >, >=, <, <= operators) fail.

Alternative:  Daily Chart Trader - EA MetaTrader 4

Real situations of where exact comparison of doubles can fail

  • Comparing doubles reached via different calculations:

    if (0.1+0.2 == 0.3)  // false
    
  • Experts with trailing stop function:

    if (new_sl > OrderStopLoss())
    if (new_sl < OrderStopLoss())
  • Experts with hidden take profit function:

    if (Bid >= HiddenTakeProfit)
    if (Ask <= HiddenTakeProfit)
  • Comparing price levels in a grid strategy:

    if (Ask < virtual_stopLoss)
    if (Bid > virtual_stopLoss)

Loose Comparison

To avoid unexpected results, it is better to replace exact comparisons (==, !=, >, >=, <, <=), with loose comparisons to overcome the floating-point imprecision. This small library provides the required functions.

Alternative:  Instantaneous_TrendFilterSign - indicator MetaTrader 5
//--- exact comparisons can fail
if (Ask < virtual_stopLoss)
if (Bid > virtual_stopLoss)
if (0.1+0.2 == 0.3)  // false

//--- using library functions, results become as expected
if (LT(Ask, virtual_stopLoss))
if (GT(Bid, virtual_stopLoss))
if (EQ(0.1+0.2, 0.3))  // true
📈 ROBOTFX MetaTrader Expert Advisors and Indicators to maximize profits and minimize the risks