错误、漏洞、问题 - 页 2160

 
Andrey Khatimlianskii:

从MQ的角度来看,显然是正确的。像往常一样,为我们决定什么更方便。

关于交易、自动交易系统和测试交易策略的论坛

资料中没有任何信息。

Renat Fatkhullin, 2018.03.08 10:31

暂时删除,以减少在兼容模式下工作的功能数量。

迁移过程完成后,我们将立即增加新的功能。

这是一个新的非常大且功能丰富的系统。


正在引入新的聊天室。

 
Andrey Khatimlianskii:

从MQ的角度来看,显然是正确的。像往常一样,为我们决定如何更加舒适。

转移到心灵感应的层面...)))))

 

主要指标中存在不明确的错误。只出现在H1 以下的时间段,而且只在终端启动 时出现。 "S-v5(EURUSD,M10)阵列超出'S-v5.mq5'范围(211,54) " 的错误文本。绘图是正确的,但顺序相反,尽管所有缓冲区都设置了时间序列标志。

模板的组成--主指标(#1)(错误发生的地方),附加指标(#2)(主指标的几个手柄与不同参数(时间框架)的组合),指标(#3)在主图表中对指标#1的信号显示箭头),指标(#4)在主图表中对指标#2的信号显示箭头。

切换时间框架,重新应用模板,如果你从2号到4号删除任何2个指标,或者只在1号,从市场概览中输出一个新的符号,应用这个模板--错误没有再现,所有指标的呈现都是正确的。

 

编译错误

#import "Test1.ex5"
       void f1();
#import "Test2.dll"
       void f2();
#import
typedef void (*fn)();
void OnStart()
{
    fn fn1 =        f1; //нормально
    fn fn2 =        f2; //Error: 'f2' - pointer to this function type is not supported yet
    fn fn3 = Test2::f2; //нормально
}
 

错误信息不允许在大量的代码中了解原因

struct A {
    void f( int    ) {}
    void g( int fn ) { f( fn ); } //Error: ')' - unexpected token ???
};
typedef void (*fn)();

以下是明确的

struct A {
    void f( int    ) {}
    void g( int fn ) { f( fn ); } //Error: 'fn' - identifier already used
};
struct fn {};
 

没有错误信息

typedef void (*fn)();
void f( int i ) { Print( __FUNCTION__, ":", i ); }
void OnStart()
{
    f( fn() );
}

此外,它正在运行,甚至还有一个结果(!)。

在这个变体中。

typedef int (*fn)();
void OnStart() { Print( fn() ); }

不跳转到错误行(通过回车)。


 

编译错误

    void g(  int ) {}
    void g( uint ) {}
#import "Test.ex5"
    void f(  int );
    void f( uint );
#import
typedef void (*fn1)(  int );
typedef void (*fn2)( uint );
void OnStart()
{
    fn1 g1 = g; /*нормально и результат*/ g1( 1 ); //совпадает с ожидаемым
    fn2 g2 = g; /*нормально и результат*/ g2( 1 ); //совпадает с ожидаемым
    fn1 f1 = f; //Error: 'f' - cannot resolve function address
    fn2 f2 = f; /*нормально и результат*/ f2( 1 ); //совпадает с ожидаемым
                                                   //при наличии Test.ex5
}
 

在创建 这个例子 时,为了加快进度,我完全意外地碰到了一个怪事,我就把它束之高阁了。

而现在,当我试图处理这个奇怪的事情时,我变得更加困惑了。

因此,在计算中我使用了平方根函数sqrt(),我决定通过创建一个双数组来绕过它。

由于我总是从整数中提取平方根,创建一个数组看起来像这样。

   double SQRT[];
   int ss=Width*Width+Height*Height;
   ArrayResize(SQRT,ss);
   for(double w=0;w<ss;w++) SQRT[(int)w]=sqrt(w);

符合逻辑的是,从数组SQRT[x]中读取数据比使用sqrt(x)函数要快。
而这一点也被检查码所证实。

   double Sum1=0,Sum2=0;
   ulong t=GetMicrosecondCount();
   for(int i=0;i<ss;i++) Sum1+=sqrt(double(i));   // Находим сумму квадратных корней всех целых чисел от 0 до ss
   t=GetMicrosecondCount()-t;
   Print("Время на сумму "+IntegerToString(ss)+" значений функций = "+IntegerToString(t)+" мкс, Сумма = "+DoubleToString(Sum1));
   t=GetMicrosecondCount();
   for(int i=0;i<ss;i++) Sum2+=SQRT[(int)(i)];    // Находим сумму квадратных корней всех целых чисел от 0 до ss через сложение элементов массива SQRT[]
   t=GetMicrosecondCount()-t;
   Print("Время на сумму "+IntegerToString(ss)+" значений массива = "+IntegerToString(t)+" мкс, Сумма = "+DoubleToString(Sum2));

结果显示速度提高了约1.5倍。

但当我把代码中的sqrt()函数替换为读取数组元素SQRT[]时,非但没有加速,反而出现了可怕的滞后。

从SQRT[]数组中读取一个项目需要很多时间,甚至可能比运行sqrt()要多一个数量级。

而且我不明白哪里发生了速度泄漏。上面的检查代码告诉你不是这样。

我们可以假设,编译器以某种奇怪的方式访问一个大数组,并且似乎在每次循环转弯时都会 "忘记 "它,每次都会执行自己的服务索引。

但这要么是一个逻辑上的问题,要么是一个策略上的编译器错误。而且你显然应该做些什么,因为这种速度泄漏非常显著,而且很难发现,因为它不是那么明显。

我在此附上脚本代码,以证明这一怪异现象。

默认运行(arr=false)计算sqrt(),但当你把arr改为true时,平方根值就从数组中取出。

什么是错的?为什么这么慢?

附加的文件:
Swirl.mq5  11 kb
 
Nikolai Semko:

为了加快进度,在创建 这个例子 时,我完全是意外地遇到了一个怪事,我就把它搁置了。


符合逻辑的 是,从数组SQRT[x]中读取比取sqrt(x)要快。

从一个动态 阵列来看,这不是一个事实。

此外,取根已经在SQRTSD 处理器的命令层面。也就是说,你不能用动态数组中已知的访问成本来击败处理器的实现。


而这是由验证码确认的

结果显示速度提高了约1.5倍。

我怀疑这是否得到证实。

这类代码就像循环优化教科书中的内容。代码优化器可能会让它变得很甜蜜,因为这是一个非常简单的案例。

   for(int i=0;i<ss;i++) 
      Sum2+=SQRT[i];

也就是说,在应用故意完美优化的情况下,性能测量需要与测试的目标明确相关。

这种情况下的测试是错误的。

从数组SQRT[]中读取一个项目比执行sqrt()函数要花很多时间,甚至可能是一个数量级。

而且我不明白速度泄漏发生在哪里。毕竟,上面的测试代码说的不是这样。

没有看到最终的汇编代码,我倾向于。

  1. sqrt实际上是很快的(我们有一个非常有效的本地代码生成器,sqrt变成了纯SQRTSD)。
  2. 检查员的代码太简单了,通过优化来补偿延迟。


让我们仔细检查一下整个代码。发现真正的原因是什么是很有趣的。

SQRTSD — Compute Square Root of Scalar Double-Precision Floating-Point Value
  • www.felixcloutier.com
Computes square root of the low double-precision floating-point value in xmm3/m64 and stores the results in xmm1 under writemask k1. Also, upper double-precision floating-point value (bits[127:64]) from xmm2 is copied to xmm1[127:64].
 
Renat Fatkhullin:

来自一个动态 阵列,而不是一个事实。


没有看到最终的汇编代码,我倾向于。

  1. sqrt实际上很快(我们在本地代码中有一个非常有效的生成器,sqrt变成了纯粹的SQRTSD)。
  2. 检查器代码太简单,通过优化来补偿延迟。

试过静态数组--同样的事情。

就像sqrt那样快,我很难相信这个函数能比仅仅读取一个数组元素 快10倍。

此外,如果在我的例子中,画布的尺寸被缩小了,比如50x50(为此有一个输入参数Size,你需要设置50而不是0)。

而阵列将小得多(5000个元素),速度情况发生了巨大的变化。现在已经没有这么强烈的对比了。

但我不明白:数组的大小是否影响访问其项目的速度?

也许你对检查代码的简单性的看法是正确的。

我试图让它变得更复杂一些,结果却完全不同。

for(int i=0;i<ss;i++) Sum1+=i*sqrt(double(i));
....
for(int i=0;i<ss;i++) Sum2+=i* SQRT[(int)(i)];