打印浮动/双不拖尾零?(复制)

时间:2022-05-10 22:23:37

This question already has an answer here:

这个问题已经有了答案:

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 %f specifier 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 %g specifier, which works for a set of numbers, but it will switch to scientific notation for some numbers, like this:

令人恼火的是,%f说明符将只打印到一个固定的精度,因此它将向所有不能达到该精度的数字添加尾随0。有些人建议使用%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对于具有小数部分的数字的标准精度?

5 个解决方案

#1


8  

Use snprintf to 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”字符。没有其他方法既正确又易于实现。

#2


3  

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

#3


2  

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^n for some integers x, n. But the only fractions that can be represented by this standard have the form x/2^n for some integers x, n.

尾随零意味着分数值可以写成x / 10 ^ n对一些整数x,n。但只有分数,可以用这个标准形式整数x x / 2 ^ n,n。

So what you write as 0.1234 is represented using the bytes 0x3D 0xFC 0xB9 0x24. This is:

因此,你所写的0。1234是用字节0x3D 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 + 1/ 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,后面有无数个0。

So I don't think there's a better way than R.'s.

所以我认为没有比R更好的方法了。

#4


0  

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';
    if (*p == '.') *p = '\0';
    strcpy(s, buf);
    free (buf);
    return s;
}

Output:

输出:

0
2823.2892
4.0003423

#5


-1  

You can print like this:

你可以这样打印:

printf("%.0f", 1000000.0);

For a more detailed answer, look here.

要获得更详细的答案,请看这里。

#1


8  

Use snprintf to 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”字符。没有其他方法既正确又易于实现。

#2


3  

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

#3


2  

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^n for some integers x, n. But the only fractions that can be represented by this standard have the form x/2^n for some integers x, n.

尾随零意味着分数值可以写成x / 10 ^ n对一些整数x,n。但只有分数,可以用这个标准形式整数x x / 2 ^ n,n。

So what you write as 0.1234 is represented using the bytes 0x3D 0xFC 0xB9 0x24. This is:

因此,你所写的0。1234是用字节0x3D 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 + 1/ 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,后面有无数个0。

So I don't think there's a better way than R.'s.

所以我认为没有比R更好的方法了。

#4


0  

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';
    if (*p == '.') *p = '\0';
    strcpy(s, buf);
    free (buf);
    return s;
}

Output:

输出:

0
2823.2892
4.0003423

#5


-1  

You can print like this:

你可以这样打印:

printf("%.0f", 1000000.0);

For a more detailed answer, look here.

要获得更详细的答案,请看这里。