Recent

Author Topic: Convert from Integer to String (Base Ten only)  (Read 2390 times)

WackaMold

  • New Member
  • *
  • Posts: 11
Convert from Integer to String (Base Ten only)
« on: May 03, 2021, 12:09:45 am »
This function makes the EXE 1K bytes larger than just calling Str(). It started as an alternative to itoa() "Integer To Ascii". Not yet tested with zero, negative values, nor large values.

Code: Pascal  [Select][+][-]
  1. function StrReverse( strVal : string ) : string; // return the string with characters in reverse order
  2. var
  3.   strRtn : string = ''; // function result
  4.   idxStr : integer    ; // indexer
  5.   chrCur : char       ; // current character
  6. begin
  7.   for idxStr := Byte(Length(strVal)) DownTo 1 do begin // scan all characters in the string in reverse order
  8.   // Byte() conversion avoids Warning: (4048) Type size mismatch, possible loss of data / range check error
  9.     chrCur := strVal[idxStr];                    // get current character
  10.     strRtn := strRtn + chrCur;                   // append it to the output
  11.   end;                                           // done scanning
  12.   StrReverse := strRtn;                          // pass result back to caller
  13. end; // StrReverse
  14.  
  15. function StrFrmInt( prmInt : integer ) : string; // convert from Integer to String, in base-ten only
  16. var
  17.   strRtn : string = ''          ; // function result
  18.   ptrTmp : byte                 ; // value of current integer-digit
  19.   chrTmp : char                 ; // char  of current string -digit
  20. begin
  21.   while prmInt > 0 do begin       // eat all of caller's integer value, from ones-place to largest-place
  22.     ptrTmp :=      prmInt Mod 10; // get value of current last digit
  23.     ptrTmp :=      ptrTmp  +  48; // convert from zero-based to '0'-based
  24.     chrTmp := Chr( ptrTmp )     ; // convert from byte-digit to character-digit
  25.     strRtn := strRtn + chrTmp   ; // append character-digit to result
  26.     prmInt :=      prmInt Div 10; // drop last digit from caller's integer
  27.   end                           ; // done eating caller's integer value
  28.   strRtn := StrReverse( strRtn ); // convert our characters from [ones-place through largest-place] to [largest-place through ones-place]
  29.  
  30.   Result := strRtn              ; // pass result back to caller
  31. end; // StrFrmInt
  32.  

mangakissa

  • Hero Member
  • *****
  • Posts: 1131
Re: Convert from Integer to String (Base Ten only)
« Reply #1 on: May 03, 2021, 11:18:55 am »
So, what's the problem?
Lazarus 2.06 (64b) / FPC 3.0.4 / Windows 10
stucked on Delphi 10.3.1

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11352
  • FPC developer.
Re: Convert from Integer to String (Base Ten only)
« Reply #2 on: May 03, 2021, 11:34:55 am »
In case you are an embedded user (*) where it might matter, string support is higher level than plain pointers and chars. Rewrite them using pchar might save you some bytes if you really need them.


(*) and by embedded I mean anything with less than 256k effective storage for programs. RPI is not embedded by this definition.

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Convert from Integer to String (Base Ten only)
« Reply #3 on: May 03, 2021, 12:44:49 pm »
You don't need StrReverse function. Just change the order of this line:
Code: Pascal  [Select][+][-]
  1.     strRtn := strRtn + chrTmp;
to
Code: Pascal  [Select][+][-]
  1.     strRtn :=  chrTmp + strRtn;

Bart

  • Hero Member
  • *****
  • Posts: 5265
    • Bart en Mariska's Webstek
Re: Convert from Integer to String (Base Ten only)
« Reply #4 on: May 03, 2021, 12:46:12 pm »
Your routine to reverse the string is a bit suboptimal.
FreePascal has a ReverseString function in strutils unit.
If you cannot (or do not want to) include that unit, simply copy the code from there.
Alternatively (see also my website, which has some other "suboptimal" ones as well, but this one is OK):
Code: Pascal  [Select][+][-]
  1. function ReverseString(const S: String): String;
  2. var i,j: LongInt;
  3. begin
  4.   j := Length(S);
  5.   Setlength(Result,j);
  6.   i := 1;
  7.   while i <= j do //Actually this is faster than a for loop
  8.   begin
  9.     result[i] := S[j-i+1];
  10.     inc(i);
  11.   end;
  12. end;

Why can't or won't you sue the Str() function?

Bart

alpine

  • Hero Member
  • *****
  • Posts: 1032
