When R converts a large number to a string in scientific notation, it includes all significant digits and no trailing zero's. Is it possible to accomplish this in C with sprintf
?
当R用科学的符号把一个大数字转换成一个字符串时,它包含了所有的有效数字,没有后面的零。是否有可能用C语言和sprintf实现这一点?
> as.character(12345e11)
[1] "1.2345e+15"
> as.character(1234500000e6)
[1] "1.2345e+15"
> as.character(1234500001e6)
[1] "1.234500001e+15"
I tried sprintf(buf, "%g", val)
but this seems to include 5 decimal digits at most. I also tried to set a higher precision with sprintf(buf, "%.18g", val)
but this will include non significant digits and trailing zeros.
我尝试过sprintf(buf,“%g”,val),但这似乎最多包含5位小数。我还尝试用sprintf(buf, %)来设置更高的精度。但是这将包括不重要的数字和后面的0。
Is there a way to get the behavior of sprintf(buf, "%g", val)
but increase the 5 digit limit?
是否有一种方法可以使sprintf(buf,“%g”,val)的行为增加5位数的限制?
1 个解决方案
#1
1
Code could use "%.18e"
or "%.18g"
, but the question is how large should "18" be? Is 18 the best value? The answer lies in DBL_DECIMAL_DIG
.
代码可以使用“%。18 e”或“%。18克,但问题是“18”应该有多大?18是最好的值吗?答案就在DBL_DECIMAL_DIG中。
DBL_DECIMAL_DIG
is the minimum number of significant digits to print to insure the round-trip of double
to string to the same exact double
for all double
.
DBL_DECIMAL_DIG是用于打印的有效数字的最小数目,以确保所有双精度双精度双精度双精度双精度双精度双精度。
Recommend using format specifier "%.*e"
.
建议使用格式说明符“%.*e”。
Note that the "18" in "%.18e"
is the number of significant digits after the decimal point. So "%.18e"
prints 19 significant digits.
注意“%”中的“18”。18e是小数点后有效位数。所以“%。18e打印出19位有效数字。
Use printf("%a", x);
which prints in a hexadecimal output.
For a decimal output:
使用printf(" % ",x);在十六进制输出中打印。对于一个十进制输出:
#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);
Ref Printf width specificer to maintain precision of floating-point value
Ref Printf宽度指定器以保持浮点值的精度
A number like y = 1.0/3.0
using the typical double
binary64 format would need to see about 53 decimal digits to see its exact value. But many of the trailing digits are not needed for a successful round-trip.
使用典型的双二进制64格式的y = 1.0/3.0这样的数字需要看到大约53位小数才能看到它的确切值。但是,许多尾随数字并不需要成功的往返。
Now we know the most digits to print, use the below to get rid of those pesky trailing 0
digits.
现在我们知道要打印的数字最多了,用下面的数字去掉那些讨厌的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;
}
Output
输出
1.2e+00
1.4285714285714285e-01
#1
1
Code could use "%.18e"
or "%.18g"
, but the question is how large should "18" be? Is 18 the best value? The answer lies in DBL_DECIMAL_DIG
.
代码可以使用“%。18 e”或“%。18克,但问题是“18”应该有多大?18是最好的值吗?答案就在DBL_DECIMAL_DIG中。
DBL_DECIMAL_DIG
is the minimum number of significant digits to print to insure the round-trip of double
to string to the same exact double
for all double
.
DBL_DECIMAL_DIG是用于打印的有效数字的最小数目,以确保所有双精度双精度双精度双精度双精度双精度双精度。
Recommend using format specifier "%.*e"
.
建议使用格式说明符“%.*e”。
Note that the "18" in "%.18e"
is the number of significant digits after the decimal point. So "%.18e"
prints 19 significant digits.
注意“%”中的“18”。18e是小数点后有效位数。所以“%。18e打印出19位有效数字。
Use printf("%a", x);
which prints in a hexadecimal output.
For a decimal output:
使用printf(" % ",x);在十六进制输出中打印。对于一个十进制输出:
#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);
Ref Printf width specificer to maintain precision of floating-point value
Ref Printf宽度指定器以保持浮点值的精度
A number like y = 1.0/3.0
using the typical double
binary64 format would need to see about 53 decimal digits to see its exact value. But many of the trailing digits are not needed for a successful round-trip.
使用典型的双二进制64格式的y = 1.0/3.0这样的数字需要看到大约53位小数才能看到它的确切值。但是,许多尾随数字并不需要成功的往返。
Now we know the most digits to print, use the below to get rid of those pesky trailing 0
digits.
现在我们知道要打印的数字最多了,用下面的数字去掉那些讨厌的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;
}
Output
输出
1.2e+00
1.4285714285714285e-01