0

ここに私の元のコード..

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.

最後に、文字列sの長さを 1,000,000,000 にする必要があります。しかし、68日かかると思います。このコードを高速化するにはどうすればよいですか?

4

3 に答える 3

3

文字列を使用して任意精度の演算を実行しようとしています。
これは悪い考えです。

代わりに bigint ライブラリを使用してください。整数の配列を使用してジョブを実行します。
すばらしいものは、http ://www.delphiforfun.org/Programs/Library/big_integers.htm からダウンロードできます。

または、LURD の提案: https://code.google.com/p/gmp-wrapper-for-delphi/

于 2013-10-23T20:24:16.197 に答える
1

明らかにこれはばかげた例ですが、できることがいくつかあります。

  1. Delphi 関数を呼び出すと何が起こるかを理解する
  2. データを知る
  3. ループの外に物を移動する
  4. 予測可能でない限りジャンプしないでください

詳しく説明しましょう

Delphi 関数を呼び出すと何が起こるかを理解
する RTL 関数を呼び出すと、string:= string + someotherstring
Delphi と同様に操作が実行されconcatます。これには、文字列割り当てのサイズ変更 (必要な場合) と、文字列のメモリ内の新しい場所への移動 (必要な場合) が含まれます。
これを何度も行うと、すべてのストレージ割り当てが加算され始めます。実際、関数を 20,000,000 回実行すると、実行時間が 2 倍以上になることがわかります。
したがって、このナンセンスを回避し、コストのかかる関数をループの外に移動します。

自分のデータを知る
掛け算は すぐs[index] = 0に 0 になります。この知識を使用して、物事を大幅に高速化できます。これを不正行為と呼ぶ人もいます。この場合は正しいかもしれませんが、より複雑なケースでは、データが何をするかを知っていると、非常に高速になります。
さらに、1 桁に 9 を掛けても 81 を超える結果は得られないことがわかっているため、2 文字を超える数をチェックする必要はありません。

ループから何か
を移動する データがわかったら、ループから何かを移動できるので、何度も実行するのではなく、1 回だけ実行します。
ループの外側のものは、ループの内側のものよりも 10,000 倍長くかかる場合でも。まだまだお得です。

予測可能でない限りジャンプしないでください
。この場合、関数はゼロの安定したストリームを出力するとすぐに安定するため、これは当てはまりませんが、とにかくデモンストレーションの目的で入れました。
実際、ジャンプは依存関係の連鎖を断ち切るため 、 ifhere は 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;
于 2013-10-23T19:34:08.167 に答える