Reputation: 1784
I have an integer n
representing a number multiplied by 1e<exp>
for some constant <exp>
. For example, for an input number of 12.345
and an <exp>
of 4, n = 123450
. I want to output the original number, with no trailing zeros, as fast as possible.
Some potential (but flawed) solutions:
// Pros:
// - Very simple
// - Does not output trailing zeros
// Cons:
// - Converts to float (slow, inaccurate)
printf("%g", n * 1e-<exp>);
// Pros:
// - Quite simple
// - Uses only integer arithmetic
// Cons:
// - Outputs trailing zeros
printf("%d.%.0<exp>d", n / (int)1e<exp>, n % (int)1e<exp>);
Upvotes: 1
Views: 550
Reputation: 145277
Your first naive solution does not work for values of <exp>
greater than 6. Here is a simple function. You can adjust the integer type and printf
format accordingly:
#include <stdio.h>
int print_fixed(int n, int exp, FILE *fp) {
char buf[32];
int len = snprintf(buf + 1, sizeof(buf) - 1, "%.*d", exp + 1, n);
int i;
for (i = 0; i < len - exp; i++) {
buf[i] = buf[i + 1];
}
buf[i] = '.';
while (buf[len] == '0') {
buf[len--] = '\0';
}
if (buf[len] == '.')
buf[len--] = '\0';
fputs(buf, fp);
return len + 1;
}
int main() {
int tests[][2] = {
{ 0, 0 }, { 1, 0 }, { 10, 1 }, { 100, 2 }, { 1000, 3 }, { 10000, 4 },
{ 1, 0 }, { 1, 1 }, { 1, 2 }, { 1, 3 }, { 1, 4 },
{ 1, 0 }, { 12, 1 }, { 123, 2 }, { 1234, 3 }, { 12345, 4 },
{ 1, 0 }, { 12, 1 }, { 120, 2 }, { 1204, 3 }, { 12040, 4 },
{ -1, 0 }, { -12, 1 }, { -120, 2 }, { -1204, 3 }, { -12040, 4 },
};
for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
printf("print_fixed(%d, %d, stdout) -> ", tests[i][0], tests[i][1]);
print_fixed(tests[i][0], tests[i][1], stdout);
printf("\n");
}
return 0;
}
Upvotes: 2
Reputation: 44339
I'm not sure how this will perform but you can try it out and let us know.
#define BUF_SZ 32
void p(unsigned n, unsigned exp)
{
char br[BUF_SZ];
int ix = BUF_SZ - 1;
br[ix--] = '\0';
while(exp)
{
// Skip trailing zeros
int t = n % 10;
n = n / 10;
exp--;
if (t)
{
br[ix--] = '0' + t;
break;
}
}
while(exp)
{
br[ix--] = '0' + n % 10;
n = n / 10;
exp--;
}
// Only insert a '.' if something has been printed
if (ix != (BUF_SZ - 2)) br[ix--] = '.';
do
{
br[ix--] = '0' + n % 10;
n = n / 10;
} while(n);
puts(&br[ix + 1]);
}
It prints no trailing zero and no '.' when there is no decimals.
Performance unknown.
Upvotes: 1