DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: bluewind23
今日帖子: 0
在线用户: 4
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 ken0137 (顺眼即佛) ★☆☆☆☆ -
普通会员
2024/7/8 9:31:14
标题:
有什么方法可以动态计算平均值 浏览:623
加入我的收藏
楼主: 有什么方法可以动态计算平均值,就是又快又准
是这样的,一个串口不停的接收数据(20ms),需要动态计算100个连续数据的平均值显示出来
比如
第1个数据到第100个数据的平均值,
第2个数据到第101个数据的平均值,
第3个数据到第102个数据的平均值,
第4个数据到第103个数据的平均值,
以此类推
这样的数据连续计算出来
----------
我想着要么,就是数组要么就是Tstringlist,
数组(A)就是设定100个,1-100,到100时先计算平局值Av
然后第101个数据A101时,Av+abs((A[1]-A101)/100)
将A[1]=A101,以此类推
----------
Tstringlist时,当ST.Count=100时计算Av
然后第101个数据A101时,Av+abs((ST[0]-A101)/100)
增加一个新的数据ST.add(A101),
删除第一个数据ST.Delete(0);
但这种效率是否比较低?
----------------------------------------------
只会简单使用,并未精通深入
作者:
男 wj2310 (wj2310) ★☆☆☆☆ -
普通会员
2024/7/8 9:49:57
1楼: 在程序里面加一个timer控件,然后申明一个数组,在timer事件里面把接收的数据,存入数组,然后通过数组进入计算平均值的计算,得出结果后,把数组清空,准备下一次的接收,如果有困难可以加我qq:331654307
----------------------------------------------
wj2310
作者:
男 jwj76 (禁卫) ▲△△△△ -
普通会员
2024/7/8 9:52:14
1楼: var
  pdata:PInteger;//读取数据
  pdataLen:Integer;//数据长度
  vdata:Single;//平均值
  i,temp:Integer;
begin
  pdata:=AllocMem(pdataLen);
  //读取数据.....
  for i:=0 to pdataLen-1 do
  begin
    temp:=pdata[i];
  end;
  vdata:=temp/pdataLen;
  Freememory(pdata);
end;
----------------------------------------------
-
作者:
男 supermay (supermay) ★☆☆☆☆ -
盒子活跃会员
2024/7/8 10:25:06
2楼: 设计一个环形的缓冲区,每收到一个数据就往里面写,当abs(end-start)=99就统计里面的数据

//**********
//  @author  Freeman
//  @version Ver1.0
//  @DateTime 2010-3-25 9:51:29
//  @todo
//  @comment 本单元根据楠楠的修改而来
//**********
//==========
// 本单元包含一个环型缓冲区类
//==========

unit uCircularBuffer;

interface

uses
  Windows, SyncObjs;

const
  //默认缓冲区大小
  DEFAULT_CIRCULAR_BUFFER_SIZE = 1024 * 8; //8k

