Fortran移动平均子程序类型判定及调用越界问题咨询
移动平均类型判定及调用代码的越界问题分析
一、判定移动平均类型
咱们先直接给出结论:这个ma子程序实现的是滞后移动平均(trailing moving average),理由如下:
先看修正语法后的核心代码(原代码的{}替换为Fortran标准的then/end if):
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) end do ave(1) = v/flen if (newn>1) then 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 end do end if return end
从计算逻辑拆解:
- 第一个输出值
ave(1)是用输入数组x的前len个元素(x(1)到x(len))计算得到的,对应窗口结束在x(len)的位置; - 后续的
ave(j)(j从2到newn)每次把窗口向右滑动一位:去掉窗口最左侧的旧值x(m),加入窗口右侧的新值x(k),最终ave(j)对应的是x(j)到x(j+len-1)的平均。
所有计算都只用到当前点及之前的元素,完全没有包含任何未来的点,既不符合居中移动平均(需要当前点前后元素)的逻辑,也和超前移动平均(依赖未来点)无关,完全符合滞后移动平均的定义。
二、调用代码的数组越界问题
再来看fts子程序的调用逻辑:
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
根据补充说明,调用ma时传入的数组x实际长度是n-2*np,但ma子程序的计算会直接访问到x(n)的位置,必然触发越界:
以第一次调用ma(x,n,np,trend)为例,ma里的newn = n - np +1,第二个循环中k的最终值是len + (newn -1) = np + (n - np +1 -1) = n,但x的实际长度只有n-2*np(显然n > n-2*np,因为np是正整数),当k超过n-2*np时,就会访问到x数组的越界位置,引发内存访问错误。
举个具体例子:如果n=10,np=2,那么x的实际长度是10-2*2=6,但ma里会尝试访问x(10),这显然超出了x的合法范围。
内容的提问来源于stack exchange,提问作者A0A
相关产品推荐
相关产品推荐

