Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 指数平均移动数_Performance_Visual C++ - Fatal编程技术网

Performance 指数平均移动数

Performance 指数平均移动数,performance,visual-c++,Performance,Visual C++,我有一个指数移动平均值,它被调用了数百万次,因此是我代码中最昂贵的部分: double _exponential(double price[ ], double smoothingValue, int dataSetSize) { int i; double cXAvg; cXAvg = price[ dataSetSize - 2 ] ; for (i= dataSetSize - 2; i > -1; --i) cXAvg +

我有一个指数移动平均值,它被调用了数百万次,因此是我代码中最昂贵的部分:

double _exponential(double price[ ], double smoothingValue, int dataSetSize)
{
    int i;
    double cXAvg;
    cXAvg = price[ dataSetSize - 2 ] ;  

    for (i= dataSetSize - 2; i > -1; --i)   
        cXAvg += (smoothingValue * (price[ i ] - cXAvg)) ;

     return ( cXAvg) ;
}
有没有更有效的方法来编写代码以加快速度?我有一个多线程的应用程序,并且使用Visual C++。p> 谢谢。

哎哟

当然,多线程可以帮助您。但您几乎可以肯定地提高单线程机器的性能

首先,你计算的方向是错误的。只有最现代的机器才能进行负步长预取。几乎所有的马希恩人的单位步幅都更快。也就是说,改变阵列的方向,以便从低到高而不是从高到低进行扫描几乎总是更好的

接下来,重写一点-请允许我缩短变量名,以便更容易键入:

avg = price[0]

for i
    avg = s * (price[i] - avg)
顺便说一下,我将开始使用缩写p表示价格,s表示平滑,以节省打字。我很懒

avg0 = p0
avg1 = s*(p1-p0)
avg2 = s*(p2-s*(p1-p0)) = s*(p2-s*(p1-avg0))
avg3 = s*(p3-s*(p2-s*(p1-p0))) = s*p3 - s*s*p2 + s*s*avg1
总的来说

avg[i] = s*p[i] - s*s*p[i-1] + s*s*avg[i-2]
预计算s*s

你可以

avg[i] = s*p[i] - s*s*(p[i-1] + s*s*avg[i-2])
但这样做可能更快

avg[i] = (s*p[i] - s*s*p[i-1]) + s*s*avg[i-2])
avg[i]和avg[i-2]之间的延迟是1乘加,而不是avg[i]和avg[i-1]之间的减法和乘法。也就是说,速度是原来的两倍多

通常,您希望重写递归,以便根据avg[j]计算avg[i] 对于j,尽可能早地返回,而不填充机器,执行单元或寄存器。
基本上,为了减少关键路径上的乘法(和减法)链,您需要进行更多的乘法运算。 从avg[i-2]跳到avg[i]很容易,你可能可以做三次和四次。到底有多远 这取决于你的机器是什么,以及你有多少寄存器

浮点加法器和乘法器的延迟。或者,更好的是,你拥有的组合乘法-加法指令的味道-所有现代机器都有。例如,如果MADD或MSUB有7个周期长,你可以在它的阴影下进行多达6个其他计算,即使你只有一个浮点单元。完全流水线。等等。Less如果每隔一个R周期进行流水线,这在旧芯片和GPU上是常见的双精度。汇编代码应该是软件流水线,以便不同的循环迭代重叠。一个好的编译器应该为您这样做,但您可能必须重写C代码以获得最佳性能

顺便说一下:我的意思不是建议您创建一个avg[]数组。相反,如果avg[I]是根据avg[I-2]计算的,那么您需要两个平均值,依此类推。 如果需要,您可以使用avg[i]数组,但我认为您只需要有2或4个avg,创造性地称为avg0和avg1(2,3…),并“旋转”它们

这种把戏,将累加器或平均值分成两个或更多, 在高性能代码中,合并多个重复阶段是很常见的

哦,是的:预先计算s*s等

如果我做对了,在无限精度下,这将是相同的。(请仔细检查我。)

然而,在有限精度FP中,由于不同的取整,结果可能会有差异,希望只有微小的差异。如果展开正确且答案明显不同,则可能存在数值不稳定的算法。你就是知道的人