type
  TCircularBuffer = class(TObject)
  private
    FBuffferSize: Integer;
    FCirBufferLock: TSynchroObject;
    FHeadPos: Integer;
    FpBuffer: PByte;
    FTailPos: Integer;
    FThreadSafeFlag: Boolean;
    procedure BufferResize;
    function HeadPosInc(nStep: Integer): Boolean;
    function IsIndexOverFlow(nLen: Integer): Boolean;
    function IsOverFlowBuffer(nLen: Integer): Boolean;
    procedure Lock;
    procedure UnLock;
  public
    {----------
      过程名:    Create
      过程作用:  构造函数
      作者:      Administrator
      日期:      2010.03.25
      参数:      BufferSize: Cardinal 缓冲区大小
      返回值:    无
    ----------}
    constructor Create(BufferSize: Cardinal);
    {----------
      过程名:    Destroy
      过程作用:  析构函数
      作者:      Administrator
      日期:      2010.03.25
      参数:      无
      返回值:    无
    ----------}
    destructor Destroy; override;
    {----------
      过程名:    GetBufferData
      过程作用:  读取数据,仅仅读出数据,并不移动环形Buffer指针
      作者:      Administrator
      日期:      2010.03.25
      参数:      pBuffer: PChar; BufLen: Integer
      返回值:    无
    ----------}
    procedure GetBufferData(pBuffer: Pansichar; BufLen: Integer);
    {----------
      过程名:    GetValidCount
      过程作用:  得到有效缓冲区大小(已占用)
      作者:      Administrator
      日期:      2010.03.25
      参数:      无
      返回值:    Integer
    ----------}
    function GetValidCount: Integer;
    {----------
      过程名:    ReadCirBuffer
      过程作用:  从环形Buffer读出数据(移动位置)
      作者:      Administrator
      日期:      2010.03.25
      参数:      pOutBuffer: PChar
      返回值:    Integer
    ----------}
    function ReadCirBuffer(pBuffer: PChar): Integer;
    {----------
      过程名:    SetPosition
      过程作用:  移动位置,
      作者:      Administrator
      日期:      2010.03.25
      参数:      APos: Integer 偏移量
      返回值:    无
    ----------}
    procedure SetPosition(APos: Integer);
    {----------
      过程名:    WriteCirBuffer
      过程作用:  向环形Buffer写入数据
      作者:      Administrator
      日期:      2010.03.25
      参数:      pBuffer: PChar; BufLen: Integer
      返回值:    无
    ----------}
    procedure WriteCirBuffer(pBuffer: PAnsiChar; BufLen: Integer);
    {----------
      过程名:    SetEmpty
      过程作用:  置空数据,从0开始写数据
      作者:      Administrator
      日期:      2010.03.25
      参数:      无
      返回值:    无
    ----------}
    procedure SetEmpty;

    //是否线程安全
    property ThreadSafe: Boolean read FThreadSafeFlag write FThreadSafeFlag;
  end;
implementation

uses
  SysUtils;

{
********** TCircularBuffer **********
}

constructor TCircularBuffer.Create(BufferSize: Cardinal);
begin
  inherited Create;
  FThreadSafeFlag := FALSE;
  //创建临界
  FCirBufferLock := TCriticalSection.Create;

  if BufferSize = 0 then
  begin
    FBuffferSize := DEFAULT_CIRCULAR_BUFFER_SIZE;
  end
  else
  begin
    FBuffferSize := BufferSize;
  end;

  FpBuffer := nil;

  //分配空间
  GetMem(FpBuffer, FBuffferSize);
  ZeroMemory(FpBuffer, FBuffferSize);

  FHeadPos := 0;
  FTailPos := 0;
end;

destructor TCircularBuffer.Destroy;
begin
  if Assigned(FpBuffer) then
  begin
    Lock;
    try
      FreeMem(FpBuffer, FBuffferSize);
    finally
      UnLock;
    end;
  end;

  if Assigned(FCirBufferLock) then
    FreeAndNil(FCirBufferLock);

  inherited Destroy;
end;

procedure TCircularBuffer.BufferResize;
var
  pNewBuffer: PByte;
  PrevBufSize: Integer;
begin
  Lock;
  try
    //得到原环形Buffer大小
    PrevBufSize := FBuffferSize;
    FBuffferSize := FBuffferSize shl 1;

    //分配2倍大小缓冲
    GetMem(pNewBuffer, FBuffferSize);
    ZeroMemory(pNewBuffer, FBuffferSize);

    //拷贝原数据到新分配的缓冲区位置
    CopyMemory(Pointer(LongInt(pNewBuffer)),
      Pointer(LongInt(FpBuffer)),
      PrevBufSize);

    //如果尾小于头,说明已经FBuffferSize之后从索引0开始到m_iTailPos之间是
    //上一个环形Buffer的数据(mod之后),现在因为缓冲区变大,这部分数据应
    //该放在真正的m_nPrevBufSize大小之后。
    if (FTailPos < FHeadPos) then
    begin
      //目的缓冲区位置:m_pNewBuffer+PrevBufSize
      CopyMemory(Pointer(LongInt(pNewBuffer) + PrevBufSize),
        Pointer(LongInt(FpBuffer)),
        FTailPos);
      //修改尾位置
      FTailPos := FTailPos + PrevBufSize;
    end;

    //释放原缓冲区数据
    FreeMem(FpBuffer, PrevBufSize);
    FpBuffer := pNewBuffer;

  finally
    UnLock;
  end;
end;

