1

我正在编写自定义变体 PhysUnit,它类似于 VarConv,但更高级,不仅允许加减,还允许乘除单位,具有实数或复数,它工作正常,但速度极慢。

问题是,这个自定义变体包含了一些其他变体(简单类型,如整数或双精度,或其他自定义,如 VarComplex),因此在执行 DoAdd、DoSubtract 时,它首先检查两个操作数是否具有相同的族(例如长度),然后如果需要,添加转换其中之一的数量:

Left:=Left + Right*multiplier;

类似的东西,这里的左和右是变体。

编译器将此行转换为一系列调用:

_varCopy(tmp,Left);
_varAdd(tmp,Right*multiplier);
_varClear(Left);
_varCopy(Left,tmp);
_varClear(tmp);

而事实上,_varAdd 就足够了,无需为临时变体和所有这些变通方法分配/释放内存。

可悲的是:我不能只写 _varAdd(Left,Right),它没有在 VCL 中链接。

所以问题是:是否有可能无论如何都调用它并使其尽可能“干净”,而不会对直接内存地址进行讨厌的调用,当使用不同的选项或添加其他库进行编译时可能会发生变化?

4

2 回答 2

1

您不能调用带下划线的函数,因为编译器会将下划线转换@为无法将其用作标识符。

但是允许汇编函数调用它们。您可以使用原始声明并将其更改TVarDataVariant,因此您不必一直转换 Variants。

procedure _VarAdd(var Left: Variant; const Right: Variant);
asm
  jmp System.Variants.@VarAdd
end;

procedure _VarSub(var Left: Variant; const Right: Variant);
asm
  jmp System.Variants.@VarSub
end;

begin
  _VarAdd(Left, Right);
end;

但是,如果您想快速使用 Variants,则不是正确的方法。它们非常慢,并且没有像整数算术这样的编译器优化器提供太多帮助,在i := i + 1;不需要临时变量/cpu 寄存器的情况下进行编译。

您可以通过对常见情况使用特殊处理来加快变体:

if TVarData(Left).VType = TVarData(Right).VType then
begin
  case TVarData(Left).VType of
    varSingle:
      begin
        TVarData(Left).VSingle := TVarData(Left).VSingle + TVarData(Right).VSingle * M;
        Exit;
      end;
    varDouble:
      begin
        TVarData(Left).VDouble := TVarData(Left).VDouble + TVarData(Right).VDouble * M;
        Exit;
      end;
  end;
end;
 // use the slow function for all other cases
_VarAdd(Left, Right * M);
于 2015-09-29T09:00:44.750 回答
0

如果您想使用干净的语法,例如:

Left := Left + Right*multiplier;

那么你必须让编译器生成代码。而且由于您使用的是变体,因此生成的代码将执行得非常糟糕。

如果你想直接调用一个函数来执行操作,那么使用变体是没有意义的。您可以创建一个类型,大概是一条记录,向该类型添加一些方法,然后直接调用这些方法。

但是,如果您想创建一个支持数学运算符的类型,并且您关心性能,那么您应该在记录上使用运算符重载

于 2015-09-29T08:51:32.350 回答