TIP: Click on subject to list as thread! ANSI
echo: z3_pascal
to: Bob Lawrence
from: Frank Malcolm
date: 1996-05-08 07:11:00
subject: StringToInteger

CG> Hi Bob

CG>  BL> function StrInt(s: string): integer;
CG>  BL> var
CG>  BL> i, size: integer;
CG>  BL> begin
CG>  BL>    i := 1; size := 0;
CG>  BL>    while s[i] in ['0'..'9'] do begin
CG>  BL>       size := size * 10 + (Ord(s[i]) - 48);
CG>  BL>       inc(i);
CG>  BL>    end;
CG>  BL>    StrInt := size;
CG>  BL> end;


CG> You might save a smidgen of time passing a pointer into the
CG> function rather than the string itself

Colin is right here, it would save time and it would be a smidgin. :-)
Instead of a pointer, you could just declare the parameter const.

CG> I think a set might use a fixed number of bytes regardless of
CG> the number of elements you use. perhaps you should look into
CG> other methods of testing each value...

He's right here, too - but it's probably worse than that. The constant
set is probably stored in the minimum number of bytes, but then expanded
to the maximum 32 bytes before being passed to the set membership
routines - which itself is a function call. Use...

    while (s[i] >= '0') and (s[i] <= '9') do

This by itself will give you an amazing speed improvement, if the code
in BP7/Delphi which you're using is anything like that which was
generated in TP6, the last one I looked at in detail.

CG> Maybe storing the Ord() - 48 values in a lookup table could
CG> speed things up ?

But not here - getting the array offset into a register will be slower
than the straightforward subtraction.

CG> I'd wrap it in 100k or whatever loop, grab a stopwatch (or timer routine)
CG> and start experimenting.

CG> Wish I had the time, it'd be fascinating :)

CG> You might also need something in there to tell it when it's reached
CG> the end of the string.

And he's right here, too - add...

    and (i <= length (s))

... to that while statement - you *might* get a string with all numbers.
Oh, and for safety you should be checking that you don't overflow 32767.

Finally, don't declare Size, and use Result := Result + etc, Result := 0
before that and omit the final assignment.

A for loop might be faster...

function StrToInt (const s: string): integer;
var i: integer;
Result := 0;
for i := 1 to Length (s) do
  if (s[i] >= '0') and (s[i] <= '9') then
    if Result < 3276 then
      Result := Result * 10  - Ord ('0')+ Ord (S[i]) { * see below }
    else { the above would have overflowed if the digit was 8 or 9 }
      begin
      Result := -1; { tell the caller we got an error }
      Exit; { and piss off }
      end
  else { we're done }
    Exit;
end;

* Do the subtraction *before* the addition if you're only dealing in +ve
numbers as you are here. Otherwise you'll get an integer overflow at
much less than 32767. Like 32711. Note also that my test is a bit of a
kludge in that it only allows numbers up to 32759. But it's a lot faster
than doing it "properly", and you (I think) aren't looking at numbers
that big in *this* application anyway.

A late-breaking thought - remove the overflow test and put it in an
exception block.

Another one - have you already stripped whitespace *before* the number?
If not you might want to put another for loop before that one, with a
Break if s[i] isn't space or tab (and maybe even Cr & LF).

And if speed is *that* important, do it in BASM. :-)

Regards, FIM.

 * * The dog ate my .REP packet.
@EOT:

---
* Origin: Pedants Inc. (3:711/934.24)
SEEN-BY: 633/267 270
@PATH: 711/934 809 808 50/99 635/544 727 633/267

SOURCE: echomail via fidonet.ozzmosis.com

Email questions or comments to sysop@ipingthereforeiam.com
All parts of this website painstakingly hand-crafted in the U.S.A.!
IPTIA BBS/MUD/Terminal/Game Server List, © 2025 IPTIA Consulting™.