如何使用C/C++格式说明符来实现与“g”相同但使用“1.”代替“1.0”

zu0ti5jz  于 2023-03-01  发布在  C/C++
关注(0)|答案(3)|浏览(254)

我想通过printf打印float,如下所示:

  • (1)右对齐成给定宽度的字符串(这里为8
  • (2)如果可能,显示相关的十进制数字,但在.之后没有不必要的尾随0
  • (3)对于舍入值也执行此操作,即将1.0化为"1."

g我不能得到(3),用f我不能得到(2,3)。
the docs来看,#似乎可以解决(3)的问题
与a、A、e、E、f、F、g或G一起使用,即使后面没有数字,也强制写入输出包含小数点。默认情况下,如果后面没有数字,则不写入小数点。
所以#g可以实现(3),但不幸的是它做的比这里写的更多:它还通过去除相关的十进制数字(见下文)来破坏特征(2)。
下面是我尝试过的一些例子,最后一行显示了我正在寻找的:
| 数|1.0分|-1.0|1.9岁|-999.1|一百万|
| - ------|- ------|- ------|- ------|- ------|- ------|
| x1米11米1x|1|-1|1.9|-1e+03|1|
| %8.g|1|-1|x1米20英寸1x|-1e+03|1|
| %8g|1|-1|1.9|-999.1|1|
| %#8.2g|x1米30英寸1x|-1.0|1.9|-1.0e+03|1.0|
| %#8.g|1.|-1.|2.|x1米39英寸|x1米40英寸1x|
| %#8g|1.00000|-1.00000|1.90000|-999.100|1.00000|
| %8.2f|1.00|-1.00|x1米50英寸|-999.10|1.00|
| %8.f|1|-1|2|-999|1|
| %8f|x1米60英寸1x|-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|x1米80英寸|-999.099976|1.000001|
| ????|1.|-1.|1.9|-999.1|1.000001|
有人能帮助我们如何在最后一行实现所需的输出吗?

mzmfm0qo

mzmfm0qo1#

建议:

    • 修改目标**

使用"%8g",因为这是标准的,并且最接近OP的目标。

    • 后期处理输出**

"%g"中的"#"修改了两项内容:总是打印'.',并且不丢弃尾随的零。OP似乎只需要第一个特性。
使用"%#*.*g", n, n-1, ...并对字符串进行后处理。
这很棘手,需要进行大量测试。

    • 不要**
  • 在打印前对float进行预处理。边缘情况会抓住你。
  • 在后处理中添加文本。边缘情况会抓住你。
  • "%e"不提供非指数形式。
  • "%f"可以使用类似-FLT_MAX的值来实现长输出。

示例代码。存在简化。

#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);
  }
}

产出

????        1.             -1.             1.9          -999.1        1.000001
           1.           -1.          1.9          -999.1       1.000001
68de4m5k

68de4m5k2#

任何人都可以使用的测试。
可能对调查有帮助。

#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];
  const char *format[] = {"%8.2g", "%8.g", "%8g", "%#8.2g", "%#8.g", "%#8g",
      "%8.2f", "%8.f", "%8f", "%#8.2f", "%#8.f", "%#8f", };
  size_t f_n = sizeof format / sizeof format[0];
  for (size_t f_i = 0; f_i < f_n; f_i++) {
    char f[100];
    snprintf(f, sizeof f, "<%s>", format[f_i]);
    printf("%-13s, ", f);
    for (size_t v_i = 0; v_i < v_n; v_i++) {
      double v = val[v_i];
      char s[100];
      snprintf(s, sizeof s, f, v);
      printf("%-13s", s);
    }
    puts("");
  }
}

产出

<%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>
fkaflof6

fkaflof63#

单独使用printf无法获得所需的输出,但可以使用snprintf并按以下方式调整输出:

int format_number(double v) {
    char buf[500];
    int len = snprintf(buf, sizeof buf, "%f", v);
    while (len > 0 && buf[len - 1] = '0')
        buf[--len] = '\0';
    return printf("%8s", buf);
}

相关问题