procedure TCircularBuffer.GetBufferData(pBuffer: Pansichar; BufLen: Integer);
var
  FirstCopySize: Integer;
  SecondCopySize: Integer;
begin
  if not ((BufLen > 0) and (BufLen <= GetValidCount)) then
    Exit;

  Lock;
  try
    //1 2 3 4 5  FBuffferSize = 5  FHeadPos = 3  BufLen =1时
    //即长度在FHeadPos之内的,可一次拷贝完整
    //如果长度在(FBuffferSize - FHeadPos)为
    if (BufLen < FBuffferSize - FHeadPos) then
    begin
      CopyMemory(Pointer(LongInt(pBuffer)),
        Pointer(LongInt(FpBuffer) + FHeadPos),
        BufLen);
    end
    else
    begin
      //1 2 3 4 5  FBuffferSize = 5  FHeadPos = 3  BufLen =4时
      FirstCopySize := FBuffferSize - FHeadPos;
      SecondCopySize := BufLen - FirstCopySize;

      CopyMemory(Pointer(LongInt(pBuffer)),
        Pointer(LongInt(FpBuffer) + FHeadPos),
        FirstCopySize);

      if (SecondCopySize > 0) then
      begin
        CopyMemory(Pointer(LongInt(pBuffer) + FirstCopySize),
          Pointer(LongInt(FpBuffer)),
          SecondCopySize);
      end;
    end;

  finally
    UnLock;
  end;
end;

function TCircularBuffer.GetValidCount: Integer;
var
  ValidCount: Integer;
begin
  Lock;
  try
    ValidCount := FTailPos - FHeadPos; //尾部-头部
    if (ValidCount < 0) then
      ValidCount := FBuffferSize + ValidCount;
    Result := ValidCount;
  finally
    UnLock;
  end;
end;

function TCircularBuffer.HeadPosInc(nStep: Integer): Boolean;
begin
  Result := FALSE;
  if (nStep <= GetValidCount) then
  begin
    FHeadPos := FHeadPos + nStep;
    FHeadPos := FHeadPos mod FBuffferSize;
    Result := FHeadPos <> FTailPos;
  end;
end;

function TCircularBuffer.IsIndexOverFlow(nLen: Integer): Boolean;
begin
  Lock;
  try
    Result := nLen + FTailPos >= FBuffferSize;
  finally
    UnLock;
  end;
end;

function TCircularBuffer.IsOverFlowBuffer(nLen: Integer): Boolean;
begin
  Lock;
  try
    Result := nLen >= FBuffferSize - GetValidCount();
  finally
    UnLock;
  end;
end;

procedure TCircularBuffer.Lock;
begin
  if FThreadSafeFlag then
    FCirBufferLock.Acquire;
end;

function TCircularBuffer.ReadCirBuffer(pBuffer: PChar): Integer;
var
  VaildLen: Integer;
  FirstCopySize: Integer;
  SecondCopySize: Integer;
begin
  Lock;
  try
    VaildLen := GetValidCount;
    //有效数据>长度-头定位情况下,说明需要二次拷贝
    if (VaildLen > (FBuffferSize - FHeadPos)) then
    begin
      //尾部需要拷贝的长度
      FirstCopySize := FBuffferSize - FHeadPos;
      //头部需要拷贝的长度
      SecondCopySize := FTailPos;

      //拷贝尾部数据
      CopyMemory(Pointer(LongInt(pBuffer)),
        Pointer(LongInt(FpBuffer) + FHeadPos),
        FirstCopySize);

      if (SecondCopySize > 0) then
      begin
        //拷贝头部数据
        CopyMemory(Pointer(LongInt(pBuffer) + FirstCopySize),
          Pointer(LongInt(FpBuffer)),
          SecondCopySize);
      end;

      //头部移动到相应位置
      FHeadPos := SecondCopySize;
    end
    else
    begin
      CopyMemory(Pointer(LongInt(pBuffer)),
        Pointer(LongInt(FpBuffer) + FHeadPos),
        VaildLen);

      FHeadPos := FHeadPos + VaildLen;
      if (FHeadPos = FBuffferSize) then
        FHeadPos := 0;
    end;

    Result := VaildLen;

  finally
    UnLock;
  end;

end;

procedure TCircularBuffer.SetEmpty;
begin
  FHeadPos := 0;
  FTailPos := 0;
