C语言 打印浮点/双精度没有尾随零?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15453470/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Print float/double without trailing zeros?
提问by Alexis King
There are a few questions related to this, but I haven't seen one that correctly answers this question. I want to print a floating-point number, but I want the number of decimal places to be adaptive. As an example:
有几个与此相关的问题,但我还没有看到一个正确回答这个问题的问题。我想打印一个浮点数,但我希望小数位数是自适应的。举个例子:
0 -> 0
1234 -> 1234
0.1234 -> 0.1234
0.3 -> 0.3
Annoyingly, the %fspecifier will only print to a fixed precision, so it will add trailing zeros to all numbers that don't reach that precision. Some have suggested the %gspecifier, which works for a set of numbers, but it will switch to scientific notation for some numbers, like this:
令人讨厌的是,说明%f符只会打印到固定精度,因此它会向所有未达到该精度的数字添加尾随零。有些人建议使用%g说明符,它适用于一组数字,但它会为某些数字切换到科学记数法,如下所示:
printf("%g", 1000000.0); // prints 1e+06
How can I print floating-point numbers without the unnecessary zeros, while still maintaining printf's standard accuracy for numbers that actually have fractional components?
如何在没有不必要的零的情况下打印浮点数,同时仍然保持 printf 对实际具有小数部分的数字的标准精度?
回答by R.. GitHub STOP HELPING ICE
Use snprintfto print to a temporary buffer then remove the trailing '0'characters manually. There is no other way that's both correct and reasonably easy to implement.
使用snprintf打印到临时缓冲区然后取出后'0'手动字符。没有其他方法既正确又易于实施。
回答by Omri Barel
The problem is that using IEEE standard 754 representation, floating point values (with a fractional part) can never have "trailing zeros".
问题是使用 IEEE 标准 754 表示,浮点值(带有小数部分)永远不会有“尾随零”。
Trailing zeros mean that the fractional value can be written as x/10^nfor some integers x, n. But the only fractions that can be represented by this standard have the form x/2^nfor some integers x, n.
尾随零意味着分数值可以写成x/10^n一些整数 x, n。但是可以由这个标准表示的唯一分数具有x/2^n某些整数 x, n的形式。
So what you write as 0.1234 is represented using the bytes 0x3D 0xFC 0xB9 0x24. This is:
所以你写的 0.1234 用字节 0x3D 0xFC 0xB9 0x24 表示。这是:
Sign = 0
Exponent = 01111011 (which means -4)
Significand: 1.11111001011100100100100
The significand means: 1 + 1/2 + 1/4 + 1/8 + 1/16 + 0/32 + 0/64 + 1/128 + 0/256 + 1/512 + 1/1024 + 1/2048 + 0/4096 + 0/8192 + ...
有效数表示:1 + 1/2 + 1/4 + 1/8 + 1/16 + 0/32 + 0/64 + 1/128 + 0/256 + 1/512 + 1/1024 + 1/2048 + 0/4096 + 0/8192 + ...
If you perform this calculation, you get 1.974400043487548828125.
如果执行此计算,则会得到 1.974400043487548828125。
So the number is + 1.974400043487548828125 * 2^(-4)= 0.1234000027179718
所以数字是+ 1.974400043487548828125 * 2^(-4)=0.1234000027179718
(I've calculated this using a computer, of course, so it could be off for the same reason...)
(当然,我是用电脑计算过的,所以它可能出于同样的原因关闭......)
As you can see, the computer does not want to decide for you that you want to chop this number after 4 digits (only) and not after 9 digits (0.123400002). The point is that the computer doesn't see this number as 0.1234 with an infinite number of trailing zeros.
如您所见,计算机不想为您决定要在 4 位(仅)后而不是 9 位后(0.123400002)砍掉这个数字。关键是计算机不会将这个数字视为 0.1234,并带有无限数量的尾随零。
So I don't think there's a better way than R.'s.
所以我认为没有比 R. 更好的方法了。
回答by flyingOwl
Try:
尝试:
printf("%.20g\n", 1000000.0); // = 1000000
This will switch to scientific notation after 20 significant digits (default is after 6 digits for "%g"):
这将在 20 位有效数字后切换到科学记数法(“%g”的默认值为 6 位数字后):
printf("%.20g\n", 1e+19); // = 10000000000000000000
printf("%.20g\n", 1e+20); // = 1e+20
But be careful with double precision:
但要小心双精度:
printf("%.20g\n", 0.12345); // = 0.12345000000000000417
printf("%.15g\n", 0.12345); // = 0.12345
回答by teppic
I wrote a small function to do this myself using the method already mentioned, here it is with a tester. I can't guarantee it's bug free but I think it's fine.
我使用已经提到的方法编写了一个小函数来自己完成此操作,这里是使用测试仪。我不能保证它没有错误,但我认为它很好。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *convert(char *s, double x);
int main()
{
char str[3][20];
printf("%s\n%s\n%s\n", convert(str[0], 0),
convert (str[1], 2823.28920000),
convert (str[2], 4.000342300));
}
char *convert(char *s, double x)
{
char *buf = malloc(100);
char *p;
int ch;
sprintf(buf, "%.10f", x);
p = buf + strlen(buf) - 1;
while (*p == '0' && *p-- != '.');
*(p+1) = '0
2823.2892
4.0003423
';
if (*p == '.') *p = 'printf("%.0f", 1000000.0);
';
strcpy(s, buf);
free (buf);
return s;
}
Output:
输出:
##代码##
