Board index » delphi » String Functions

String Functions


2005-04-30 08:56:17 PM
delphi252
Hi
Maybe im wrong but werent there function replacements for INtToStr and
FloatToStr in the fastcode challenges ?
If so where are they ?
If not when ? :)
Thanks and Regards
X
 
 

Re:String Functions

Hi Chekcin
We have not made any FloatToStr or IntoToStr functions.
Regards
Dennis
 

Re:String Functions

Quote
We have not made any FloatToStr or IntoToStr functions.
There were a IntToStr some months ago:
groups.google.com/groups&lr=&threadm=41f3fa05%40newsgroups.borland.com&rnum=13&prev=/groups%3Fq%3Dint%2Bgroup:borland.public.delphi.language.basm%26start%3D10%26hl%3Dfr%26lr%3D%26selm%3D41f3fa05%2540newsgroups.borland.com%26rnum%3D13
named "IntToStr fastcode challenge?" from 2005-01-23 06:16:57 PST
This code seemed to be the fast:
groups.google.com/groups&lr=&selm=41f3c66f%40newsgroups.borland.com
Cheers,
Florent
 

Re:String Functions

"Florent Ouchet" <XXXX@XXXXX.COM>wrote
Quote
There were a IntToStr some months ago:

groups.google.com/groups&lr=&threadm=41f3fa05%40newsgroups.borland.com&rnum=13&prev=/groups%3Fq%3Dint%2Bgroup:borland.public.delphi.language.basm%26start%3D10%26hl%3Dfr%26lr%3D%26selm%3D41f3fa05%2540newsgroups.borland.com%26rnum%3D13
Quote
This code [IntToStrPLR1 from Pierre le Riche] seems to be fast:

groups.google.com/groups&lr=&selm=41f3c66f%40newsgroups.borland.com
The following IntToStr_JH1 function seems to be about
4 times faster than IntToStrPLR1 on small integers and
about the same as IntToStrPLR1 on the largest integers.
IntToStrPLR1 seems to be about 2.2 as fast as the RTL
IntToStr. I am running D5 under Win2K.
--JohnH
Function IntToStr_JH1(const Int: integer): string;
var r, i, n: integer; temp: array [0..11] of char; neg: boolean;
begin
neg := (Int < 0);
If neg
then r := -Int
else r := Int;
i := high(temp);
Repeat
temp[i] := char((r mod 10) + ord('0'));
dec(i);
r := r div 10;
Until (r = 0);
If neg
then begin temp[i] := '-'; dec(i) end;
n := high(temp)-i;
SetLength(Result,n);
Move(temp[i+1],Result[1],n);
end; {NOT WELL TESTED}
 

Re:String Functions

Really more simple and easier to understand than Pierre's ;)
Working with register overflow is really difficult to understand.
Florent
 

Re:String Functions

"Florent Ouchet" <XXXX@XXXXX.COM>wrote
Quote
Really more simple and easier to understand than Pierre's ;)
Working with register overflow is really difficult to understand.
Yes, but maybe the inner loop could be replaced by some ASM
code (something like Andreas Hausladen's SmallDivMod
routine) to make it even faster. --JohnH
 

Re:String Functions

Hi John,
Quote
The following IntToStr_JH1 function seems to be about
4 times faster than IntToStrPLR1 on small integers and
about the same as IntToStrPLR1 on the largest integers.
I have serious doubts about the validity of that statement. How did you
measure it?
I just did a few tests on a P4:
With input values of +-maxint IntToStrPLR1 is 4.1 times faster.
With completely random integers IntToStrPLR1 is 3.7 times faster.
With integers < 10000 IntToStrPLR1 is about twice as fast.
With integers < 10 they are about the same.
Note that these times take into account the time used to generate the random
numbers and the loop traversal, so the actual difference is even greater.
Here is the benchmark code I used:
function GetTicks: Int64;
asm
rdtsc;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
ticks: Int64;
begin
ticks := getticks;
for i := 1 to 100000 do
begin
IntToStr_JH1(random(10000));
// IntToStrPLR1(random(10000));
end;
ticks := getticks - ticks;
label1.caption := inttostr(ticks div 1000);
end;
Regards,
Pierre
 

