在Delphi 2010中高效地将单个数组转换为双数组

时间:2011-01-31 09:19:58

标签: delphi casting delphi-2010 dynamic-arrays

我需要使用稍微不同的类型在高级应用程序和低级子系统之间实现包装层:

应用程序生成一个单向量数组:

unit unApplication
type

TVector = record
  x, y, z : single;
end;

TvectorArray = array of Tvector;

procedure someFunc(): tvectorArray;
[...]

虽然子系统需要一个双向量数组。我还实现了从tvector到Tvectord的类型转换:

unit unSubSystem
type

TVectorD = record
  x, y, z : double;
  class operator Implicit(value : t3dVector):t3dvectorD;inline;
end;

TvectorDArray = array of TvectorD;

procedure otherFunc(points: tvectorDArray);

implementation 
    class operator T3dVecTorD.Implicit(value : t3dVector):t3dvectorD;
begin
  result.x := value.x;
  result.y := value.y;
  result.z := value.z;
end;

我目前正在做的是这样的:

uses unApplication, unsubsystem,...
procedure ConvertValues
var
  singleVecArr : TvectorArray;
  doubleveArr :  TvectorDArray; 
begin
  singleVecArr := somefunc;
  setlength(doubleVecArray, lenght(singlevecArr));
  for i := 0 to length(singlevecArr) -1 do
    doubleVecArray[i] := singleVecArr[i];
end;

是否有更有效的方法来执行这些转换?

3 个答案:

答案 0 :(得分:1)

首先,我会说如果没有第一次计时,你不应该尝试任何优化。在这种情况下,我并不是指对替代算法进行计时,我的意思是对相关代码进行计时,并评估在那里花费的总时间的比例。

我的直觉告诉我,您展示的代码将占总时间的一小部分,因此优化它将不会带来任何可识别的好处。我认为如果你对这个数组的每个元素做了任何有意义的事情,那么这必须是真的,因为与浮点运算相比,从单一转换为double的成本会很小。

最后,如果这个代码是一个瓶颈,你应该考虑不要转换它。我的假设是您正在使用映射到8087 FPU的标准Delphi浮点运算。所有这些浮点运算都发生在8087浮点堆栈内。值在输入时转换为64或更高,通常为80位精度。我不认为加载单个加载比加载双倍更慢 - 事实上,由于内存读取性能,它甚至可能更快。

答案 1 :(得分:1)

假设转换确实是瓶颈,那么加速转换的一种方法可能是使用SSE#而不是FPU,前提是可以假设必要的指令集存在于运行此代码的计算机。

例如,以下内容会将一个Vector转换为一个双向量:

procedure SingleToDoubleVector (var S: TVector; var D: TVectorD);
// @S in EAX
// @D in EDX
asm
  movups    xmm0, [eax]     ;// Load S in xmm0
  movhlps   xmm1,  xmm0     ;// Copy High 2 singles of xmm0 into xmm1
  cvtps2pd  xmm2,  xmm0     ;// Convert Low two singles of xmm0 into doubles in xmm2
  cvtss2sd  xmm3,  xmm1     ;// Convert Lowes single in xmm1 into double in xmm1
  movupd   [edx],  xmm2     ;// Move two doubles in xmm2 into D (.X and .Y)
  movsd    [edx+16],xmm3    ;// Move one double from xmm3 into D.Z
end;

我并不是说这段代码是最有效的方法,并且通常使用汇编代码有很多警告,特别是这段代码。请注意,此代码假设您的记录中的字段对齐。 (它没有对整个记录的对齐做出假设。)

此外,为了获得最佳效果,您可以控制数组/记录元素在内存中的对齐方式,并在汇编中编写整个转换循环,以减少开销。这是你想要/可以做的是另一个问题。

答案 2 :(得分:0)

如果无法修改源以产生双打而不是单打,则可以尝试线程化该过程。尝试将TArray分成两个或四个相等大小的块(取决于处理器数量)并让每个线程进行转换。这样做可以实现几乎两倍或四倍的速度。

此外,每次循环计算“长度”调用吗?也许把它放在变量中以避免计算。