Delphi 如何对任意大小的整数执行算术?

Delphi 如何对任意大小的整数执行算术?,delphi,delphi-7,Delphi,Delphi 7,我的原始代码在这里 function AddNumStrings(Str1, Str2: string): string; var i: integer; carryStr: string; worker: integer; workerStr: string; begin Result:= inttostr(length(Str1)); Result:= ''; carryStr:= '0'; // make numbers the same length

我的原始代码在这里

function AddNumStrings(Str1, Str2: string): string;
var
  i: integer;
  carryStr: string;
  worker: integer;
  workerStr: string;
begin
  Result:= inttostr(length(Str1));
  Result:= '';
  carryStr:= '0';

  // make numbers the same length
  while length(Str1) < length(Str2) do Str1:= '0' + Str1;
  while length(Str1) > length(Str2) do Str2:= '0' + Str2;

  i:= 0;
  while i < length(Str1) do begin
    worker:= strtoint(copy(Str1, length(Str1) - i, 1)) + strtoint(copy(Str2, length(Str2) - i, 1)) + strtoint(carryStr);
    if worker > 9 then begin
      workerStr:= inttostr(worker);
      carryStr:= copy(workerStr, 1, 1);
      Result:= copy(workerStr, 2, 1) + Result;
    end else begin
      Result:= inttostr(worker) + Result;
      carryStr:= '0';
    end;

    inc(i);
  end; { while }
  if carryStr <> '0' then Result:= carryStr + Result;
  Application.ProcessMessages;
end;

function yeni(s1, s2: string): string;
var
  j, i, k: integer;
  c: char;
  s: string;
begin
  k:= length(s2);
  j:= length(s1) - length(s2);
  for i:= j downto 1 do begin
    c:= s1[i];
    k:= k + 1;
    if (c <> '9') and (c <> '0') then begin
      s:= copy(s1, i, k);
      s:= AddNumStrings(s, s2);
      Setlength(s1, i - 1);
      Result:= s1 + s;
      break;
    end;

    Application.ProcessMessages;
  end;

  procedure TForm1.Button13Click(Sender: TObject);
  var
    i, k: integer;
    s: Ansistring;
  begin
    s:= '1111';
    for i:= 1 to 1000000 do begin
      for k:= 1 to 120 do begin
        s:= yeni(s, '4');
      end;
    end;
  end;

end.
函数addNumString(Str1,Str2:string):string;
变量
i:整数;
卡里斯特:弦;
工作者:整数;
workerStr:字符串;
开始
结果:=inttostr(长度(Str1));
结果:='';
carryStr:=“0”;
//使数字长度相同
而长度(Str1)length(Str2)做Str2:=“0”+Str2;
i:=0;
当我9,则开始
workerStr:=inttostr(工人);
carryStr:=副本(workerStr,1,1);
结果:=复制(workerStr,2,1)+结果;
结束,否则开始
结果:=inttostr(工人)+结果;
carryStr:=“0”;
终止
公司(一);
终止{while}
如果carryStr“0”,则结果:=carryStr+Result;
Application.ProcessMessages;
终止
函数yeni(s1,s2:string):string;
变量
j、 i,k:整数;
c:半焦;
s:字符串;
开始
k:=长度(s2);
j:=长度(s1)-长度(s2);
对于i:=j向下至1,开始
c:=s1[i];
k:=k+1;
如果是(c'9')和(c'0'),则开始
s:=副本(s1,i,k);
s:=AddNumStrings(s,s2);
设定长度(s1,i-1);
结果:=s1+s;
打破
终止
Application.ProcessMessages;
终止
程序TForm1.按钮13点击(发送方:TObject);
变量
i、 k:整数;
s:翻译;
开始
s:='1111';
对于i:=1到1000000,开始
对于k:=1到120,开始
s:=yeni(s,'4');
终止
终止
终止
终止
最后,我的字符串
s
长度必须为100000000。但我想这需要68天。
如何加速此代码

您的代码被的变体阻塞了。每次这样添加两个字符串时,Delphi RTL都必须增加字符串的大小,这可能涉及分配一个新的、更大的字符串并复制旧字符串,然后释放旧字符串。当你这样做1000万次时,所有的内存复制和重新分配都会累加起来