Re: Convert from Integer to String (Base Ten only)
« Reply #5 on: May 03, 2021, 01:44:06 pm »
Just a side question - why is it necessary to make a string ltr and then reverse? Is there any subtle reason I am not aware of?
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Convert from Integer to String (Base Ten only)
« Reply #6 on: May 03, 2021, 01:47:37 pm »
@Bart, Because of Unicode I wouldn't call it ReverseString,  O:-)

@y.ivanov, I don't think so. See my previous post.

alpine

  • Hero Member
  • *****
  • Posts: 1032
Re: Convert from Integer to String (Base Ten only)
« Reply #7 on: May 03, 2021, 01:56:48 pm »
@engkin
My question is partially because your previous post, partially because I reviewed some C library sources for itoa() and I what I saw was that some implementations really do reversing. And so I suspected reason I'm unfamiliar with.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Convert from Integer to String (Base Ten only)
« Reply #8 on: May 03, 2021, 02:05:00 pm »
In this case probably it is speed.

WackaMold

  • New Member
  • *
  • Posts: 11
Re: Convert from Integer to String (Base Ten only)
« Reply #9 on: May 03, 2021, 08:36:05 pm »
Quote
You don't need StrReverse().

Code: [Select]
[Del] strRtn := strRtn + chrTmp; // ap pend character-digit to result
[Ins] strRtn := chrTmp + strRtn; // prepend character-digit to result

Thank you, this saved another 1K.

Quote
Why not use Str()?
On the off chance of shrinking the EXE further, without the extra effort of trying a function written in assember. Using StrUtils or SysUtils or untStrings added far too much unused code, making the EXE more than twice larger. Speed is not a concern in this case, but might be useful in other cases.

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Convert from Integer to String (Base Ten only)
« Reply #10 on: May 03, 2021, 09:32:12 pm »
Hi!

Str () is part of the system unit - so no additional code is added.

As Bart said: use Str()

Winni

alpine

  • Hero Member
  • *****
  • Posts: 1032
Re: Convert from Integer to String (Base Ten only)
« Reply #11 on: May 03, 2021, 11:46:42 pm »
If you want a slight reduction you can consider using ShortString instead of String.

Your function is incorrect for zero and negative.

As markov suggested, you should use PChar if the code size is critical.
Here is example implementation for base 10 (not reentrant).

Code: Pascal  [Select][+][-]
  1. function StrFrmInt(prmInt: Integer): PChar;
  2. const
  3.   Buf: array[0..22] of Char = '';
  4. var
  5.   I, Sign: Integer;
  6. begin
  7.   if prmInt < 0 then
  8.     Sign := -1 else
  9.     Sign := 1;
  10.   Buf[High(Buf)] := #0;
  11.   I := Pred(High(Buf));
  12.   repeat
  13.     Buf[I] := Char(48 + prmInt mod 10 * Sign);
  14.     prmInt := prmInt div 10;
  15.     Dec(I);
  16.   until (prmInt = 0) or (I < 1);
  17.   if Sign < 0 then
  18.   begin
  19.     Buf[I] := '-';
  20.     Dec(I);
  21.   end;
  22.   Result := PChar(@Buf[Succ(I)]);
  23. end;
  24.  
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

WackaMold

  • New Member
  • *
  • Posts: 11
Re: Convert from Integer to String (Base Ten only)
« Reply #12 on: May 09, 2021, 02:36:49 pm »
Cool. This version ignores Sign and has comments. It's good for only non-negative values.
Code: [Select]
function StrFrmInt( intPrm : Integer ) : PChar; // convert from non-negative Integer to String, in base-ten only. Adds 2K
const
  bufStr : array[ 0..22 ] of Char = ''            ; // null-terminated string; eats 32 bytes
var
  idxBuf : Integer                                ; // indexer into string buffer
begin
  intPrm :=               Abs    ( intPrm        ); // convert negative values to positive
  bufStr[         High( bufStr ) ] := #0          ; // put string-terminator in last position
  idxBuf := Pred( High( bufStr ) )                ; // point to next-to-        last position

  repeat                                            // process loop
    bufStr[ idxBuf ] := Char( 48 + intPrm Mod 10 ); // shift ones-place from integer-digit to character-digit; put that in buffer's current position
    intPrm :=             Integer( intPrm Div 10 ); // drop ones-place from caller's integer; typecast suppresses Warning 4048 'Type size mismatch, possible loss of data / range check error'
    Dec( idxBuf )                                 ; // point to preceding buffer position
  until( intPrm = 0 ) Or ( idxBuf < 1 )           ; // done when [caller's integer is eaten up] or [we have run out of positions to fill]

  Result := PChar( @bufStr[ Succ( idxBuf ) ] )    ; // return a string-pointer to the character after the current buffer position
end; // StrFrmInt

 

TinyPortal © 2005-2018