alexpanter
alexpanter

Reputation: 1578

At least one decimal after dot with printf in C

I'm looking for a way to print a floating-point number in C, which prints at least one decimal after the dot, but still truncates trailing zeroes, e.g.

double x = 5.0;
printf("<some_format>", x);
// should print 5.0, not 5, and not 5.000000

double y = 5.10;
printf("<same_format>", y);
// should print 5.1, not 5.10, and not 5.100000

double x = 5.1230;
printf("<same_format>", z);
// should print 5.123, not 5.1230

Also, defining a maximum or a fixed number of digits/decimals is exactly what I'm trying to avoid.

Someone knows of one format which accomplishes this with printf without needing to resort to writing the number to a char buffer and then manually editing this buffer?

Upvotes: 5

Views: 4480

Answers (1)

chqrlie
chqrlie

Reputation: 144685

If I understand your question correctly, You want 5.0 to print as 5.0, 5.10 to print as 5.1 and 5.15 to print as 5.15...

There is no simple way to achieve this with printf because the problem is not so simple: 5.10 is represented in C as a double with a binary encoded fractional part that is an approximation of 5.1, not an exact representation. If you print it with enough decimals, you will see that it stops producing trailing zeroes:

    printf("%.23f", 5.10) -> 5.09999999999999999991326

So your question should be:

How to print a floating point number with at least n but at most p decimals, eliding trailing zeroes?

This can be achieved by passing p as the precision field of %f in sprintf and running a loop to remove the trailing zeroes beyond n and trailing period if n is 0.

Here is an example:

#include <stdio.h>

int print_double(double value, int n, int p) {
    char buf[400];
    int dot;
    int len;
    len = snprintf(buf, sizeof buf, "%.*f", p, value);
    if (len >= (int)sizeof(buf)) {
        printf("value too large: %g\n", value);
        return -1;
    }
    for (dot = 0; dot < len;) {
        if (buf[dot++] == '.')
            break;
    }
    while (len - dot > n && buf[len - 1] == '0')
        len--;
    if (len > 0 && buf[len - 1] == '.')
        len--;
    buf[len] = '\0';
    printf("%s\n", buf);
    return len;
}

int main(int argc, char *argv[]) {
    print_double(5.0, 1, 2);
    print_double(5.1, 1, 2);
    print_double(5.15, 1, 2);
    return 0;
}

Upvotes: 6

Related Questions