3

I'm confused about the behavior of printf("%f", M_PI). It prints out 3.141593, but M_PI is 3.14159265358979323846264338327950288. Why does printf do this, and how can I get it to print out the whole float. I'm aware of the %1.2f format specifiers, but if I use them then I get a bunch of unused 0s and the output is ugly. I want the entire precision of the float, but not anything extra.

Jack Maloney
  • 527
  • 2
  • 5
  • 18
  • 2
    related: https://stackoverflow.com/questions/16839658/printf-width-specifier-to-maintain-precision-of-floating-point-value – cremno Aug 06 '15 at 16:40
  • 3
    Once a piece of text is converted to a float or double, "all" the digits is no longer a meaningful concept. There's no way for the computer to know, for example, that it converted "3.14" or "3.14000000000000000275", and they both happened to produce the same internal representation. You'll simply have to pick the number of digits appropriate to your task, based on what you know about the precision of the numbers involved. – Lee Daniel Crocker Aug 06 '15 at 16:42

3 Answers3

11

Why does printf do this, and how can I get it to print out the whole float.

By default, the printf() function takes precision of 6 for %f and %F format specifiers. From C11 (N1570) §7.21.6.1/p8 The fprintf function (emphasis mine going forward):

If the precision is missing, it is taken as 6; if the precision is zero and the # flag is not specified, no decimal-point character appears. If a decimal-point character appears, at least one digit appears before it. The value is rounded to the appropriate number of digits.

Thus call is just equivalent to:

printf("%.6f", M_PI);

The is nothing like "whole float", at least not directly as you think. The double objects are likely to be stored in binary IEEE-754 double precision representation. You can see the exact representation using %a or %A format specifier, that prints it as hexadecimal float. For instance:

printf("%a", M_PI);

outputs it as:

0x1.921fb54442d18p+1

which you can think as "whole float".

If all what you need is "longest decimal approximation", that makes sense, then use DBL_DIG from <float.h> header. C11 5.2.4.2.2/p11 Characteristics of floating types :

number of decimal digits, q, such that any floating-point number with q decimal digits can be rounded into a floating-point number with p radix b digits and back again without change to the q decimal digits

For instance:

printf("%.*f", DBL_DIG-1, M_PI);

may print:

3.14159265358979
Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
2

You can use sprintf to print a float to a string with an overkill display precision and then use a function to trim 0s before passing the string to printf using %s to display it. Proof of concept:

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

void trim_zeros(char *x){
    int i;
    i = strlen(x)-1;
    while(i > 0 && x[i] == '0') x[i--] = '\0';
}

int main(void){
    char s1[100];
    char s2[100];
    sprintf(s1,"%1.20f",23.01);
    sprintf(s2,"%1.20f",M_PI);
    trim_zeros(s1);
    trim_zeros(s2);
    printf("s1 = %s, s2 = %s\n",s1,s2);
    //vs:
    printf("s1 = %1.20f, s2 = %1.20f\n",23.01,M_PI);
    return 0;
}

Output:

s1 = 23.010000000000002, s2 = 3.1415926535897931
s1 = 23.01000000000000200000, s2 = 3.14159265358979310000

This illustrates that this approach probably isn't quite what you want. Rather than simply trimming zeros you might want to truncate if the number of consecutive zeros in the decimal part exceeds a certain length (which could be passed as a parameter to trim_zeros. Also — you might want to make sure that 23.0 displays as 23.0 rather than 23. (so maybe keep one zero after a decimal place). This is mostly proof of concept — if you are unhappy with printf use sprintf then massage the result.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
John Coleman
  • 51,337
  • 7
  • 54
  • 119
1

Once a piece of text is converted to a float or double, "all" the digits is no longer a meaningful concept. There's no way for the computer to know, for example, that it converted "3.14" or "3.14000000000000000275", and they both happened to produce the same float. You'll simply have to pick the number of digits appropriate to your task, based on what you know about the precision of the numbers involved.

If you want to print as many digits as are likely to be distinctly represented by the format, floats are about 7 digits and doubles are about 15, but that's an approximation.

Lee Daniel Crocker
  • 12,927
  • 3
  • 29
  • 55