Link to home
Start Free TrialLog in
Avatar of Lescha
Lescha

asked on

Printing floats, not doubles, with printf functions

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.
Avatar of Narendra Kumar S S
Narendra Kumar S S
Flag of India image

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

-ssnkumar
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.
Avatar of Lescha
Lescha

ASKER

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?>
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
Avatar of Lescha

ASKER

How, exactly?
And what further processing?

something like
  if( x <> 0)
    printf("%.*f",7-round(log10(abs(x)),x);
int getNoOfDigits(int n)
{
        int i = 0;

        if (n == 0) return 1;

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

        return i;
}
fprintf(LOG_FILE,"%.7g",fX),
      
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
Hi, Stefan
Looks very similar to my example.
Shoudn't check for x==0 ?
Marek
How about
P(123e20);
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
Stefan,
Your absolutly right. :-)
Marek
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
Avatar of Lescha

ASKER

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...
ASKER CERTIFIED SOLUTION
Avatar of wayside
wayside

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Did you try out my suggestion?

-ssnkumar
Avatar of Lescha

ASKER

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.
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
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
Avatar of Lescha

ASKER

Thanks...
> 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.