Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use C/C++ format specifiers to achieve the same as "g" but with "1." instead of "1.0"

I'd like to print floats via printf as follows:

  • (1) right-align into a string of given width (here 8)
  • (2) show relevant decimal digits if possible, but no unneccesary trailing 0s after .
  • (3) also do this for rounded values, i.e. format 1.0 as "1."

With g I cannot achieve (3), with f I cannot achieve (2,3).

From the docs it seems that # would do the trick for (3)

Used with a, A, e, E, f, F, g or G it forces the written output to contain a decimal point even if no more digits follow. By default, if no digits follow, no decimal point is written.

So #g can achieve (3), but it unfortunately does more than is written there: it also breaks the feature (2) by removing also relevant decimal digits (see below).

Here are some examples I tried, the last line shows what I am looking for:

number 1.0 -1.0 1.9 -999.1 1.000001
%8.2g 1 -1 1.9 -1e+03 1
%8.g 1 -1 2 -1e+03 1
%8g 1 -1 1.9 -999.1 1
%#8.2g 1.0 -1.0 1.9 -1.0e+03 1.0
%#8.g 1. -1. 2. -1.e+03 1.
%#8g 1.00000 -1.00000 1.90000 -999.100 1.00000
%8.2f 1.00 -1.00 1.90 -999.10 1.00
%8.f 1 -1 2 -999 1
%8f 1.000000 -1.000000 1.900000 -999.099976 1.000001
%#8.2f 1.00 -1.00 1.90 -999.10 1.00
%#8.f 1. -1. 2. -999. 1.
%#8f 1.000000 -1.000000 1.900000 -999.099976 1.000001
???? 1. -1. 1.9 -999.1 1.000001

Can somebody help how to achieve the wanted output in the last line?

like image 691
flonk Avatar asked Dec 05 '25 15:12

flonk


1 Answers

Suggestions:

Modify goal

Use "%8g" as that is standard and closest to OP's goal.

Post process output

"#" in "%g" modifies 2 things: a '.' is always printed and trailing zeroes are not discarded. OP seems to want just the first feature.

Use "%#*.*g", n, n-1, ... and post-process the string.

This is tricky and deserves extensive testing.

Do not

  • Pre-process the float before printing. Edge cases will catch you.

  • Add text in post processing. Edge cases will catch you.

  • "%e" does not provide non-exponential form.

  • "%f" can make for long output with values like -FLT_MAX.

Sample code. Simplifications exists.

#include <stdio.h>
int main() {
  float val[] = {1.0, -1.0, 1.9f, -999.1f, 1.000001f};
  size_t v_n = sizeof val / sizeof val[0];
  puts("????        1.             -1.             1.9          -999.1        1.000001");
  fputs("           ", stdout);
  for (size_t v_i = 0; v_i < v_n; v_i++) {
    double v = val[v_i];
    char s[100];
    int n = 8;
    snprintf(s, sizeof s, "%#*.*g", n, n - 1, v);
    char *dot = strchr(s, '.');
    if (dot) {
      char *begin = dot + 1;
      begin = begin + strspn(begin, "0123456789");
      char *end = begin;
      while (begin[-1] == '0')
        begin--;
      if (begin < end) {
        //printf("xx: <%s> <%s>\n", begin, end);
        size_t len = strlen(end);
        memmove(begin, end, len + 1);
      }
    }
    printf(" %-13s", s);
  }
}

Output

????        1.             -1.             1.9          -999.1        1.000001
           1.           -1.          1.9          -999.1       1.000001     
like image 93
chux - Reinstate Monica Avatar answered Dec 08 '25 09:12

chux - Reinstate Monica



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!