避免 printf() 中的尾随零 [英] Avoid trailing zeroes in printf()

查看:25
本文介绍了避免 printf() 中的尾随零的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直对 printf() 系列函数的格式说明符感到困惑.我想要的是能够在小数点后打印具有最大给定位数的双精度(或浮点数).如果我使用:

I keep stumbling on the format specifiers for the printf() family of functions. What I want is to be able to print a double (or float) with a maximum given number of digits after the decimal point. If I use:

printf("%1.3f", 359.01335);
printf("%1.3f", 359.00999);

我明白

359.013
359.010

代替想要的

359.013
359.01

有人可以帮我吗?

推荐答案

使用普通的 printf 格式说明符无法做到这一点.你能得到的最接近的是:

This can't be done with the normal printf format specifiers. The closest you could get would be:

printf("%.6g", 359.013); // 359.013
printf("%.6g", 359.01);  // 359.01

但是.6"是数字宽度,所以

but the ".6" is the total numeric width so

printf("%.6g", 3.01357); // 3.01357

打破它.

可以做的是将数字sprintf("%.20g")放到一个字符串缓冲区中,然后操作这个字符串使小数点后只有N个字符.

What you can do is to sprintf("%.20g") the number to a string buffer then manipulate the string to only have N characters past the decimal point.

假设您的数字在变量 num 中,以下函数将删除除第一个 N 小数以外的所有小数,然后去除尾随的零(以及小数点,如果它们都是零).

Assuming your number is in the variable num, the following function will remove all but the first N decimals, then strip off the trailing zeros (and decimal point if they were all zeros).

char str[50];
sprintf (str,"%.20g",num);  // Make the number.
morphNumericString (str, 3);
:    :
void morphNumericString (char *s, int n) {
    char *p;
    int count;

    p = strchr (s,'.');         // Find decimal point, if any.
    if (p != NULL) {
        count = n;              // Adjust for more or less decimals.
        while (count >= 0) {    // Maximum decimals allowed.
             count--;
             if (*p == '')    // If there's less than desired.
                 break;
             p++;               // Next character.
        }

        *p-- = '';            // Truncate string.
        while (*p == '0')       // Remove trailing zeros.
            *p-- = '';

        if (*p == '.') {        // If all decimals were zeros, remove ".".
            *p = '';
        }
    }
}

<小时>

如果您对截断方面不满意(这会将 0.12399 转换为 0.123 而不是将其四舍五入为 0.124),您实际上可以使用 printf 已经提供的舍入功能.您只需要事先分析数字以动态创建宽度,然后使用它们将数字转换为字符串:


If you're not happy with the truncation aspect (which would turn 0.12399 into 0.123 rather than rounding it to 0.124), you can actually use the rounding facilities already provided by printf. You just need to analyse the number before-hand to dynamically create the widths, then use those to turn the number into a string:

#include <stdio.h>

void nDecimals (char *s, double d, int n) {
    int sz; double d2;

    // Allow for negative.

    d2 = (d >= 0) ? d : -d;
    sz = (d >= 0) ? 0 : 1;

    // Add one for each whole digit (0.xx special case).

    if (d2 < 1) sz++;
    while (d2 >= 1) { d2 /= 10.0; sz++; }

    // Adjust for decimal point and fractionals.

    sz += 1 + n;

    // Create format string then use it.

    sprintf (s, "%*.*f", sz, n, d);
}

int main (void) {
    char str[50];
    double num[] = { 40, 359.01335, -359.00999,
        359.01, 3.01357, 0.111111111, 1.1223344 };
    for (int i = 0; i < sizeof(num)/sizeof(*num); i++) {
        nDecimals (str, num[i], 3);
        printf ("%30.20f -> %s
", num[i], str);
    }
    return 0;
}

在这种情况下 nDecimals() 的重点是正确计算字段宽度,然后使用基于此的格式字符串格式化数字.测试工具 main() 显示了这一点:

The whole point of nDecimals() in this case is to correctly work out the field widths, then format the number using a format string based on that. The test harness main() shows this in action:

  40.00000000000000000000 -> 40.000
 359.01335000000000263753 -> 359.013
-359.00999000000001615263 -> -359.010
 359.00999999999999090505 -> 359.010
   3.01357000000000008200 -> 3.014
   0.11111111099999999852 -> 0.111
   1.12233439999999995429 -> 1.122

一旦您获得了正确舍入的值,您可以再次将其传递给 morphNumericString() 以通过简单地更改来删除尾随零:

Once you have the correctly rounded value, you can once again pass that to morphNumericString() to remove trailing zeros by simply changing:

nDecimals (str, num[i], 3);

进入:

nDecimals (str, num[i], 3);
morphNumericString (str, 3);

(或在 nDecimals 的末尾调用 morphNumericString 但是,在这种情况下,我可能只是将两者合并为一个函数),你最终得到:

(or calling morphNumericString at the end of nDecimals but, in that case, I'd probably just combine the two into one function), and you end up with:

  40.00000000000000000000 -> 40
 359.01335000000000263753 -> 359.013
-359.00999000000001615263 -> -359.01
 359.00999999999999090505 -> 359.01
   3.01357000000000008200 -> 3.014
   0.11111111099999999852 -> 0.111
   1.12233439999999995429 -> 1.122

这篇关于避免 printf() 中的尾随零的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