C语言 如果是整数,则使用 sprintf 格式化没有小数位的浮点数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14499579/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:08:16  来源:igfitidea点击:

Use sprintf to format floats with no decimal places if integer

cfloating-pointprintf

提问by integra753

Originally I was using sprintf with floats always with 2 decimal places using the following code:

最初,我使用带有浮点数的 sprintf 始终使用以下代码保留 2 个小数位:

static void MyFunc(char* buffer, const float percentage)
{
    sprintf(buffer, "%.2f", percentage);
}

One of the percentage values passed was 0x419FFFFF 20 (debugger view), this printed 20.00 into buffer.

传递的百分比值之一是 0x419FFFFF 20(调试器视图),这将 20.00 打印到缓冲区中。

I would like instead to show 2 decimal places when not an integer, e.g.

当不是整数时,我想显示 2 个小数位,例如

94.74 displayed as 94.74
94.7  displayed as 94.70
0     displayed as 0
5     displayed as 5
100   displayed as 100

I am currently using the following code:

我目前正在使用以下代码:

static void MyFunc(char* buffer, const float percentage)
{
    int fractional_part = ((percentage - (int)percentage) * 100);
    if (0 == fractional_part)
    {
        sprintf(buffer, "%d", (int)percentage);
    }
    else
    {
        sprintf(buffer, "%.2f", percentage);
    }
}

Now if 0x419FFFFF 20 (debugger view) is passed, fractional part is calculated as 99. I assume then the sum for fractional_part ends up being (19.99 - 19) * 100 = 99. Why then does the first example not print 19.99 into buffer?

现在,如果通过 0x419FFFFF 20(调试器视图),小数部分计算为 99。我假设分数部分的总和最终为 (19.99 - 19) * 100 = 99。为什么第一个示例不将 19.99 打印到缓冲区中?

What is the correct solution for my problem?

我的问题的正确解决方案是什么?

回答by LSerni

Yours is a problem of approximation.

你的问题是近似问题。

Suppose that the percentage is 19.999. Then fractional_partwould be 99, and the floating point branch would be invoked.

假设百分比是 19.999。然后fractional_part将是 99,并且将调用浮点分支。

But printing 19.999 with two decimals will round it to 20.00, and thatis what is printed.

但是打印19.999两个小数将它送到20.00,而是被打印的内容。

You could always use the floating point branch, in order to get consistent results, and then truncate at '.' if it comes out with '.00'. Otherwise, you risk your test and printf's internals to be at odds some time.

您可以始终使用浮点分支,以获得一致的结果,然后在 '.' 处截断。如果它出现'.00'。否则,您的测试和printf内部结构有时会出现不一致的风险。

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

int main(int argc, char **argv)
{
        float percentage = 19.999;
        char buffer[50];

        for (percentage = 19.990; percentage < 20.001; percentage += 0.001)
        {
                sprintf(buffer, "%.2f", percentage);
                char *p = strstr(buffer, ".00");
                if (p) *p = 0x0;
                printf("%.3f rendered as %.2f and becomes %s\n", percentage, percentage, buffer);
        }
        return 0;
}

19.990 rendered as 19.99 and becomes 19.99
19.991 rendered as 19.99 and becomes 19.99
19.992 rendered as 19.99 and becomes 19.99
19.993 rendered as 19.99 and becomes 19.99
19.994 rendered as 19.99 and becomes 19.99
19.995 rendered as 19.99 and becomes 19.99
19.996 rendered as 20.00 and becomes 20
19.997 rendered as 20.00 and becomes 20
19.998 rendered as 20.00 and becomes 20
19.999 rendered as 20.00 and becomes 20
20.000 rendered as 20.00 and becomes 20
20.001 rendered as 20.00 and becomes 20

If you don't agree with printf's rounding strategy, just use round()on (a copy of) percentageand force your own. Or you might also, e.g., sprintf()with three digits, and erase the third.

如果您不同意printf的舍入策略,只需使用round()on(的副本)percentage并强制使用您自己的。或者您也可以,例如,sprintf()使用三个数字,然后擦除第三个数字。

And in your specific case (note how my system (Linux x86_64) renders 0x419FFFFF):

在您的特定情况下(请注意我的系统(Linux x86_64)如何呈现 0x419FFFFF):

#include <stdio.h>
#include <string.h>
#include <stdint.h>

int main(int argc, char **argv)
{
        float percentage = 3.1415;
        char buffer[50];

        ((uint32_t *)(&percentage))[0] = 0x419FFFFF;

        sprintf(buffer, "%.2f", percentage);
        char *p = strstr(buffer, ".00");
        if (p) *p = 0x0;
        printf("%.15f rendered as %.2f and becomes %s\n", percentage, percentage, buffer);
        return 0;
}


19.999998092651367 rendered as 20.00 and becomes 20

回答by Kris

Instead of calculating the fractional part yourself you can try to use ceilf(f) == for floorf(f) == fwhich return trueif fis an integer. Another alternative would be too use modf (float x, float *ipart)from std lib or fmodfrom math

您可以尝试使用ceilf(f) == for floorf(f) == fwhich return trueiff是整数,而不是自己计算小数部分。另一种选择太modf (float x, float *ipart)从 std lib 或fmod从数学使用