Re:String Functions

Hi,
Quote
i just tried yours John and it seems like its about 4x slower than Pierre's
in most cases ?
anyone else can confirm this? on an AthlonXP 2500+ and Delphi7
I can confirm your findings on a P4.
I was immediately suspicious when I saw John's claim that his function is 4x
faster. I mean (a) it has a loop and (b) it uses div (slow) and (c) there's
even a call to system.move in there.
Regards,
Pierre
 

Re:String Functions

Quote
>I just tried yours John and it seems like its about
>4x slower than Pierre's in most cases? Anyone
>else confirm this? On an AthlonXP 2500+ and D7
"Pierre le Riche" <XXXX@XXXXX.COM>wrote
Quote
I can confirm your findings on a P4.
Here is my test program and some results under
D5 and D7. The results seem about the same with
optimization $O+ and $O-.
procedure TForm1.T_IntToStr_bClick(Sender: TObject);
var c,d: int64; i: integer; s: string;
const a,b: bytes;
begin
i := 1;
c := GetCpuClockCycleCount;
s := IntToStr(i);
d := GetCpuClockCycleCount - c;
Memo1.Lines.Add(Format(' %D IntToStr %S',[d,s]));
c := GetCpuClockCycleCount;
s := IntToStrPLR1(i);
d := GetCpuClockCycleCount - c;
Memo1.Lines.Add(Format(' %D IntToStrPLR1 %S',[d,s]));
c := GetCpuClockCycleCount;
s := IntToStr_JH1(i);
d := GetCpuClockCycleCount - c;
Memo1.Lines.Add(Format(' %D IntToStr_JH1 %S',[d,s]));
end;
Win2K, SP4, D5, Athlon ~1.5GHz
TSC Routine Number
8800 IntToStr 1
3424 IntToStrPLR1 1
1270 IntToStr_JH1 1
8697 IntToStr 1
3529 IntToStrPLR1 1
963 IntToStr_JH1 1
8870 IntToStr -123456789
1936 IntToStrPLR1 -123456789
1866 IntToStr_JH1 -123456789
8753 IntToStr -123456789
2332 IntToStrPLR1 -123456789
1896 IntToStr_JH1 -123456789
(Win2K, SP4, D7, Athlon ~1.5GHz)
TSC Routine Number
7810 IntToStr 1
3832 IntToStrPLR1 1
1392 IntToStr_JH1 1
7877 IntToStr 1
3941 IntToStrPLR1 1
1074 IntToStr_JH1 1
8202 IntToStr -123456789
2032 IntToStrPLR1 -123456789
2018 IntToStr_JH1 -123456789
8443 IntToStr -123456789
1793 IntToStrPLR1 -123456789
1839 IntToStr_JH1 -123456789
 

Re:String Functions

i just tried yours John and it seems like its about 4x slower than Pierre's
in most cases ?
anyone else can confirm this? on an AthlonXP 2500+ and Delphi7
"John Herbster" <herb-sci1_AT_sbcglobal.net>writes
Quote

"Florent Ouchet" <XXXX@XXXXX.COM>wrote
>Really more simple and easier to understand than Pierre's ;)
>Working with register overflow is really difficult to understand.

Yes, but maybe the inner loop could be replaced by some ASM
code (something like Andreas Hausladen's SmallDivMod
routine) to make it even faster. --JohnH

 

Re:String Functions