end;

procedure TCircularBuffer.SetPosition(APos: Integer);
var
  iLen: Integer;
begin
  Lock;
  try
    iLen := FHeadPos + APos;
    FHeadPos := iLen mod FBuffferSize;

    //移动位置超过已有数据长度,则设置空的数据使用长度
    if FTailPos <= iLen then
      FTailPos := FHeadPos;
  finally
    UnLock;
  end;
end;

procedure TCircularBuffer.UnLock;
begin
  if FThreadSafeFlag then
    FCirBufferLock.Release;
end;

procedure TCircularBuffer.WriteCirBuffer(pBuffer: PAnsiChar; BufLen: Integer);
var
  FirstCopySize: Integer;
  SecondCopySize: Integer;
begin
  if BufLen <= 0 then
    Exit;

  Lock;
  try
    while IsOverFlowBuffer(BufLen) do
      BufferResize;
    if IsIndexOverFlow(BufLen) then
    begin
      //尾部需要拷贝的长度
      FirstCopySize := FBuffferSize - FTailPos;
      //头部需要拷贝的长度
      SecondCopySize := BufLen - FirstCopySize;

      //拷贝到尾
      CopyMemory(Pointer(LongInt(FpBuffer) + FTailPos),
        Pointer(LongInt(pBuffer)),
        FirstCopySize);

      if (SecondCopySize > 0) then
      begin
        //拷贝到头
        CopyMemory(Pointer(LongInt(FpBuffer)),
          Pointer(LongInt(pBuffer) + FirstCopySize),
          SecondCopySize);
        FTailPos := SecondCopySize;
      end
      else
        FTailPos := 0;
    end
    else
    begin
      //如果未溢出,直接把数据附加到尾部
      CopyMemory(Pointer(LongInt(FpBuffer) + FTailPos),
        Pointer(LongInt(pBuffer)),
        BufLen);
      FTailPos := FTailPos + BufLen;
    end;

  finally
    UnLock;
  end;
end;

end.
----------------------------------------------
链接:https://pan.baidu.com/s/12jzmECYKhGCsHBxz8tmB6w 提取码:pelr --来自百度网盘超级会员V9的分享
作者:
男 sail2000 (小帆工作室) ★☆☆☆☆ -
盒子活跃会员
2024/7/8 10:49:22
3楼: TStringList 有 OnChange 事件,未满100,则统计全部,满100,则统计 Count - 1至倒数100个,还可以满例如200则保留最后100个数,其它无用的数据清掉。
----------------------------------------------
delphi 是兴趣,和工作无关,即使它倒闭。又不靠它 delphi 吃饭,怕甚?
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2024/7/8 11:23:18
4楼: TQueue<integer>
前面100个数Push以后求总和S
后面每来一个新数据Y,
先pop出来最老的数据X,Sum-=X;
再Push进来Y,Sum+=Y
Average=S/100;
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2024/7/8 11:27:20
5楼: 4 楼的办法最简单。用 TStringList 当作环形缓冲区用也不是不可以,就是稍微麻烦点。4楼直接使用 Delphi 提供的 TQueue 就使得代码更简单。
----------------------------------------------
-
作者:
男 huangyalei (huangyalei) ★☆☆☆☆ -
盒子活跃会员
2024/7/8 12:15:26
6楼: 哪用这么复杂,简单的四则运算就可以了
第一次先将1加到100存储为A,平均数=A/100
第二次开始A减去第一个元素值,再加上新增的元素值,还是存储为A,平均数=A/100
----------------------------------------------
-
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2024/7/8 13:54:46
7楼: 带了临界区的话,环形缓冲区就没必要了,直接用数组或者队列就行,每到一百个数据计算完就删除就行了。
计算的话也不会太麻烦,四则运算就行。
如果数据是顺序的,还可以有简便的方法来计算。如果是无序的数字,那就只能用笨办法了。

