How can you set the precision of printf to a fixed maximal deviation?

时间:2015-11-12 11:24:20

标签: c floating-point printf

Say I have a couple of values with uncertainty estimates

double x, sigma_x;

e.g.

45.34302958634   ± 4.25976343
3.52986798343    ± 0.2363467
3.3734874533e+12 ± 6.34659e+6

Clearly, most of those decimals aren't significant. How do I choose the correct number of “significant digits” (what does that even mean?), to always get as many decimals as needed out of printf, but no more?

I.e. I want some definition of char* fmtString, dependent on sigma_x, such that

printf(fmString, x)

yields

45
3.5
3.373487e+12

4 个答案:

答案 0 :(得分:1)

以下代码为测试数据输出以下内容:

45
3.5
3.373487e+12

这完全符合要求,而且不会受到我原始解决方案中的缺陷的影响,而且更简单。

floor( log10(sigma) )确定与小数点相关的最后一位有效数字的位置。表达式的其余部分基本上将非有效数字归零。如此调整的值,可以根据需要使用受支持的浮点格式说明符进行打印。

#include <stdio.h>
#include <math.h>

double fn( double x, double sigma )
{
    return x - fmod( x, pow( 10, floor( log10(sigma) ) ) );
}       

int main()
{

    struct
    {
        double x ;
        double sigma ;
    } data[] = {{45.34302958634, 4.25976343},
                {3.52986798343, 0.2363467},
                {3.3734874533e+12, 6.34659e+6}} ;

    for( int i = 0; i < sizeof(data)/sizeof(*data); i++ )
    {
        double xs = fn( data[i].x, data[i].sigma ) ;
        printf( "%.7g\n", xs ) ;
    }

    return 0 ;
}

答案 1 :(得分:1)

关于如何格式化输出,我不清楚这个问题。但是当我明白了,

printf("%.*g", precision, number);

似乎还不错。

那么,如何计算精度?

这肯定不是最快的方式。但你可以像在纸上那样做。

int calc_width(double n, double d)
{
    char s[300], e[300]; //300?? I don't know how much to use. ;)
    int i, j = 0;

    //write them down
    sprintf(s, "%f", n-d/100);
    sprintf(e, "%f", n+d/100);

    //see how many are same
    for(i=0; s[i] == e[i]; i++)
        if(s[i] == '.') j = 1; //well, see 'man printf'

    return i-j;
}

测试:

int main()
{
    double n[] = {45.34302958634, 3.52986798343, 3.3734874533e+12};
    double d[] = {4.25976343, 0.2363467, 6.34659e+6};
    int i;

    for(i=0; i<3; i++)
        printf("%.*g\n", calc_width(n[i], d[i]), n[i]);

    return 0;
}

结果:

45.3
3.5
3.373487e+12

答案 2 :(得分:0)

Use this:

printf("%.*g", precision, number);

with precision computed from your sigma_x as you desire.

答案 3 :(得分:0)

使用"%.*e"控制小数点后的位数。

包括各种测试以确保理智的精确度。

不同意45.34302958634 ± 4.25976343应打印为45,而不是45.3 - 但这是一个数学细节。根据需要调整精度计算。

OP不清楚何时使用指数表示法。 "%.*g"如果符合OP的未说明的截止,则会在那里获得代码。

#include <float.h>
#include <math.h>
// #define DBL_DECIMAL_DIG (DBL_DIG + 3)

void print_number_sigma(double x, double sigma_x) {
  double precision = sigma_x*x ? 
      ceil(log10(fabs(x)) - log10(fabs(sigma_x))) :
      DBL_DECIMAL_DIG - 1;
  if (precision <= 0) precision = 1;
  else if (precision >= DBL_DECIMAL_DIG) precision = DBL_DECIMAL_DIG - 1;
  printf("%.*e +/- %e\n", (int) precision, x, sigma_x);
}

int main(void) {
  print_number_sigma(45.34302958634, 4.25976343);
  print_number_sigma(3.52986798343, 0.2363467);
  print_number_sigma(3.3734874533e+12, 6.34659e+6);
  return 0;
}

输出

4.53e+01 +/- 4.259763e+00
3.53e+00 +/- 2.363467e-01
3.373487e+12 +/- 6.346590e+06
相关问题