"Pierre le Riche" <XXXX@XXXXX.COM>wrote
Quote
I just did a few tests on a P4:
With input values of +-maxint IntToStrPLR1 is 4.1 times faster.
With completely random integers IntToStrPLR1 is 3.7 times faster.
With integers < 10000 IntToStrPLR1 is about twice as fast.
With integers < 10 they are about the same.
Here is the benchmark code I used:
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
ticks: Int64;
begin
ticks := getticks;
for i := 1 to 100000 do
begin
IntToStr_JH1(random(10000));
// IntToStrPLR1(random(10000));
end;
ticks := getticks - ticks;
label1.caption := inttostr(ticks div 1000);
end;
Here below are my results for code similar to the above
with the results converted to TSC counts per conversion.
Note what happens if the number of repeats is reduced
to just 1 (near bottom of post). I think that this the key to
the observed differences --JohnH
Athlon, 1.5Ghz, D7, Win2K
NbrRepeats = 100000; Random(10000);
With Pierre's Code:
260 Random+IntToStrPLR1
585 Random+IntToStr_JH1
260 Random+IntToStrPLR1
585 Random+IntToStr_JH1
Removed the times required for loop random():
230 IntToStrPLR1
578 IntToStr_JH1
229 IntToStrPLR1
581 IntToStr_JH1
Added assignment of result to a string:
230 IntToStrPLR1 771
590 IntToStr_JH1 537
230 IntToStrPLR1 8853
589 IntToStr_JH1 2928
With NbrRepeats = 1; Random(10000);
8363 IntToStrPLR1 0
2672 IntToStr_JH1 313
8179 IntToStrPLR1 8610
2900 IntToStr_JH1 2025
With NbrRepeats = 1; Random(10);
8030 IntToStrPLR1 0
2301 IntToStr_JH1 0
8076 IntToStrPLR1 8
2450 IntToStr_JH1 2
 

Re:String Functions

