我正在查看以下fortran代码,该代码计算移动平均线并试图确定它是否为尾随,居中或前向平均值。
subroutine ma(x, n, len, ave)
integer n, len, i, j, k, m, newn
real x(n), ave(n), flen, v
newn = n-len+1
flen = float(len)
v = 0.0
# get the first average
do i = 1,len
v = v+x(i)
ave(1) = v/flen
if (newn>1) {
k = len
m = 0
do j = 2, newn {
# window down the array
k = k+1
m = m+1
v = v-x(m)+x(k)
ave(j) = v/flen
}
}
return
end
编辑: 我特别困惑,因为这个函数被称为
ma(x,n,np,out)
x
是一个数组,而n
等于x
加2*np
的长度。看来第二个do
循环的索引将超出x
的范围。
编辑2:这是这个子程序的调用方式:
subroutine fts(x,n,np,trend,work)
integer n, np
real x(n), trend(n), work(n)
call ma(x,n,np,trend)
call ma(trend,n-np+1,np,work)
call ma(work,n-2*np+2,3,trend)
return
end
答案 0 :(得分:0)
所以如果我把它正确拼凑起来......
此函数返回一组平均值。 (AVE)
该数组的第一个元素在此处确定:
do i = 1,len
v = v+x(i)
ave(1) = v/flen
它将(len)元素的数量相加,然后除以(len) - 实际上(flen),它只是转换为实数的int len(认为是c#的浮点数)。
以下条件实际上产生0到许多其他(ave)元素。 数字由(n)和(len)之间的差异决定。
它将每个连续值添加到先前计算的总和中,然后除以(k)得到新总数的平均值:以(len + 1)
开头 编辑:我对逻辑的初步理解犯了一个错误。我仍然有我所描述的代码。但是代码实际上会在输入集上移动一个窗口,每次都会获得相同数量元素的平均值,而不是为不断增长的输入大小累积平均值。我还在这篇文章的底部添加了一个更新的答案。考虑到这一点,试试这个C#翻译:
public float[] CalcRollingAverage (float[] inputs, int beginAvg, int numInputs)
{
float[] averages = new float[(numInputs - beginAvg + 1)];
float sumUpToBeginAvg = 0;
for(int i = 0; i < beginAvg; i++)
{
sumUpToBeginAvg += inputs[i];
}
averages[0] = sumUpToBeginAvg / beginAvg;
int additionalAvgs = numInputs - beginAvg;
if(additionalAvgs > 0)
{
float currentSum = sumUpToBeginAvg;
int nextValIndex = numInputs - additionalAvgs - 1;
for(int j = 1; j <= additionalAvgs; j++)
{
currentSum += inputs[nextValIndex];
averages[j] = currentSum / (nextValIndex + 1);
}
nextValIndex++;
}
return averages;
}
请仔细检查数学,对于Fortran中C#vs 1基于数组的基于0的数组进行了大量调整。
此外,Fortran版本基本上使用ref参数进行平均,我改为创建一个新数组并返回它。两者都有效,但第二种方式在C#中比较常规。我相信。
以上是我能想到的直接翻译。下面是一个使用更合适的数据结构的简化版本。
public List<float> CalcRollingAverage(List<float> inputs, int beginAvg)
{
List<float> results = new List<float>();
int index = 1;
float currentSumOfInputs = 0;
foreach(float value in inputs)
{
currentSumOfInputs += value;
if(index >= beginAvg)
{
results.Add(currentSumOfInputs / index);
}
index++;
}
return results;
}
根据我最近发现的一个更新,我遗漏了一些原始逻辑。这个移动窗口并保持平均元素的数量相同:
public List<float> CalcRollingAverage(List<float> inputs, int windowSize)
{
List<float> results = new List<float>();
int index = 1;
float currentSumOfInputs = 0;
foreach(float value in inputs)
{
currentSumOfInputs += value;
if(index == windowSize)
{
results.Add(currentSumOfInputs / windowSize);
break;
}
index++;
}
if(inputs.Count > windowSize)
{
for(int i = index - windowSize + 1; i <= inputs.Count; i++;)
{
currentSumOfInputs = currentSumOfInputs - inputs(index - windowSize);
currentSumOfInputs += inputs(index);
results.Add(currentSumOfInputs / windowSize)
index++;
}
}
}