avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] Initilizing complex const arrays : syntax ?


From: David Brown
Subject: Re: [avr-gcc-list] Initilizing complex const arrays : syntax ?
Date: Mon, 19 Sep 2005 18:11:11 +0200

----- Original Message -----
From: "Dave Hansen" <address@hidden>

> From: David Kelly <address@hidden>
> [...]
> >
> >     char buffer[4];
> >     uint8_t i;
> >     strncpy_P( buffer, PGM_P("000"), 3 );
> >     i = 2;
> >     while(x) {
> >         buffer[i--] = x%10 + '0';
> >         x = x/10;
> >     }
> >     putchar(buffer[0]);
> >     putchar('.');
> >     putchar(buffer[1]);
> >     putchar(buffer[2]);
> >
> >In the above I find myself wishing for the FORTH /mod operator. Avr- gcc
> >calls exactly the same routine for division or modulo and stores  the
> >desired result. In assembly we could store both but I don't see  how to
get
> >at both from C. Is possible the compiler could optimize it  but plain -O
> >didn't in recent tests.
>
> Try something like
>
>    #include <stdlib.h>
>    ...
>    div_t qr;
>
>      while(x) {
>          qr = div(x,10);
>          buffer[i--] = qr.rem + '0';
>          x = qr.quot;
>      }
>
> I'm not certain this is optimal.  I haven't looked closely, but it looks
> like it should be.  It certainly has the opportunity to be.
>

That's probably fairly close to optimal in terms of code size (assuming you
already need div() linked in), and close to optimal in terms of size of
source code, scalability, and legibility of source code, and thus a good
solution.  For run-time efficiency, you can do a lot better.  I missed the
beginning of this thread, so I don't know the exact requirements, but I
assume you have an unsigned 16-bit int "x" ranging from 0 to 999, which you
want to convert into three ascii characters in buffer[].  The following code
should be about as fast as you can get without using table lookups, despite
slightly sub-optimal code generated for "if (x & 0x0200)" (avr-gcc 3.4.1) :

void printx(unsigned int x) {
 char hiChar;
 uint8_t lo;    // Keep as uint8 instead of char to avoid overflow

 if (x & 0x0200) {
  hiChar = '5';
  lo = 12;
 } else {
  hiChar = '0';
  lo = 0;
 };
 if (x & 0x0100) {
  hiChar += 2;
  lo += 56;
 };
 if (x & 0x0080) {
  hiChar += 1;
  lo += 28;
 };
 lo += (x & 0x7f);  // Lo can be up to 0x7f + 12 + 56 + 28 = 223
 if (lo & 0x80) {  // Bit test should be faster than comparison
  hiChar += 1;
  lo -= 100;
 };
 if (lo > 99) {
  hiChar += 1;
  lo -= 100;
 };

 putchar(hiChar);

 hiChar = '0';
 if (lo & 0x40) {
  hiChar += 6;
  lo -= 60;
 };
 if (lo & 0x20) {
  hiChar += 2;
  lo -= 20;
 };
 if (lo & 0x20) {  // Might have been set by carry
  hiChar += 2;
  lo -= 20;
 };
 if (lo & 0x10) {
  hiChar += 1;
  lo -= 10;
 };
 if (lo & 0x10) {  // Might have been set by carry
  hiChar += 1;
  lo -= 10;
 };
 if (lo > 9) {
  hiChar += 1;
  lo -= 10;
 };

 putchar(hiChar);
 putchar('0' + lo);
}


Of course, no one would use code like that unless it was *really* necessary,
or for a library people will use but no one will ever look at, or if you
think such optomisations are fun :-)







reply via email to

[Prev in Thread] Current Thread [Next in Thread]