Solved

Printing floats, not doubles, with printf functions

Posted on 2004-03-30
22
1,019 Views
Last Modified: 2013-12-14
In MSDN, the format of printf states that %f is for printing doubles.
The format of scanf, on the other hand, makes the difference between %f for floats and %lf for doubles.

Is there a way I can print a float variable on the screen so that only its correct value is printed? That is to say, it is well-known that only 7 digits of any float number are relevant, thus, for example, 957.3456 is okay but 19923.3456 is not (the latter should be 19923.35). But if I assign the latter to some float variable, or make some operation with this result, and then printf it (or fprintf, or sprintf) it will show all the digits.

So, here is the question: if I'm using a log file and print numbers into it with fprintf(LOG_FILE,"%f",fX), how should I change is in order to get in the file the same value that I'm getting in Visual Studio's watch? That is, if I watch the value of fX during the debug, the value is different from that written into LOG_FILE, because of what I said above.
0
Comment
Question by:Lescha
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 5
  • 4
  • +3
22 Comments
 
LVL 8

Expert Comment

by:ssnkumar
ID: 10711730
What about the following statement:
printf("%7.2f\n", i); // i is of type float

-ssnkumar
0
 
LVL 17

Expert Comment

by:mokule
ID: 10711743
You can specify precision that decimal digits by for example %.2f to two digits.
It can also be a parameter %.*f. Then You should pass two values: printed and precision.
0
 
LVL 1

Author Comment

by:Lescha
ID: 10711794
No, that's not what I want, because I don't know how my digits are situated around the decimal point.
For example,

123456789 is not a good float.
1234567.89 is not a good float, either.
0.123456789 is not a good float, either.

See my point?

The only way I can see to do that is to print it to a string, like a double and with sprintf, and then look for the decimal point, etc. But this is tedious and, honestly, stupid. Surely there should be another way to do this?>
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 8

Expert Comment

by:ssnkumar
ID: 10711820
But, you can write a small code to find out the number of digits before the decimal point and use that result for further processing...!?

-ssnkumar
0
 
LVL 1

Author Comment

by:Lescha
ID: 10711931
How, exactly?
And what further processing?
0
 
LVL 17

Expert Comment

by:mokule
ID: 10711933

something like
  if( x <> 0)
    printf("%.*f",7-round(log10(abs(x)),x);
0
 
LVL 8

Expert Comment

by:ssnkumar
ID: 10711946
int getNoOfDigits(int n)
{
        int i = 0;

        if (n == 0) return 1;

        while (n)
        {
                n = n / 10;
                i++;
        }

        return i;
}
0
 
LVL 84

Expert Comment

by:ozo
ID: 10711948
fprintf(LOG_FILE,"%.7g",fX),
      
0
 
LVL 12

Expert Comment

by:stefan73
ID: 10712164
Hi Lescha,

First of all, float arguments to a vargs function are promoted to double. So %f is fine.

Toy around with this:

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


#define MANTISSA_PRECISION 7
#define P(x) { int px = (int)(MANTISSA_PRECISION-1-floor(log10(fabs(x)))); \
      printf("%-20s: px=%2d %.*f\n",#x,px,px,(float)x);}

int main(){
      P(1.234567);
      P(0.0001234567);
      P(12.34567);
      P(1234567);
      P(0.1234567);
      return 0;
}


Cheers,
Stefan
0
 
LVL 17

Expert Comment

by:mokule
ID: 10712265
Hi, Stefan
Looks very similar to my example.
Shoudn't check for x==0 ?
Marek
0
 
LVL 84

Expert Comment

by:ozo
ID: 10712366
How about
P(123e20);
0
 
LVL 12

Expert Comment

by:stefan73
ID: 10712697
mokule,
> Looks very similar to my example.
Yes :-)

But your example used abs() instead of fabs(), which is a common error - I fell into this pitfall once, too...

Stefan
0
 
LVL 17

Expert Comment

by:mokule
ID: 10712744
Stefan,
Your absolutly right. :-)
Marek
0
 
LVL 12

Expert Comment

