Jump to content

pmcgee

Members
  • Content Count

    38
  • Joined

  • Last visited

Posts posted by pmcgee


  1. On 8/24/2020 at 8:08 PM, Stefan Glienke said:

    Leave implementing generic collections to people experienced with it (which I in no way claim to have monopoly on)

    To be fair, there's a Catch-22 in that idea.   ie don't implement Generics until you have experience implementing Generics.

     

    (and the same would apply for trying to use a c++ like move feature)

     

    If someone publishes open source ... not part of a (reasonably big) commercial product like RAD ... and it is useful to maybe 80% of people, then sure it's valuable to point out edge cases - but it doesn't mean it should be discouraged.  We need *more* Delphi out there.  And more understanding of these elements that weren't even part of Delphi in say 2005.

    • Like 1

  2. On 12/1/2020 at 1:52 AM, Kas Ob. said:

     the fact you are using it on only AnsiStrings will reduce its usability a lot.

    ...

    12! and waiting 15second is long time, shorter test bed will be nice

    Sure ... byte / ansichar is a simple case ... but you need to start with simple and solve it the best you can before tackling a bigger / harder problem.

     

    The testing is made faster by just using a shorter string.  The increase in time is about x10 at the 12 mark ... so 11 is quicker, and 10 is almost immediate.


  3. 8 hours ago, Kas Ob. said:

     if you already have Delphi code, then at least share the implementation, along with tests for correctness, and one or two benchmarks, many here can spot inefficient code or just suggest things that we all can benefit from.

    I'm a little confused.  First post *is* the Delphi code.

     

    I've been learning about C++ for a couple years, alongside 20 with Delphi, and the ideas from both are interesting to me.
    Naively, it seems like a Delphi version should be able to produce about the same performance.  Teasing that out should be educational.


  4. The calling code from c++ :

    int main()
    {
    	const std::string Test = "abcdefghijkl";
    	int i = 0;
    	std::string v = Test;
    
    	Timer timer;   
    	timer.start();
    	do    { ++i; }
    	while ( std::next_permutation( v.begin(), v.end() ) );
    	timer.stop();
              
    	std::cout << "C++     " << i << "\n";
    	std::cout << "Seconds: " << timer.elapsedSeconds() << std::endl;
    
    	AnsiString s = Test.c_str();
    	int len      = s.Length()+1;
    	i = 0;
    
    	Timer timer2;  
    	timer2.start();
    	do    { ++i; }
    	while ( D_next_permutation(s, 1, len ) );
    	timer2.stop();
    
    	std::cout << "Delphi  " << i << "\n";
    	std::cout << "Seconds: " << timer2.elapsedSeconds() << std::endl;
    
    	getchar();
    	return 0;

     


  5. @Kas Ob.  posted this in the original thread :

    procedure reverse2(var s: AnsiString; const a, x: word); inline;
    var
      i, j: word;
      tmpChar: Byte;
      SBytes: pByte absolute s;
    begin
      if a = x - 1 then
        exit;
      j := (x - a) shr 1;     //  trunc((x-a)/2);
      for i := 1 to j do
      begin
        tmpChar := SBytes[a - 1 + i];
        SBytes[a - 1 + i] := SBytes[x - i];
        SBytes[x - i] := tmpChar;
      end;
    end;
    
    var
      st: AnsiString;
      i: Integer;
      D: Uint64;
    
    begin
      st := '1234567890ab';
      Writeln(st);
      d := GetTickCount;
      for i := 1 to 479001600 do           // 12!
        reverse(st, 1, 12);
      D := GetTickCount - D;
      Writeln(d);
    
      st := '1234567890ab';
      Writeln(st);
      d := GetTickCount;
      for i := 1 to 479001600 do
        reverse2(st, 1, 12);
      D := GetTickCount - D;
      Writeln(d);
    
      Readln;
    end.

    With these results ... (32 bit?  64 bit? compile)
    1234567890ab
    14125
    1234567890ab
    4891

     


  6. A bit of a challenge ... to produce Delphi code equaling the performance of C++'s next_permutation.


    1162961718_nxt2(1).thumb.png.a486df34c54aaf337a26bd91acec71db.png

     

     

    Hopefully more readable in Delphi ... 

     

    unit D_Next_perm_string;
    
    interface
    
    procedure             swapCh(var a:Ansichar; var b:Ansichar);
    procedure            reverse(var s:AnsiString; const a,x:word);
    function  D_next_permutation(var s:AnsiString; const first, end_:word) : boolean;
    
    implementation
    //uses System.Diagnostics;
    
    procedure swapCh( var a : Ansichar; var b : Ansichar );   inline;
    var c :  Ansichar;
    begin
        if a<>b then begin
           c := a; a := b; b := c;
        end;
    end;
    
    
    procedure reverse(var s:AnsiString; const a,x:word);  inline;
    var
        i,j : word;
        //t   : string;
    begin                          //  x is one past the end of string
       if  a  = x-1 then exit;
       j     := ( x-a ) shr 1;     //trunc((x-a)/2);
       for i := 1 to j do
                swapCh( s[a-1+i] , s[x-i] );
    end;
    
    
    function  D_next_permutation(var s : AnsiString; const first, end_ : word) : boolean;   inline;
    var
    	i, ii, j : word;
    begin
    	if first  = end_  then begin result := false; exit; end;
    	    i    := first + 1;
    	if  i     = end_  then begin result := false; exit; end;
    	    i    := end_  - 1;
    
    	while true do begin
    	     ii := i;  dec(i);
    
    	     if s[i] < s[ii] then begin
    	          j := end_;
    	          repeat dec(j); until     s[i] < s[j];
    
    	          swapCh( s[i] , s[j] );
    	          reverse(s, ii, end_);
    	          result := true;
    	          exit;
    	     end;
    
    	     if i = first then begin
    	          reverse(s, first, end_);
    	          result := false;
    	          exit;
    	     end;
    	end;
    end;
    
    end.

    Ballpark, we're looking at about 6s vs 2s for s = "abcdefghijkl" (12 bytes).   Increases by about a factor of 10 per character beyond that.

     

    Note the c++ end() iterator is **one past the end of string**, so ... D_next_permutation(s,1,13)

     


  7. 5 minutes ago, Kas Ob. said:

    @pmcgee That swapCh caught my eye and signaled something wrong, would you care to share its implementation ?

     

    I think it can be faster but that depends on that swapChar, s is var string and the compiler in many cases will introduce an overhead for handling it and passing it further.

    While you care about the speed of 12! permutations operation, then can you check if this is faster

    
       for i := 1 to j do
         begin
           tmpChar := SBytes[a - 1 + i];
           SBytes[a - 1 + i] := SBytes[x - i];
           SBytes[x - i] := tmpChar;      
           //swapCh( s[a-1+i] , s[x-i] );
         end;

     

    I had tried a couple things there ... this was a small improvement.  I haven't pulled apart the assembly code yet.  It's just an ongoing interest.    It'll be fun to try it with char/byte array.
     

    procedure swapByte( a:Pbyte ; b:Pbyte );    inline;
    begin
        if a <> b then begin
           a^ := a^ + b^;
           b^ := a^ - b^;
           a^ := a^ - b^ ;
        end;
    end;
    
    procedure swapChar( var a : Ansichar; var b : Ansichar );   inline;
    var c :  Ansichar;
    begin
        if a<>b then begin
           c := a; a := b; b := c;
        end;
    end;

     


  8. On 11/26/2020 at 7:08 PM, A.M. Hoornweg said:

    The problem of having local variables of managed data types such as strings is that Delphi needs to guarantee that no memory leaks occur.  So there's always a hidden Try/Finally block in such methods that will "finalize" the managed variables and release any allocated heap space. That takes time to execute, even if there's no further "code" in the method.

     

    I came across this trying to duplicate C++'s std::next_permutation using Delphi.  I went through various modifications, and had left a string declaration in where it was no longer needed:

    procedure reverse(var s:AnsiString; const a,x:word);  inline;
    var
        i,j : word;
        //t   : string;
    begin                          //  x is one past the end of string
       if  a  = x-1 then exit;
       j     := ( x-a ) shr 1;     //  trunc((x-a)/2);
       for i := 1 to j do
                swapCh( s[a-1+i] , s[x-i] );
    end;

    All permutations of 12 chars = 479,001,600.  C++ = 2s.  Commenting out the string reduced the Delphi code from 9s to 6s.  (I haven't been back to it since then.)

     

    • Like 1
×