0

I want to trail the output of a double to 2 decimals or less. Consider following example:

#include <stdio.h>

int main() {
    printf( "%.2f\n", 2.    );
    printf( "%.2f\n", 2.5   );
    printf( "%.2f\n", 2.25  );
    printf( "%.2f\n", 2.125 );
}

The output is

2.00
2.50
2.25
2.12

Is there any way to print the values with less than 2 decimals, in case less are needed? I mean the desired output is

2
2.5
2.25
2.12

Answers with iomanip are allowed. I'm focusing on C++, not C but the example is c-only.

I know, that it is often not possible because double values are not precise, but in my examples they are because all fractional parts are powers of 2

Live example

smac89
  • 32,960
  • 13
  • 112
  • 152
meddle0106
  • 1,252
  • 1
  • 11
  • 20

3 Answers3

2

If the absolute value is known to be between 0.006 and 999.995, you could use format %.3g:

#include <stdio.h>

int main() {
    printf( "%.3g\n", 2.    );
    printf( "%.3g\n", 2.5   );
    printf( "%.3g\n", 2.25  );
    printf( "%.3g\n", 2.125 );
}

Output is

2
2.5
2.25
2.12

But for the general case, trimming the string converted by snprintf() seems required:

void print_double_with_at_most_2_decimal_figures(double x) {
    char buf[400];
    int i = snprintf(buf, sizeof buf, "%.2f", x);
    while (i > 0 && buf[i - 1] == '0')
        buf[--i] = '\0';
    if (i > 0 && buf[i - 1] == '.')
        buf[--i] = '\0';
    fputs(buf, stdout);
}
chqrlie
  • 114,102
  • 10
  • 108
  • 170
0

With a little help of modf and pow:

#include <stdio.h>
#include <math.h>

static int dprec(double num, int digs)
{
    if (digs <= 0) return 0;

    double integral;
    // fractional part * (10 ^ digs)
    long mul = (long)(modf(num, &integral) * pow(10, digs));

    while (digs) {
        if (mul % 10 != 0) {
            break;
        }
        mul /= 10;
        digs--;
    }
    return digs;
}

int main(void)
{
    double nums[] = {2.00, 2.50, 2.25, 2.125};

    for (size_t i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) {
        int prec = dprec(nums[i], 2);
        printf("%.*f\n", prec, nums[i]);
    }
    return 0;
}

Output:

2
2.5
2.25
2.12
David Ranieri
  • 37,819
  • 6
  • 48
  • 88
  • Even Ignoring int range, this doesn't work correctly for almost all floating points values. – 2501 Nov 08 '16 at 08:03
  • @2501, can you give an example that doesn't work? – David Ranieri Nov 08 '16 at 08:07
  • Pick a float at random from a uniform distribution. You should almost always hit one that doesn't work. I'll post a counterexample later, I'm too busy now. – 2501 Nov 08 '16 at 08:07
  • 8798.67567, so what? I don't get you, and of course we can switch to `long` or `long long` to enlarge the range. – David Ranieri Nov 08 '16 at 08:09
  • OP says that he is fine with inaccuracies, so your answer is correct, still, here are some examples of discrepancies between your approach and the exact solution: https://ideone.com/RHo1UV – 2501 Nov 08 '16 at 08:52
  • @2501, ah, ok, you mean due to round errors, yes, those inaccuracies will be transmited, anyway edited (added `modf` in order to avoid overflows) – David Ranieri Nov 08 '16 at 09:22
  • Well, the rounding isn't really rounding consistently. If more digits were used the problem would be more apparent. – 2501 Nov 08 '16 at 09:47
-3

One way to do it is to take the value that is 2.00 and then assign it to a variable. This should take care of the extra 0's and give you the correct answer.

Max Ho
  • 17