by:stefan73
ID: 10712794
ozo,
You're right. The macro should be defined as
#define P(x) { int px = (int)(MANTISSA_PRECISION-1-floor(log10(fabs(x)))); \
      if(px<0) px=0; \
      printf("%-20s: px=%2d %.*f\n",#x,px,px,(float)x);}

...otherwise there will six decimal places if px < 0.

BTW: It's interesting to see the difference between double and float mantissa precision in the 123e20 case:

123e20              : px= 0 12300000492793395937280 (float)
123e20              : px= 0 12300000000000001048576 (double)
123e20              : px= 0 12300000000000001048576 (long double -> %Lf)
123e20L             : px= 0 12300000000000000000000 (long double)
123e30L             : px= 0 123000000000000000000494994980864 (long double)

Lescha: This "random noise" beyond mantissa accuracy is not avoidable.

Stefan
0
 
LVL 1

Author Comment

by:Lescha
ID: 10716683
Guys, I think you either misread my question or I didn't make it quite clear. What I want is to get the exact same representation in a file/console/string as I get in the Visual Studio's watch window during debug. Somehow, they do know exactly what to show me. I want to know, too...
0
 
LVL 14

Accepted Solution

by:
wayside earned 50 total points
ID: 10717684
I don't see any way to do it just with the format specifications. And who's to knwo what sort of manipulations Visual Studiois doing before they show it; there's no guarantee they are using a simple printf.

You could do something like this though:

char buf[50];
sprintf(buf, "%f", myfloat);
pdot = strchr(buf, '.');  // find where the '.' is
result = (int)(pdot - buf); // find the index of the '.'

int trunc = 8;
if (result > 8)
  trunc = result; // ends string at the '.', i.e. 12345670000.000 => 12345670000
else if (result == 1 && buf[0] == '0') {
  // we have a 0.  find the first non-zero after the decimal, add 7
  int i = 2;
  while (buf[i] == '0') {
     i++;
  }
  trunc = i + 7;
}

buf[trunc] = '\0'; // leaves 7 digits plus the '.'

// buf now contains 7 significant digits
printf(buf);

Seems a lot easier then messing with logs and mantissas and what-not.
0
 
LVL 8

Expert Comment

by:ssnkumar
ID: 10721524
Did you try out my suggestion?

-ssnkumar
0
 
LVL 1

Author Comment

by:Lescha
ID: 10721884
ssnkumar:
Your suggestion is not connected to the issue. You talk about integers, not floats.

wayside:
I tested it and it is as close to what I need as can be, I think. Thanks.
0
 
LVL 12

Expert Comment

by:stefan73
ID: 10721931
Lescha,
> Somehow, they do know exactly what to show me

OK, it's simple:

#define P(x) { int px = (int)(MANTISSA_PRECISION-1-floor(log10(fabs(x)))); \
      if(px<0) px=0;  \
      else if (px > MANTISSA_PRECISION) px=MANTISSA_PRECISION; \
      printf("%-20s: px=%3d %.*g\n",#x,px,MANTISSA_PRECISION,(float)x);}

The maximum width of the output will be MANTISSA_PRECISION + 1 (decimal point) + 4 (like e+05).

Stefan
0
 
LVL 12

Expert Comment

by:stefan73
ID: 10721943
wayside,
> Seems a lot easier then messing with logs and mantissas and what-not.
That's exactly what you're doing ;-)

For large numbers, the solution you offered has no limit in digits. A buffer size of 50 is very prone to overflows (snprintf!).

Stefan
0
 
LVL 1

Author Comment

by:Lescha
ID: 10722921
Thanks...
0
 
LVL 14

Expert Comment

by:wayside
ID: 10723231
> For large numbers, the solution you offered has no limit in digits. A buffer size of 50 > is very prone to overflows (snprintf!).

Very true. For floats (range of 1e38 to 1e-38 or so, 50 would be enough. For a double (1e308 to 1e-308 or so) you'd need a larger buffer, 350 or so should be enough. And you're right, it's always better to use snprintf.
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Delphi : could not find program, '...exe' 2 240
Eclipse IDE - Cannot copy/paste from console output 8 377
C Programming - If Statement 8 84
Acrinis True image 2 118
An Outlet in Cocoa is a persistent reference to a GUI control; it connects a property (a variable) to a control.  For example, it is common to create an Outlet for the text field GUI control and change the text that appears in this field via that Ou…
Update (December 2011): Since this article was published, the things have changed for good for Android native developers. The Sequoyah Project (http://www.eclipse.org/sequoyah/) automates most of the tasks discussed in this article. You can even fin…
The goal of this video is to provide viewers with basic examples to understand opening and writing to files in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use while-loops in the C programming language.

737 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question