程序库: 数学工具 - 页 2

 
2023 年 2 月 21 日更新

添加了一个用于比较双倍值的新函数:

//+------------------------------------------------------------------+
//| 测试两个数字是否接近于 "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)));
  }