|
|
View previous topic :: View next topic |
Author |
Message |
Torello
Joined: 29 Sep 2006 Posts: 120
|
Int32 to string conversion; fastest itoa |
Posted: Fri Jan 02, 2009 2:57 am |
|
|
Hi,
First, best wishes to everybody on this forum. A C-full 2009!
Tweaking my application to the minimum energy consumption (thus also execution speed of a task), I found out that sprintf 4 int32 values take up about 92 ms (18LF4620 @4Mhz)! Quite shocked!
Replaced the sprintf with the use of ccs-itoa, but that did not make any difference; probably sprintf uses ccs-itoa. Then took a look at the standard-c itoa. It is using the % (mod) operator heavily. The code looks very resources efficient. I've come up with an replacement below. Uses probably more recourses, but It does the same 4 int32 in 10ms!. So nine times faster. Or 90% discount on energy consumption. Heh, thats worth while spending on a little more bytes.
Can we make this function still faster? Or has somebody an other, faster routine to share?
Regards,
Edwin
Code: | //==============================================================================
// Function converts int32 to signed decimal string
// returns pointer to the '/0' ended string. (handy for formatting more values)
char *i32toa(int32 n, char *s) {
int8 i,j; //decade counter
int8 idx=0; //string index
int32 const Div[10] = { //decades table
1000000000L,100000000L,10000000L,1000000L
100000L,10000L,1000L,100L,10L,1};
int32 b; //i32 to hold table read
int fdd; //first digit detect (suppress leading zero function)
fdd=0; //clear detection
if (bit_test(n,31)) { //T: n=negative
n=(~n)+1; //convert to positive
s[0]='-'; //mark the negative number
idx++;
}
for (i=0; i<10;i++) { //do all the decades, start with biggest
j=0; //clear the decimal digit counter
b=Div[i]; //read the table once;
while (n>=b) { //T: "left-over" still bigger then decade; substr. and count
j++;
n-=b;
}
if ((j)||(fdd)) { //T: decade count!=0 or first digit has been detected
fdd=1;
s[idx++]='0'+j; //..then add the decade count
}
}
if (!fdd) s[idx++]='0'; //dont suppress zero when n==0!
s[idx]=0; //end the string
return(s+idx); //return last written pointer
}
//=== code snippet to format 4 int32 into string with comma as separator
i320=-2139999999L;
i321=-2139999999L;
i322=-2139999999L;
i323=-2139999999L;
#ifdef _DM output_high(pin_b3); #endif
ptS = i32toa(i320,tS);
*(ptS++)=',';
ptS = i32toa(i321,ptS);
*(ptS++)=',';
ptS = i32toa(i322,ptS);
*(ptS++)=',';
ptS = i32toa(i323,ptS); //total 10ms
#ifdef _DM output_low(pin_b3); #endif
fprintf(debug,"%s\n",tS);
|
|
|
|
Ttelmah Guest
|
|
Posted: Fri Jan 02, 2009 3:14 am |
|
|
You might find a more efficient '%', with a search here. Though things may have changed.
CCS, 'waste' a lot of time in several places using %. Their implementation, performs a division, then takes the integer part of the result, and multiplies this, subtracting this result from the original to get the %. In many places, they perform this, and a division again, as well, to get the part needed for the next operation!.....
A long time ago, I found that in fact their division code, had the remainder already present in a temporary store, and the two divisions, and one multiplication used to get the values needed, could be replaced with just one division, if you accessed this. I posted a routine to do this. It was though a long time ago (probably on the old board), and I have no idea what the thread was called, but a search might find it. Made a massive difference to the performance...
Best Wishes |
|
|
|
|
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
|
Powered by phpBB © 2001, 2005 phpBB Group
|