要使其快速运行,您需要做的是预先计算完成的字符串的长度,然后在
s
上调用
SetLength
,并从一开始就分配大字符串。之后,跟踪尚未“填充”的最高字符的索引。每个
IntToStr
调用都将生成一个新字符串;插入
|
字符,然后将
IntToStr
结果复制过来,同时更新索引。这将大大减少代码运行所需的时间。

显然,这是一个愚蠢的示例,但您可以做以下几件事:

  • 知道调用Delphi函数时会发生什么
  • 了解你的数据
  • 把东西移到圈外
  • 除非可以预测,否则不要跳
  • 让我详细说明一下

    知道调用Delphi函数时会发生什么 调用RTL函数时,如
    string:=string+someotherstring

    Delphi将执行
    concat
    操作。这涉及调整字符串分配的大小(如果需要)并将字符串(如果需要)移动到内存中的新位置。
    如果您多次这样做,所有的存储分配都将开始累积。事实上,如果您将函数的运行次数翻倍到20000000次,您会发现运行时的运行次数会翻倍以上。
    因此,您可以避免这种胡说八道,并将那些代价高昂的函数移出循环

    了解您的数据
    只要
    s[index]=0
    ,任何乘法都将为0。你可以利用这些知识大大加快速度。有人称之为欺骗;在这种情况下,这可能是正确的,但在更复杂的情况下,了解数据将做什么可以让您获得非常好的加速。
    此外,您知道将一位数字乘以九永远不会产生大于81的结果,因此您不需要检查超过2个字符

    将内容移出循环
    一旦你知道了你的数据,你就可以把数据从循环中移出,所以你不需要做很多次,只需要做一次。
    即使循环外的东西比循环内的东西花费的时间长10000倍。这仍然是一笔不错的交易

    除非可以预测,否则不要跳转
    在这种情况下,这不适用,因为函数在输出稳定的零流时会很快稳定下来,但我还是将其放入演示中。
    事实上,这里的
    if
    比no
    if
    更快,因为跳转打破了依赖链

    代码示例

    procedure TForm1.Button4Click(Sender: TObject); 
    const
      NumberOfCharsForKToSettleTo0 = 10;
      ManyTimes = 10 * 1000 * 1000 
    var
      i,j,k,l:integer;
      s:string;
    begin
      //preallocate the length of the string
      SetLength(s, 4 + (ManyTimes * length('|1')) + NumberOfCharsForKToSettleTo0);
      s:='1369';
      l:= 4;
      for i:=1 to ManyTimes do begin
        j:=i mod 9;
        //k:=strtoint(s[Length(s)])*j; don't use strtoint
        k:= ord(s[l]) - ord('0');
        k:= k*j;
        //s:=s+'|'+inttostr(k);
        inc(l);
        s[l]:= '|';
        inc(l);
        s[l]:= chr(k div 10+ord('0'));
        inc(l,integer(k>9));  //avoid jumps/ifs that are hard to predict.
        s[l]:= chr(k+ord('0'));
      end;
    end;
    

    您正在尝试使用字符串执行任意精度的算术运算。
    这是个坏主意

    改用bigint库。 它使用整数数组来执行此任务。
    一个不错的可在以下网站下载:


    或者根据LURD的建议:

    预先分配整个字符串,然后填写内容。如果您学会了如何缩进代码,可能会有所帮助。如果你没有问如何快速完成愚蠢的、毫无意义的任务,而是告诉我们真正的问题,这也会有所帮助。可能重复的“请勿在其他帐户下再次发布相同的问题”。相反,编辑并改进你的内容,这样我们就可以知道你在问什么。@DavidHeffernan:要知道他想做什么并不难,说真的,这一切真的有必要吗?如果你把一半的精力投入到侮辱和贬低这张海报上,而实际上是想帮助他,那么你现在已经找到了答案…@mason回答这个问题很容易。可以在编译时计算字符串!这不是一个正确的问题。提问者说真正的问题是不同的。肯已经给出了和你一样的答案,基本上是在他问同样的问题时。除非我们告诉他问正确的问题,否则他会一直问同一个问题