使用恒定空间的fprintf

时间:2014-02-21 16:06:38

标签: c printf

我遇到了fprintf的问题。我想要的是使用尽可能多的空间停留在同一列,但这意味着改变十进制浮点数的数量。我有点问题要描述它,所以也许只是例子:

0.001234
0.123456
1.234567
12.34567
123.4567

我尝试使用g和f选项,但它对我不起作用(例如%8.6g%8.6f)。

2 个答案:

答案 0 :(得分:3)

这对于幸存的角落来说是个棘手的问题。

使用不同的精度说明符时,小数点左侧的位数会发生变化。

printf("%.3f", 9.996) --> "9.996";
printf("%.2f", 9.996) --> "10.00"; // Same print width with different precision.

给定各种舍入模式,+ / - 数字,NaN,INF和浮点数的典型二进制表示的细节,尝试预测给定浮点数的宽度printf(),at最好的,近似的。而不是超出思考printf(),简单sprintf()具有最佳猜测精度。使用sprintf()返回值并根据需要调整精度。

解决方案:

  1. 估计宽度。
  2. 打印到缓冲区。
  3. 根据需要进行调整。
  4. #include <float.h>
    int fprintf_Width(FILE *outf, double a, int width) {
      // Subtract 2 for a potential leading "0."
      int prec = width - 2;
      if (prec < 0 || prec > 100 /* TBD upper bound */)
        return 0;  // `width` out of range
    
      // By some means, determine the approximate precision needed.
      char buf[1 + 1 + DBL_MAX_10_EXP + 1 + prec + 1];
      int len = sprintf(buf, "%#.*f", prec, a);
      prec -= len - width;
      if (prec < 0)
        return 0;  // `a` too big
    
      // Try it out
      len = sprintf(buf, "%#.*f", prec, a);
    
      // Adjust as needed
      if (len > width) {
        prec--;
        if (prec < 0)
          return 0;  // `a` too big
        sprintf(buf, "%#.*f", prec, a);
      }
      len = fprintf(outf, "%s", buf);
      return len;
    }
    

答案 1 :(得分:0)

  

鸣谢:正如评论中所指出的,这种方法会因某些宽度规格的数字而失败。

您可以做的一件事是计算小数点前的位数,然后使用printf Precision Specification截断会使数字太长的数字。

  • 您可以创建一个自定义函数,将FILE指针用于要打印的fprintffloat nubmer以及您想要的所需字符数量有; 3个论点。

  • 接下来要做的是确定小数点前的位数。拥有一个新的int变量并将float放入其中,然后将新的int除以10,直到它为零,就应该这样做。但请注意,0.001234在小数点前也有一位数,但int评估不会显示一位数。

  • 然后你所要做的就是减少小数点前的数字位数,加上小数点本身的1(或者更确切地说是负数),这应该是您将使用的fprintf精度规格。

所以,最后,您的fprintf应该看起来像这样:

fprintf( fp, "%.*f", Width - digitsbeforeDpoint - 1 );

这是我已经完成的一个例子,我可以测试。它还有一些进一步的预防措施,确保每个输入都是合理的,并确保给定的浮点数有资格打印出你想要的数字位数:

#include <stdio.h>

void fixdLengthfprintf( FILE * _File, float a, int width ) {
    if ( !_File ) return;
    if ( width < 3 ) return;

    int b = a;
    do {
        width--;
        b /= 10;
    } while ( b );
    width--;

    if ( width > 0 ) fprintf( _File, "%.*f\n", width, a );
}

int main( ) {

    float numbers[7] = {    // prints as:
        1.123456,           // 1.123456
        12.1234567,         // 12.12346 (apparently rounded)
        123456.0123456,     // 123456.0 (heavily rounded)
        1234567.0123456,    // doesn't get printed
        12345678.0123456,   // doesn't get printed
        123456789.0123456,  // doesn't get printed
        0.123456789,        // 0.123457
    };

        // I don't allow them to get printed because else they'd look like:
        // 1.123456
        // 12.12346
        // 123456.0
        // 1234567
        // 12345678.000000
        // 123456792.000000
        // 0.123457

    for ( int i = 0; i < 7; i++ ) fixdLengthfprintf( stdout, numbers[i], 8 );

    fflush( stdin );
    getchar( );
    return 0;
}