 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
J French Guest
|
Posted: Fri Dec 12, 2003 3:35 pm Post subject: Re: 2Q: Danger of using FillMem() on a string? Speed of Abs( |
|
|
On Fri, 12 Dec 2003 15:25:54 +0100, Quivis <quivis (AT) ask (DOT) me.first>
wrote:
<snip>
| Quote: |
My second question is best illustrated as follows:
//Quivis, 2003-12: Reverse string (S)
function ReverseStr(const S: string): string;
var
I, iLen: integer;
sTmp: string;
begin
iLen := Length(S);
SetLength(sTmp, iLen);
for I := 1 to iLen do
sTmp[I] := S[Abs(I - (iLen + 1))];
Result := sTmp;
end;
|
Abs() is not slow
- but this code is daft
..... bizarre is more likely
Draw a string on a bit of paper, as a load of boxes
- draw arrows
- try a string of length two
- then one of length three
Think hard about what 'Div' does
Who Knows (Quivis) what you will realize ?
|
|
| Back to top |
|
 |
Rob Kennedy Guest
|
Posted: Fri Dec 12, 2003 4:21 pm Post subject: Re: 2Q: Danger of using FillMem() on a string? Speed of Abs( |
|
|
Quivis wrote:
| Quote: | Anyway, what I'm concerned about is, are there any dangers in using this
function? Like: "it's a bad idea because [...]," and similar.
|
The code is fine. However, it will *never* return False. If SetLength or
FillMemory fail, you will get an exception and you will have no return
value at all.
Your error checking seems to assume that FillMemory will start filling
at the beginning of the buffer and finish at the end, but it's allowed
to fill the buffer backward if it wants to, in which case checking the
last character won't be a good indication of success anyway.
You should check for the case when iNumChars is zero or negative. A zero
value will be fine for SetLength and FillMemory, but it will fail when
you check S[iNumChars]. A negative value is invalid input; use Assert to
check for it:
Assert(iNumChars >= 0);
I would declare S as an out parameter instead of var; it's more
expressive of how the parameter is used.
FillMemory is just a thin wrapper around the built-in FillChar
procedure. Save yourself a CALL/RET and use FillChar directly.
| Quote: | I've seen similar approaches used in many code-snippets on how to
reverse a string, but so far I have not seen anyone using Abs() to do
the "dirty work" of reversing the string. So my question is: Is there a
reason for this? Is Abs() very slow, or what?
|
It's not slow, but it's not needed, either. Within your loop, iLen+1 is
always greater than I, so the result of subtraction will always be
negative. If the result is always negative, then you can save the call
to Abs and just reverse the operands:
sTmp[I] := S[iLen + 1 - I];
ILen+1 is also an expression with a constant result, so you should
perform the operation outside the loop.
I'd remove the use of sTmp and work on Result directly.
Abs is actually not a function at all. It's compiler magic, so there is
no CALL/RET involved; it's about as fast as it could possibly be.
--
Rob
|
|
| Back to top |
|
 |
AlanGLLoyd Guest
|
Posted: Fri Dec 12, 2003 7:04 pm Post subject: Re: 2Q: Danger of using FillMem() on a string? Speed of Abs( |
|
|
In article <MPG.1a43ee611d5f529a989845 (AT) 207 (DOT) 14.113.17>, Quivis
<quivis (AT) ask (DOT) me.first> writes:
| Quote: | In some of my apps I do this:
//Quivis, 2002-03, edited 2003-12: Fill a string (S) with a
//character (cCharacter) up to desired length (iNumChars),
//returns boolean
function FillString(var S: string; iNumChars: integer;
cCharacter: Char): boolean;
begin
Result := False; //assume failure
SetLength(S, iNumChars);
FillMemory(pointer(S), iNumChars, Ord(cCharacter));
if S[iNumChars] = cCharacter then
Result := True;
end;
...and it seems to be working. To those who may wonder: I don't have a
clue as to how fast this is, I've never tested it since it's mainly used
on fairly short strings. I just thought it was a waste not to use
already built-in stuff, and, to tell you the truth, I didn't really
expect it to run... :-)
But if anyone has a clue as to how fast this function might be, I'd
appreciate to hear about it, although this is not why I'm posting.
Anyway, what I'm concerned about is, are there any dangers in using this
function? Like: "it's a bad idea because [...]," and similar.
|
What's the problem with using Delphi's StringOfChar() ?
Alan Lloyd
[email]alanglloyd (AT) aol (DOT) com[/email]
|
|
| Back to top |
|
 |
J French Guest
|
Posted: Sat Dec 13, 2003 11:58 am Post subject: Re: 2Q: Danger of using FillMem() on a string? Speed of Abs( |
|
|
On Sat, 13 Dec 2003 11:28:19 +0100, Quivis <quivis (AT) ask (DOT) me.first>
wrote:
| Quote: | In article <3fd9dd86.10662948 (AT) news (DOT) btclick.com>, [email]erewhon (AT) nowhere (DOT) com[/email]
says...
8>< /snip
Abs() is not slow
- but this code is daft
.... bizarre is more likely
See my response to Rob where it came from.
8>< /snip
Think hard about what 'Div' does
I came up with this:
iLen := Length(S) + 1;
Result := S;
for I := 1 to iLen div 2 do
begin
//is there a faster way to swap two characters?
C := Result[I];
Result[I] := Result[iLen - I];
Result[iLen - I] := C;
end;
|
Yes, that is more like it, but the code is slightly obfuscated
Just because something looks terser, does not mean that it is faster
- I also missed a trick
- I thought you were reversing a string
L := Length( S );
For L9 := 1 To L Div 2 Do
Begin
C := S[L9];
S[ L9 ] := Result[ L ];
S[ L ] := C;
L := L - 1;
End;
However you are actually making a COPY of the String
L := Length( S );
SetLength( Result, L );
For L9 := 1 To L Do
Begin
Result[ L9 ] := S[ L ];
L := L - 1 ;
End;
Notice that I am using a simple counter rather than doing the maths
time and time again
- this makes the code far easier to understand
- and probably faster
if the compiler can 'remember' the results of simple math
- then it can certainly 'remember' to substitute a Register for a
variable
BTW, the reason why I would recomend using SetLength() if you are
returning a Result, is because Delphi definitely creates a new unique
Result, whereas assigning a copy of the string in S to Result _might_
result in reference counting
- probably not, as the compiler is pretty smart
- but in principle it is better to tell the compiler to do exactly
what you want, rather than 'misleading' it
- it also makes the code clearer to read
As far as swapping characters goes, it is probably not worth worrying
about
- there is the ASM XCHG
- but it is unlikely to be one of the 'optimized' Op codes that have
had a RISC element since the .486
| Quote: |
Who Knows (Quivis) what you will realize ?
Well, it seems you have realized what my "name" means...
|
I wasn't sure for some time ...
BTW apologies for being rather sharp yesterday
- it is just that I've spent much of my coding life trying to unravel
'clever' code by other people
- and avoid writing it myself
|
|
| Back to top |
|
 |
Rob Kennedy Guest
|
Posted: Sat Dec 13, 2003 5:50 pm Post subject: Re: 2Q: Danger of using FillMem() on a string? Speed of Abs( |
|
|
Quivis wrote:
| Quote: | In article <vtjqohcq2p3a2 (AT) corp (DOT) supernews.com>, Rob Kennedy <.> says...
FillMemory is just a thin wrapper around the built-in FillChar
procedure. Save yourself a CALL/RET and use FillChar directly.
Are you sure? FillMemory() is, if I'm not mistaken, a system API.
|
I am certain. Go check it yourself in the source code. Another
indication is in the documentation. Unlike for most other API functions,
MSDN doesn't tell you which C library to link to your code since the
function doesn't appear in any library. Its implementation is left to
the compiler vendor. The same goes for CopyMemory, MoveMemory, and
ZeroMemory. They're implemented using Delphi's Move and FillChar.
| Quote: | From Win32 help:
[...]
VOID FillMemory (
PVOID Destination, // pointer to block to fill
DWORD Length, // size, in bytes, of block to fill
BYTE Fill // the byte value with which to fill
);
[...]
|
The I in API stands for interface, not implementation.
--
Rob
|
|
| Back to top |
|
 |
Dr John Stockton Guest
|
Posted: Sat Dec 13, 2003 9:26 pm Post subject: Re: 2Q: Danger of using FillMem() on a string? Speed of Abs( |
|
|
JRS: In article <MPG.1a45082b98f29eb9989849 (AT) 207 (DOT) 14.113.17>, seen in
news:comp.lang.pascal.delphi.misc, Quivis <quivis (AT) ask (DOT) me.first> posted
at Sat, 13 Dec 2003 11:28:19 :-
| Quote: | iLen := Length(S) + 1;
Result := S;
for I := 1 to iLen div 2 do
begin
//is there a faster way to swap two characters?
C := Result[I];
Result[I] := Result[iLen - I];
Result[iLen - I] := C;
end;
|
The entire string is copied and then reversed; it bight be better to
copy it backwards. Consider something like
K := 1 ; L := Length(S) ;
SetLength(Result, L) ;
for J := L downto 1 do begin Result[K] := S[J] ; Inc(K) end ;
or
K := 1 ; L := Length(S) ;
SetLength(Result, L) ;
repeat Result[K] := S[L] ; Inc(K) ; Dec(L) until L=0 ;
or
L := Length(S) ; SetLength(Result, L) ; PS = @S[L] ; PR = @R[1] ;
repeat PR^ := PS^ ; Inc(PR) ; Dec(PS) until ??? ;
--
© John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Delphi 3 Turnpike 4 ©
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/&c., FAQqy topics & links;
<URL:http://www.bancoems.com/CompLangPascalDelphiMisc-MiniFAQ.htm> clpdmFAQ;
<URL:http://www.borland.com/newsgroups/guide.html> news:borland.* Guidelines
|
|
| Back to top |
|
 |
Maarten Wiltink Guest
|
Posted: Sat Dec 13, 2003 11:09 pm Post subject: Re: Some tests on variations of the theme (a bit long) [ Re: |
|
|
"Quivis" <quivis (AT) ask (DOT) me.first> wrote
| Quote: | In article <3fdaf94d.83320989 (AT) news (DOT) btclick.com>, [email]erewhon (AT) nowhere (DOT) com[/email]
says...
However you are actually making a COPY of the String
Yes, but it seems Delphi refuses to work in this way directly on
TMemo.Text, ...
|
That is correct. You are not allowed to pass a property as a var parameter,
because it _may_ be backed by accessor methods. Even if it's backed by a
field in the current class, and constructing a reference would be possible,
a descendant class may change that. So the only safe thing to do is to
forbid it altogether.
Groetjes,
Maarten Wiltink
|
|
| Back to top |
|
 |
J French Guest
|
Posted: Sun Dec 14, 2003 1:33 pm Post subject: Re: Some tests on variations of the theme (a bit long) [ Re: |
|
|
On Sat, 13 Dec 2003 18:10:51 +0100, Quivis <quivis (AT) ask (DOT) me.first>
wrote:
| Quote: | In article <3fdaf94d.83320989 (AT) news (DOT) btclick.com>, [email]erewhon (AT) nowhere (DOT) com[/email]
says...
8>< /snip
However you are actually making a COPY of the String
Yes, but it seems Delphi refuses to work in this way directly on
TMemo.Text, so I had to. Either inside the function or before I called
it. I opted for doing it inside the function. They way I use it, it will
only be called once for each string.
|
TMemo.Text is a Property
- in general you are probably right in making StrReverse a function
- my version works on the string itself (a procedure)
- this is historical, since the original was in ASM from about 1987
| Quote: |
8>< /snip
BTW, the reason why I would recomend using SetLength() if you are
returning a Result, is because Delphi definitely creates a new unique
Result, whereas assigning a copy of the string in S to Result _might_
result in reference counting
That's something to keep in mind.
|
IMO/IME it is better to be totally 'honest' when writing routines
- it makes them cleaner and clearer
| Quote: |
Some tests I've done, using the following setup:
snip |
| Quote: |
Conclusion: There are more ways than one to skin a cat, especially when
the cats are so similar in size as these.
|
True, but let's face it, the second version of the routine that I
posted was 'blindingly obvious' code
| Quote: |
Well, it seems you have realized what my "name" means... ;-)
I wasn't sure for some time ...
Well, it actually means whoever, at least in my Latin dictionary, e.g.
as in "whoever did that shall be keelhauled"
|
Did the Romans keelhaul ?
- I doubt that there boats were sufficiently barnacled
| Quote: |
BTW apologies for being rather sharp yesterday
No problems.
|
|
|
| Back to top |
|
 |
Dr John Stockton Guest
|
Posted: Sun Dec 14, 2003 8:12 pm Post subject: Re: 2Q: Danger of using FillMem() on a string? Speed of Abs( |
|
|
JRS: In article <MPG.1a465d13cde147b3989850 (AT) 207 (DOT) 14.113.17>, seen in
news:comp.lang.pascal.delphi.misc, Quivis <quivis (AT) ask (DOT) me.first> posted
at Sun, 14 Dec 2003 11:42:51 :-
| Quote: | In article <uBvns5AMQ42$Ewwb (AT) merlyn (DOT) demon.co.uk>,
[email]spam (AT) merlyn (DOT) demon.co.uk[/email] says...
The entire string is copied and then reversed; it bight be better to
^^^
Have you caught a cold?
|
The cause is that I am not a good typist; however, your supposition is
unfortunately correct. The latter situation, unlike the former, will
probably improve.
--
© John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Delphi 3 Turnpike 4 ©
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/&c., FAQqy topics & links;
<URL:http://www.bancoems.com/CompLangPascalDelphiMisc-MiniFAQ.htm> clpdmFAQ;
<URL:http://www.borland.com/newsgroups/guide.html> news:borland.* Guidelines
|
|
| Back to top |
|
 |
Michael Brown Guest
|
Posted: Tue Dec 16, 2003 2:31 am Post subject: Re: Some tests on variations of the theme (a bit long) [ Re: |
|
|
Quivis wrote:
| Quote: | In article <3fdaf94d.83320989 (AT) news (DOT) btclick.com>, [email]erewhon (AT) nowhere (DOT) com[/email]
says...
[...]
Some tests I've done, using the following setup:
XP-Pro, 1.3 GHz CPU (Celeron Mobile), 256 MB RAM
Iterations: 100,000 for each code snippet on separate runs.
String to reverse: Many websites assume that every visitor will have a
browser capable of Javascript.
[...]
//Tick count: 761, stabilized around this value, first run: 781
[...] |
What? There's no heavily-unrolled, hand-optimised MMX version in there? Aww
(estimated tick count: 20-50)
[...]
--
Michael Brown
www.emboss.co.nz : OOS/RSI software and more
Add michael@ to emboss.co.nz - My inbox is always open
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|