We help IT Professionals succeed at work.

Check out our new AWS podcast with Certified Expert, Phil Phillips! Listen to "How to Execute a Seamless AWS Migration" on EE or on your favorite podcast platform. Listen Now

x

Printing floats, not doubles, with printf functions

Lescha
Lescha asked
on
Medium Priority
1,085 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.
Comment
Watch Question

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

-ssnkumar

Commented:
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.

Author

Commented:
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?>

Commented:
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

Author

Commented:
How, exactly?
And what further processing?

Commented:

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

Commented:
int getNoOfDigits(int n)
{
        int i = 0;

        if (n == 0) return 1;

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

        return i;
}
ozo
CERTIFIED EXPERT
Most Valuable Expert 2014
Top Expert 2015

Commented:
fprintf(LOG_FILE,"%.7g",fX),
      
Top Expert 2004

Commented:
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

Commented:
Hi, Stefan
Looks very similar to my example.
Shoudn't check for x==0 ?
Marek
ozo
CERTIFIED EXPERT
Most Valuable Expert 2014
Top Expert 2015

Commented:
How about
P(123e20);
Top Expert 2004

Commented:
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

Commented:
Stefan,
Your absolutly right. :-)
Marek
Top Expert 2004

Commented:
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

Author

Commented:
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...
Commented:
Unlock this solution with a free trial preview.
(No credit card required)
Get Preview

Commented:
Did you try out my suggestion?

-ssnkumar

Author

Commented:
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.
Top Expert 2004

Commented:
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
Top Expert 2004

Commented:
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

Author

Commented:
Thanks...

Commented:
> 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.
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a free trial preview!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.