Solved

Printing floats, not doubles, with printf functions

Posted on 2004-03-30
22
1,004 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
  • 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
 
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
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
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

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

Here is a helpful source code for C++ Builder programmers that allows you to manage and manipulate HTML content from C++ code, while also handling HTML events like onclick, onmouseover, ... Some objects defined and used in this source include: …
Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.

747 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

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now