----- Original Message ----- From: "Dave Hansen" <[EMAIL PROTECTED]>
> From: David Kelly <[EMAIL PROTECTED]> > [...] > > > > 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 :-) _______________________________________________ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list