注意:浮点舍入错误将改变答案的低位。 这两个原因都是因为重新排列代码和使用MADD。 我想这可能没问题,但你必须做出决定

注:avg[i]和avg[i-1]的计算现在是独立的。因此,您可以使用SIMD 指令集,如Intel SSE2,允许一次对128位宽寄存器中的两个64位值进行操作。 在一台有足够ALU的机器上,这几乎是2倍

如果您有足够的寄存器按照avg[i-4]重写avg[i] (我相信你在iA64上也是这样),然后你可以走4倍宽, 如果您可以访问256位AVX之类的机器

在GPU上……你可以进行更深层次的复发,根据avg[i-8]重写avg[i],等等

一些GPU有将AX+B甚至AX+BY作为一条指令计算的指令。 虽然这对于32位精度比64位精度更常见

在某个时候,我可能会问:你想一次以多种价格做这件事吗? 这不仅有助于多线程处理,还适合在GPU上运行,并使用宽SIMD

轻微延迟添加

我有点尴尬没有应用霍纳的规则来表达像

avg1 = s*p3 - s*s*p2 + s*s*avg1
给予

avg1 = s*(p3 - s*(p2 + avg1))
效率稍高。四舍五入的结果稍有不同

为我辩护,任何体面的编译器都应该为您这样做

但Hrner的规则使依赖链在倍数方面更加深入。 您可能需要将循环展开并管道化几次。 或者你可以

avg1 = s*p3 - s2*(*p2 + avg1)
你在哪里预先计算

s2 = s*s

这里是最有效的方法,尽管在C语言中,你需要把它移植到C++,这应该非常简单,它以最有效的方式计算EMA和斜率。

public class ExponentialMovingAverageIndicator
{
    private bool _isInitialized;
    private readonly int _lookback;
    private readonly double _weightingMultiplier;
    private double _previousAverage;

    public double Average { get; private set; }
    public double Slope { get; private set; }

    public ExponentialMovingAverageIndicator(int lookback)
    {
        _lookback = lookback;
        _weightingMultiplier = 2.0/(lookback + 1);
    }

    public void AddDataPoint(double dataPoint)
    {
        if (!_isInitialized)
        {
            Average = dataPoint;
            Slope = 0;
            _previousAverage = Average;
            _isInitialized = true;
            return;
        }

        Average = ((dataPoint - _previousAverage)*_weightingMultiplier) + _previousAverage;
        Slope = Average - _previousAverage;

        //update previous average
        _previousAverage = Average;
    }
}

需要更多关于这个问题的信息。可以并行计算吗?价格有多大?你能预计算一些价格数组吗?你确定这是瓶颈吗?你分析过吗?如果是的话,在这个函数中花费的时间占总时间的百分之几?我使用Visual C profiler对此进行了分析,它大约占总时间的35%运行时间。这个指数移动平均值被称为超过1万亿次,因为它被反复用于处理超过400 GB的数据。数据来自Raid级别0的固态磁盘阵列,因此读取数据的时间占不到5%。价格大约为100。我最初在通过对尽可能多的数据进行预计算,将p乘以4,然后我可以将其再次增加一个因子,我可以将速度再次增加一个因子
public class ExponentialMovingAverageIndicator
{
    private bool _isInitialized;
    private readonly int _lookback;
    private readonly double _weightingMultiplier;
    private double _previousAverage;

    public double Average { get; private set; }
    public double Slope { get; private set; }

    public ExponentialMovingAverageIndicator(int lookback)
    {
        _lookback = lookback;
        _weightingMultiplier = 2.0/(lookback + 1);
    }

    public void AddDataPoint(double dataPoint)
    {
        if (!_isInitialized)
        {
            Average = dataPoint;
            Slope = 0;
            _previousAverage = Average;
            _isInitialized = true;
            return;
        }

        Average = ((dataPoint - _previousAverage)*_weightingMultiplier) + _previousAverage;
        Slope = Average - _previousAverage;

        //update previous average
        _previousAverage = Average;
    }
}