Einzelnen Beitrag anzeigen

Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#7

AW: Brauche Idee, um immer wiederkehrenden Quellcode zu vermeiden.

  Alt 10. Feb 2015, 08:54
Mit den Anonymen Methoden kann man schon sehr lustige Dinge anstellen:
Delphi-Quellcode:
type
  Closure = record
    class function Memoize<T, TResult>( AFunc: TFunc<T, TResult>; AEqualityComparer: IEqualityComparer<T> = nil ): TFunc<T, TResult>; static;
  end;

class function Closure.Memoize<T, TResult>( AFunc: TFunc<T, TResult>; AEqualityComparer: IEqualityComparer<T> ): TFunc<T, TResult>;
var
  LDict: AutoRef<TDictionary<T, TResult>>; { AutoRef kapselt eine Instanz in einem Interface und sorgt für die automatische Freigabe }
begin
  LDict := TDictionary<T, TResult>.Create( AEqualityComparer );
  Result := function( Arg: T ): TResult
    begin
      if not LDict.Reference.TryGetValue( Arg, Result )
      then
        begin
          Result := AFunc( Arg );
          LDict.Reference.Add( Arg, Result );
        end;
    end;
end;
So, wozu braucht man das?
Delphi-Quellcode:
function fibonacci( n: Int64 ): Int64;
begin
  if n < 2
  then
    Result := n
  else
    Result := fibonacci( n - 1 ) + fibonacci( n - 2 );
end;

function fibonacci_memoize( n: Int64 ): Int64;
var
  fibonacci: TFunc<Int64, Int64>;
begin
  fibonacci := Closure.Memoize<Int64, Int64>(
      function( n: Int64 ): Int64
    begin
      if n < 2
      then
        Result := n
      else
        Result := fibonacci( n - 1 ) + fibonacci( n - 2 );
    end );
  Result := fibonacci( n );
end;

procedure memoize_test;
var
  LFibN, LFibResult: Int64;
  LStopwatch: TStopwatch;
begin
  LFibN := 40;
  LStopwatch := TStopwatch.StartNew;
  LFibResult := fibonacci( LFibN ); // Standard Umsatzung
  LStopwatch.Stop;
  Writeln( Format( 'fibonacci(%d) = %d (%dms)', [LFibN, LFibResult, LStopwatch.ElapsedMilliseconds] ) );

  LStopwatch := TStopwatch.StartNew;
  LFibResult := fibonacci_memoize( LFibN ); // mit Closure.Memoize
  LStopwatch.Stop;
  Writeln( Format( 'fibonacci(%d) = %d (%dms)', [LFibN, LFibResult, LStopwatch.ElapsedMilliseconds] ) );
end;
Beide berechnen exakt die gleichen Werte, spannend sind jetzt die Laufzeiten
Code:
fibonacci(40) = 102334155 (1101ms)
fibonacci(40) = 102334155 (0ms)

fibonacci(100) = (dauert mir zu lange)
fibonacci(100) = 3736710778780434371 (0ms)
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat