Библиотеки: Math Utils - страница 2

 
Обновление 21 февраля 2023 года

Добавлена новая функция для сравнения двоек:

//+------------------------------------------------------------------+
//| Проверяем, близки ли два числа в пределах "n" значимых значений |
//| Цифры точности.|
//+------------------------------------------------------------------+
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 #:
Добавлены две новые функции для сравнения двоек:

Быстрее.

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

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

Быстрее.

Уродливо!

Конечно, это быстрее, но в интерпретируемых языках, таких как JavaScript, но не в MQL. См. https://stackoverflow.com/a/48764436.

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

// EqualDoubles(1.2345,5.4321,4) -> 0 мс
// EqualDoubles_2(1.2345,5.4321,4) -> 0 мс
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 #:

Конечно, это быстрее, но в интерпретируемых языках, таких как JavaScript, но не в MQL. См. https://stackoverflow.com/a/48764436.

Вам нужно научиться правильно проводить измерения производительности.

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

#define  BENCH(A) for (int i = 0; i < 1 e8; 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 раз быстрее.

 

@fxsaber Да, вы правы, я забыл, что выражение было оптимизировано, потому что его значение не использовалось.

Тем не менее, мой занимает 0,04 микросекунды на вызов. Как вы думаете, стоит ли эта микрооптимизация читабельности?!

Процент, сэкономленный за всю программу = процент, на который вызывается функция * процент, сэкономленный за счет оптимизации.

Конечно, первый член уравнения всегда слишком мал для данной конкретной функции. Вот почему профилирование программы иногда более важно, чтобы увидеть всю картину, а не тайминг одной инструкции.

Спасибо, что заглянули :-)
 
amrali #:

Однако мой занимает 0,04 микросекунды на вызов. Как вы думаете, стоит ли такая микрооптимизация читабельности?!

В данном случае я определенно на стороне производительности. Читабельность для меня очень проста.

 
fxsaber #:

В данном случае я определенно на стороне производительности. Читабельность для меня очень проста.

Уверен, вы тоже. Берегите себя.

 
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<1 e8;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<1 e8;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<1 e8;i++)Tmp+=EqualDoubles3(1.2345,5.4321,i%8)] = 573889 mcs.
0
 

Мне кажется, что такая модификация условия является правильной.

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)));
  }