只是很久不折腾串口了,不过记忆里串口也会有与tcp一样所谓“粘包”与“分包”的情况,所以收数据要注意一下,一般的串口数据包都会有包头、包尾、以及校验位。
如果只是持续不断的传数据的话,那怎么校验数据包是一个问题。
----------------------------------------------
--
作者:
男 zhaoyf (zyf) ★☆☆☆☆ -
普通会员
2024/7/8 19:52:40
8楼: Tstringlist的效率肯定没有数组高
楼主的数组方法中不应该用ABS
而且用 平均值+差值/100
后面会有浮点数的累加误差
应该 (S + A101 - A[1]) / 100
S是100个数的和
----------------------------------------------
-
作者:
男 wk_knife (wk_knife) ★☆☆☆☆ -
盒子活跃会员
2024/7/9 15:12:07
9楼: 提问:delphi 滑动平均
下面是百度的回答:
在Delphi中实现滑动平均,通常可以通过维护一个固定大小的缓冲区来完成,每次添加新的数据时,从缓冲区尾部移除最旧的数据。然后计算缓冲区内所有数据的平均值。

以下是一个简单的实现例子:

type
  TSlidingAverage = class
  private
    FBuffer: array of Double;
    FCount: Integer;
    FCapacity: Integer;
    FSum: Double;
    function GetAverage: Double;
    procedure SetCapacity(Value: Integer);
  public
    constructor Create(Capacity: Integer);
    procedure AddValue(Value: Double);
    property Average: Double read GetAverage;
    property Capacity: Integer read FCapacity write SetCapacity;
  end;
 
implementation
 
constructor TSlidingAverage.Create(Capacity: Integer);
begin
  SetCapacity(Capacity);
end;
 
procedure TSlidingAverage.SetCapacity(Value: Integer);
begin
  if Value < 1 then
    raise Exception.Create('Capacity must be greater than 0.');
  FCapacity := Value;
  SetLength(FBuffer, FCapacity);
  FCount := 0;
  FSum := 0;
end;
 
procedure TSlidingAverage.AddValue(Value: Double);
begin
  if FCount = FCapacity then
  begin
    Dec(FSum, FBuffer[0]);
    FBuffer[0] := Value;
    // Shift buffer
    Move(FBuffer[1], FBuffer[0], (FCapacity - 1) * SizeOf(Double));
  end
  else
    Inc(FCount);
  FSum := FSum + Value;
end;
 
function TSlidingAverage.GetAverage: Double;
begin
  if FCount = 0 then
    Result := 0
  else
    Result := FSum / FCount;
end;

使用方法:

var
  SlidingAverage: TSlidingAverage;
  NewValue: Double;
begin
  SlidingAverage := TSlidingAverage.Create(10); // 10为滑动窗口大小
  try
    // 添加数据
    NewValue := ...; // 获取新数据
    SlidingAverage.AddValue(NewValue);
 
    // 获取平均值
    ShowMessage(Format('Average: %.2f', [SlidingAverage.Average]));
  finally
    SlidingAverage.Free;
  end;
end;

这个实现中,TSlidingAverage类维护了一个缓冲区FBuffer,一个计数FCount,一个总和FSum,以及一个容量FCapacity。AddValue方法用于添加新数据,并且会更新平均值。当缓冲区满时,最老的数据会被移除,从而保持缓冲区大小不变。GetAverage方法计算并返回平均值。
----------------------------------------------
-
作者:
男 bighawk (Hawk) ★☆☆☆☆ -
盒子活跃会员
2024/7/9 15:38:35
10楼: 这是标准的先进先出数据结构,简化一下就是搞个链表,从头部删除,从尾部加入。如下:
uses unitDDLinkList;

type
  TDataType = integer;

  TDataItem = class(TDoubleDirLinkListItem)
  private
    FData: TDataType;
  public
    property Data: TDataType read FData;
  end;

  TDataPool = class(TCriticalDDLLItem)
  private
    FMaxDataCount: integer;
    FAveValue: Double;
  public
    procedure Reset; override;
    procedure AddData(Data: TDataType);

    property MaxDataCount: integer read FMaxDataCount write FMaxDataCount;
    property AveValue: Double read FAveValue;
  end;

implementation

{ TDataPool }

procedure TDataPool.AddData(Data: TDataType);
var
  tmp: TDataItem;
  all: Double;
begin
  tmp := TDataItem.Create;
  tmp.FData := Data;
  AppendItem(tmp);
  while Count > FMaxDataCount do
    Item[0].Free;
  all := 0;
  tmp := TDataItem(Item[0]);
  while tmp <> nil do
  begin
    all := all + tmp.FData;
    tmp := TDataItem(tmp.Next);
  end;
  FAveValue := all / Count;
