打印sprintf科学记数法中的所有有效数字

Jer*_*oen 7 c printf r

当R将科学记数法中的大数字转换为字符串时,它包含所有有效数字而不包括尾随零.是否有可能在C中实现这一点sprintf

> as.character(12345e11)
[1] "1.2345e+15"
> as.character(1234500000e6)
[1] "1.2345e+15"
> as.character(1234500001e6)
[1] "1.234500001e+15"
Run Code Online (Sandbox Code Playgroud)

我试过sprintf(buf, "%g", val)但这似乎最多包括5位十进制数字.我也尝试设置更高的精度,sprintf(buf, "%.18g", val)但这将包括非有效数字和尾随零.

有没有办法获得行为,sprintf(buf, "%g", val)但增加5位数限制?

chu*_*ica 4

代码可以使用"%.18e"or "%.18g",但问题是“18”应该有多大?18是最好的价值吗?答案就在于DBL_DECIMAL_DIG

DBL_DECIMAL_DIG是要打印的有效数字的最小数量,以确保所有字符串的往返完全相同。doubledouble double

推荐使用格式说明符"%.*e"

注意,其中的“18”是小数点"%.18e"的有效位数。因此打印 19 位有效数字。"%.18e"


使用printf("%a", x);which 以十六进制输出进行打印。
对于十进制输出:

#include <float.h>

//    sign + digit +  dp +       digits          + e + sign + expo + \0
char buf[1 + 1 +      1  + (DBL_DECIMAL_DIG - 1) + 1 + 1    + 5    + 1]; 
sprintf(buf, "%.*e", DBL_DECIMAL_DIG - 1, x);
Run Code Online (Sandbox Code Playgroud)

Ref Printf 宽度特定以保持浮点值的精度


y = 1.0/3.0像使用典型的double binary64格式这样的数字需要查看大约 53 位十进制数字才能看到其准确值。但成功的往返并不需要许多尾随数字。


现在我们知道要打印的最多数字,请使用以下内容来摆脱那些讨厌的尾随0数字。

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

char *trim0(double x, char *buf) {
  sprintf(buf, "% .*e", DBL_DECIMAL_DIG - 1, x);
  if (isfinite(x)) {
    char *p = &buf[DBL_DECIMAL_DIG + 1];  // address of last significand digit
    char *t;
    for (t=p; *t == '0'; t--);
    memmove(t+1, p+1, strlen(p+1)+1);
  }
  return buf;
}

int main(void) {
  char buf[1 + 1 + 1 + (DBL_DECIMAL_DIG - 1) + 1 + 1 + 5 + 1];
  printf("%s\n", trim0(1.2, buf));
  printf("%s\n", trim0(1.0/7, buf));
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出

 1.2e+00
 1.4285714285714285e-01
Run Code Online (Sandbox Code Playgroud)