Here is a modification of Pierre's test program.
It stores the results in an array and allows setting
the NbrRepeats and the Random modulus. I see
a lot of time be consumed in memory allocation.
Note that the program requires:
Button Button1
Edit boxes NbrRepeats_e and RandMod_e
Memo box Memo1 for results.
--JohnH
procedure TForm1.Button1Click(Sender: TObject);
var NbrRepeats, RandMod, i, n: integer; t0,t1,ticks: Int64;
TicksPerConv: double; s: string;
Results: array [1 .. 100000] of string;
begin
NbrRepeats := StrToInt(NbrRepeats_e.Text);
RandMod := StrToInt(RandMod_e.Text);
Memo1.Lines.Add(Format('With %D repeats with
random(%D)',[NbrRepeats,RandMod]));
ticks := 0;
for i := 1 to NbrRepeats do
begin
n := random(RandMod);
t0 := GetCpuClockCycleCount;
Results[i] := IntToStrPLR1(n);
t1 := GetCpuClockCycleCount;
ticks := ticks + (t1 - t0);
end;
TicksPerConv := ticks/NbrRepeats;
Memo1.Lines.Add(Format('%0.0F IntToStrPLR1
%S',[TicksPerConv,Results[1]]));
ticks := 0;
for i := 1 to NbrRepeats do
begin
n := random(RandMod);
t0 := GetCpuClockCycleCount;
Results[i] := IntToStr_JH1(n);
t1 := GetCpuClockCycleCount;
ticks := ticks + (t1 - t0);
end;
TicksPerConv := ticks/NbrRepeats;
Memo1.Lines.Add(Format('%0.0F IntToStr_JH1
%S',[TicksPerConv,Results[1]]));
ticks := 0;
for i := 1 to NbrRepeats do
begin
n := random(RandMod);
t0 := GetCpuClockCycleCount;
Results[i] := IntToStrPLR1(n);
t1 := GetCpuClockCycleCount;
ticks := ticks + (t1 - t0);
end;
TicksPerConv := ticks/NbrRepeats;
Memo1.Lines.Add(Format('%0.0F IntToStrPLR1
%S',[TicksPerConv,Results[1]]));
ticks := 0;
for i := 1 to NbrRepeats do
begin
n := random(RandMod);
t0 := GetCpuClockCycleCount;
Results[i] := IntToStr_JH1(n);
t1 := GetCpuClockCycleCount;
ticks := ticks + (t1 - t0);
end;
TicksPerConv := ticks/NbrRepeats;
Memo1.Lines.Add(Format('%0.0F IntToStr_JH1
%S',[TicksPerConv,Results[1]]));
end;
 

Re:String Functions

"ffz" <XXXX@XXXXX.COM>wrote
Quote
what about GetCpuClockCycleCount ?
It reads the CPU's TSC counter.
It is the same as Pierre's "GetTicks".
--JohnH
 

Re:String Functions

what about GetCpuClockCycleCount ?
"John Herbster" <herb-sci1_AT_sbcglobal.net>writes
Quote

Here is a modification of Pierre's test program.
It stores the results in an array and allows setting
the NbrRepeats and the Random modulus. I see
a lot of time be consumed in memory allocation.
Note that the program requires:
Button Button1
Edit boxes NbrRepeats_e and RandMod_e
Memo box Memo1 for results.
--JohnH

procedure TForm1.Button1Click(Sender: TObject);
var NbrRepeats, RandMod, i, n: integer; t0,t1,ticks: Int64;
TicksPerConv: double; s: string;
Results: array [1 .. 100000] of string;
begin
NbrRepeats := StrToInt(NbrRepeats_e.Text);
RandMod := StrToInt(RandMod_e.Text);
Memo1.Lines.Add(Format('With %D repeats with
random(%D)',[NbrRepeats,RandMod]));
ticks := 0;
for i := 1 to NbrRepeats do
begin
n := random(RandMod);
t0 := GetCpuClockCycleCount;
Results[i] := IntToStrPLR1(n);
t1 := GetCpuClockCycleCount;
ticks := ticks + (t1 - t0);
end;
TicksPerConv := ticks/NbrRepeats;
Memo1.Lines.Add(Format('%0.0F IntToStrPLR1
%S',[TicksPerConv,Results[1]]));
ticks := 0;
for i := 1 to NbrRepeats do
begin
n := random(RandMod);
t0 := GetCpuClockCycleCount;
Results[i] := IntToStr_JH1(n);
t1 := GetCpuClockCycleCount;
ticks := ticks + (t1 - t0);
end;
TicksPerConv := ticks/NbrRepeats;
Memo1.Lines.Add(Format('%0.0F IntToStr_JH1
%S',[TicksPerConv,Results[1]]));
ticks := 0;
for i := 1 to NbrRepeats do
begin
n := random(RandMod);
t0 := GetCpuClockCycleCount;
Results[i] := IntToStrPLR1(n);
t1 := GetCpuClockCycleCount;
ticks := ticks + (t1 - t0);
end;
TicksPerConv := ticks/NbrRepeats;
Memo1.Lines.Add(Format('%0.0F IntToStrPLR1
%S',[TicksPerConv,Results[1]]));
ticks := 0;
for i := 1 to NbrRepeats do
begin
n := random(RandMod);
t0 := GetCpuClockCycleCount;
Results[i] := IntToStr_JH1(n);
t1 := GetCpuClockCycleCount;
ticks := ticks + (t1 - t0);
end;
TicksPerConv := ticks/NbrRepeats;
Memo1.Lines.Add(Format('%0.0F IntToStr_JH1
%S',[TicksPerConv,Results[1]]));
end;

 

Re:String Functions

Hi John,
Quote
Here is my test program and some results under
D5 and D7. The results seem about the same with
optimization $O+ and $O-.
Two mistakes in your benchmark:
(1) You do not reset the result string (s) back to blank before calling each
function. This means that the SetLength call doesn't do the same thing in
all functions. In fact, after my function the SetLength in yours does
nothing, since the length is already set correctly. Exchange the order of
the calls by putting yours first and you will see the dramatic difference it
makes. Also, by the time it gets to the thrid test function the memory used
by 's' is cached and it runs much faster.
(2) One iteration is not anywhere near enough. We're talking an execution
time of a few microseconds here.
If I add the line
s := ''
before each benchmark, and I increase the benchmark count to a few thousand
I get repeatable results which bear out the results of my previous post.
Regards,
Pierre