end;

procedure TDataPool.Reset;
begin
  inherited;
  FMaxDataCount := 100;
  FAveValue := 0;
end;

自己实例化 TDataPool 即可,通过属性 MaxDataCount 设置容纳的最大数据量,修改一下 TDataType 的类型,TDataPool 自带临界段,可以多线程环境下安全使用它。
unitDDLinkList 这个单元请到 https://gitee.com/bighawk/unifi-platform/blob/master/Common/unitDDLinkList.pas ;获取。
----------------------------------------------
-
作者:
男 zhangshelly (雪莱) ★☆☆☆☆ -
盒子活跃会员
2024/7/9 15:46:47
11楼: 哪有那么麻烦的,定义100长度的数组Arr,一个整数变量P,一个总数S,也不用移动内存,来个新的数,S=S-Arr[p]+N  ;Arr[p]:=N; if P=99 then p:=0 else inc(p)
----------------------------------------------
-
作者:
男 bighawk (Hawk) ★☆☆☆☆ -
盒子活跃会员
2024/7/9 15:56:18
12楼: 环形缓冲区的一大问题就是需要记录起始和终止指针,对最终使用者而言不大友好;调试起来也麻烦
----------------------------------------------
-
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2024/7/9 18:31:35
13楼: 就开一个1000长的数组难道就能罚款么?一个这么简单的需求为什么会搞的这么复杂?
一直纠结这么复杂的算法,但实际上提升又不高,反倒增加了开发与维护成本,何必呢?性能瓶颈了么?
而且环形缓冲区完全可以把起止位置什么的这些内部细节全部封装起来,对调用方而言,与一般的队列完全没什么区别。

反倒是需要注意的地方却全部被忽略了。

还是先实现功能吧~
----------------------------------------------
--
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2024/7/9 20:55:16
14楼: 13楼说得不错。这里那么多层楼,我看最简单的是使用 TQueue
----------------------------------------------
-
作者:
男 ken0137 (顺眼即佛) ★☆☆☆☆ -
普通会员
2024/7/9 23:54:37
15楼: @zhaoyf (zyf)
谢谢,我已经发现错误所在了
----------------------------------------------
只会简单使用,并未精通深入
作者:
男 dorry (littlecat) ★☆☆☆☆ -
盒子活跃会员
2024/7/10 10:11:28
16楼: 你这个不就是滑动均值滤波算法吗?

以下是单片机的程序。C 改过来的。未实测!

const
  FilterCount=100;//滤波次数 100

var
  Buffer:array[0..FilterCount-1] of real;

function MoveAverageFilter(Value:Real):Real; var
  i:Integer;
  filter_sum:Real;
begin
  if (FilterCount=0) then begin
     Result:=Value;
     Exit;
  end;
  Buffer[FilterCount]:= value;
  filter_sum:=0;
  for i:=0 to FilterCount-1 do begin
     Buffer[i]:= Buffer[i+1];
     filter_sum:=filter_sum+Buffer[i+1];
  end;
  Result:=filter_sum/FilterCount;
end;
----------------------------------------------
泱泱华夏十亿兵,国耻期待儿孙平,愿提十万虎狼旅,跃马扬刀灭东京!
作者:
男 yayongm (昵  称) ★☆☆☆☆ -
盒子活跃会员
2024/7/10 11:41:54
17楼: 每次计算量很小,随便折腾都行:
1,0..99这个数组你只管添加管理数据就行.就两句代码:
  Move 数组[1], 数组[0], SizeOf(数组类型)*99
  数组[99] := 新数值
2,计算时:(上次的总和-数组[0]+数组[100])/100即可,速度很快的.

==========
上述整个计算量在汇编代码上应该不会超过20个汇编指令,所以速度应该是绝对没问题的.
----------------------------------------------
弱小和无知不是生存的障碍,傲慢才是!
作者:
男 ybj316 (ybj) ★☆☆☆☆ -
盒子活跃会员
2024/7/10 13:32:19
17楼: 这也叫  移动平均值 ,在计算股票指标上经常用到 。用TQueue  是最简单的 ,D7也支持!
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行50.29297毫秒 RSS