Libraries: Math Utils - page 2

 
Update 21 February 2023

Added a new function for comparing doubles:

//+------------------------------------------------------------------+
//| Test whether two numbers are close to within "n" significant     |
//| digits of precision.                                             |
//+------------------------------------------------------------------+
bool EqualDoubles(const double a, const double b, const int significantDigits = 15)
  {
//--- https://stackoverflow.com/a/17382806
   return MathAbs(a - b) < MathPow(10, -significantDigits) * MathMax(MathAbs(a), MathAbs(b));
  }
 
amrali #:
Added two new functions for comparing doubles:

Faster.

bool EqualDoubles(const double a, const double b, const int significantDigits = 15)
  {
    static const double MathPows[] = {1e-0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15};

//--- https://stackoverflow.com/a/17382806
   return MathAbs(a - b) < MathPows[significantDigits] * MathMax(MathAbs(a), MathAbs(b));
  }
 
fxsaber #:

Faster.

Ugly!

Sure, it is faster but in interpreted languages like JavaScript, but not in MQL. See https://stackoverflow.com/a/48764436.

void OnStart()
  {
   int runs = 1e9;
   Benchmark(runs, EqualDoubles(1.2345, 5.4321, 4));
   Benchmark(runs, EqualDoubles_2(1.2345, 5.4321, 4));
  }

// EqualDoubles(1.2345,5.4321,4) -> 0 msec
// EqualDoubles_2(1.2345,5.4321,4) -> 0 msec
How to round to at most 2 decimal places, if necessary
How to round to at most 2 decimal places, if necessary
  • 2012.08.06
  • stinkycheeseman stinkycheeseman 42.2k 7 7 gold badges 29 29 silver badges 49 49 bronze badges
  • stackoverflow.com
I'd like to round at most two decimal places, but only if necessary . How can I do this in JavaScript?
 
amrali #:

Sure, it is faster but in interpreted languages like JavaScript, but not in MQL. See https://stackoverflow.com/a/48764436.

You need to learn how to make proper performance measurements.

#include <fxsaber\Benchmark\Benchmark.mqh> // https://www.mql5.com/ru/code/31279

#define BENCH(A) for (int i = 0; i < 1e8; i++) Tmp += A

void OnStart ()
{
  int Tmp = 0;  
  _BV(BENCH(EqualDoubles(1.2345, 5.4321, i % 15)), 1) // 3953430 mcs.
  Print(Tmp);
  
  Tmp = 0;
  _BV(BENCH(EqualDoubles2(1.2345, 5.4321, i % 15)), 1) // 182654 mcs.
  Print(Tmp);  
}

21 times faster.

 

@fxsaber Yes, you are right, I forgot that the expression got optimized out, coz its value was not used.

However, mine takes 0.04 microsec per call. Do you think it worth this micro-optimization over readability?!!

The percentage saved over a whole program = percentage function is called * percentage saved by optimization.

Surely, the 1st term of the equation is always way too small for this specific function. That is why profiling your program is sometimes more important to see the whole picture, rather than timing a single instruction.

Thanks for passing by. :-)
 
amrali #:

However, mine takes 0.04 microsec per call. Do you think it worth this micro-optimization over readability?!!

In this case, I am definitely on the performance side. Readability is very easy for me.

 
fxsaber #:

In this case, I am definitely on the performance side. Readability is very easy for me.

I'm sure you are. take care.

 
Print(EqualDoubles(1.2345, 5.4321, 0)); // true
 
bool EqualDoubles3( const double a, const double b, const int significantDigits = 8 )
  {
   return(!NormalizeDouble(a - b, significantDigits));
  }
Alert: Bench_Stack = 0, 1 <= Time[Test5-3.mq5 169 in OnStart: for(inti=0;i<1e8;i++)Tmp+=EqualDoubles(1.2345,5.4321,i%8)] = 3689020 mcs.
12500000
Alert: Bench_Stack = 0, 1 <= Time[Test5-3.mq5 173 in OnStart: for(inti=0;i<1e8;i++)Tmp+=EqualDoubles2(1.2345,5.4321,i%8)] = 111013 mcs.
12500000
Alert: Bench_Stack = 0, 1 <= Time[Test5-3.mq5 177 in OnStart: for(inti=0;i<1e8;i++)Tmp+=EqualDoubles3(1.2345,5.4321,i%8)] = 573889 mcs.
0
 

It seems to me that such a modification of the condition is correct.

bool EqualDoubles4(const double a, const double b, const int significantDigits = 15)
  {
//--- https://stackoverflow.com/a/17382806
   return (a == b) || (MathAbs(a - b) < MathPow(10, -significantDigits) * MathMax(MathAbs(a), MathAbs(b)));
  }