C++: What Is the Printf() Format Spec for "Float"

C: printf a float value

You can do it like this:

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

6 represents the number of digits after the decimal separator.

C++: What is the printf() format spec for float?

double and float use the same format specifiers with printf (%a, %e, %f, and %g). This is because printf is a variadic function. Any float arguments are implicitly promoted to double before the call; you can't actually pass a float to printf.

C printf format for float

The first number in the format string is the minimum field width, which includes all of the characters, including the decimal point. In your case, the field width needs to be at least 4 for the decimal points to line up.

So you want

int main( void )
{
float a = 1.0, b = 25.16;
printf("%4.1f\n", a);
printf("%4.1f\n", b);
}

Using printf to print float pointer using %d

why float pointer should be printed using %f but why can't by using %d.

The conversion specification (%d or %f) tells printf two things:

  • Where to find the argument that was passed.
  • How to interpret the bits of that argument.

On the first point, modern processors commonly have different registers for integer data and floating-point data. Due to this and related reasons, the rules for how arguments are passed to subroutines (part of the Application Binary Interface for a computing environment) typically say that the first few integer arguments are passed in certain integer registers and the first few floating-point arguments are passed in floating-point registers. (After the first few arguments, additional arguments are typically passed on the hardware stack.)

So, when you tell printf to convert a number with %d but pass it a floating-point argument, printf may take the value from some integer register, but the floating-point argument is not there. It is in some floating-point register. And then printf prints the wrong value.

On the second point, the values of integers and floating-point numbers are encoded in bits differently. %d tells printf to interpret the bits as a binary number (along with some scheme for representing negative numbers, most frequently two’s complement). %f tells printf to interpret the bits as a number encoding with a floating-point format. Also, due to C history, float arguments to printf are passed as double. The most common floating-point format for double uses one bit for the sign, 11 bits for an exponent of two, and 52 bits for a significand portion. (In ordinary scientific notation, for the numeral −3.74•1013, − is the sign, 13 is the exponent, and 3.74 is the significand.) If printf did take some or all of the bits that encoded a double and interpreted them according to %d, it would print a number very different from the value of the floating-point number (except by exceedingly rare coincidence).

Also note that no pointers are printed or passed in printf ("\n%d %d %d %d",a,*( &a ),*b,*c );. a, *( &a ), *b, and *c are all a.

In printf ( "\n%u %u %u", &a, b, c );, the pointers are printed incorrectly. Correct code is printf("%p %p %p\n", (void *) &a, (void *) b, (void *) c);. Here I have made three changes:

  • %p is a correct conversion specification for printing pointers. Sometimes printing with %u will print the same value (although in decimal rather than hexadecimal), but, if that happens, it is just because pointers get passed in the same places as unsigned int, they are the same size, and the errors did not fall afoul of compiler optimization.
  • The pointers are cast to void * for printing. This ensures they are in a common form, suitable for %p, when passed.
  • I moved the \n to the end of the string instead of the beginning. C is designed for new-line characters to be at the ends of the lines instead of the starts, because, when there is a new-line character, it sends output to interactive devices immediately instead of holding it in a buffer.

Correct format specifier for double in printf

"%f" is the (or at least one) correct format for a double. There is no format for a float, because if you attempt to pass a float to printf, it'll be promoted to double before printf receives it1. "%lf" is also acceptable under the current standard -- the l is specified as having no effect if followed by the f conversion specifier (among others).

Note that this is one place that printf format strings differ substantially from scanf (and fscanf, etc.) format strings. For output, you're passing a value, which will be promoted from float to double when passed as a variadic parameter. For input you're passing a pointer, which is not promoted, so you have to tell scanf whether you want to read a float or a double, so for scanf, %f means you want to read a float and %lf means you want to read a double (and, for what it's worth, for a long double, you use %Lf for either printf or scanf).



1. C99, §6.5.2.2/6: "If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions." In C++ the wording is somewhat different (e.g., it doesn't use the word "prototype") but the effect is the same: all the variadic parameters undergo default promotions before they're received by the function.

Printf width specifier to maintain precision of floating-point value

I recommend @Jens Gustedt hexadecimal solution: use %a.

OP wants “print with maximum precision (or at least to the most significant decimal)”.

A simple example would be to print one seventh as in:

#include <float.h>
int Digs = DECIMAL_DIG;
double OneSeventh = 1.0/7.0;
printf("%.*e\n", Digs, OneSeventh);
// 1.428571428571428492127e-01

But let's dig deeper ...

Mathematically, the answer is "0.142857 142857 142857 ...", but we are using finite precision floating point numbers.
Let's assume IEEE 754 double-precision binary.
So the OneSeventh = 1.0/7.0 results in the value below. Also shown are the preceding and following representable double floating point numbers.

OneSeventh before = 0.1428571428571428 214571170656199683435261249542236328125
OneSeventh = 0.1428571428571428 49212692681248881854116916656494140625
OneSeventh after = 0.1428571428571428 769682682968777953647077083587646484375

Printing the exact decimal representation of a double has limited uses.

C has 2 families of macros in <float.h> to help us.

The first set is the number of significant digits to print in a string in decimal so when scanning the string back,
we get the original floating point. There are shown with the C spec's minimum value and a sample C11 compiler.

FLT_DECIMAL_DIG   6,  9 (float)                           (C11)
DBL_DECIMAL_DIG 10, 17 (double) (C11)
LDBL_DECIMAL_DIG 10, 21 (long double) (C11)
DECIMAL_DIG 10, 21 (widest supported floating type) (C99)

The second set is the number of significant digits a string may be scanned into a floating point and then the FP printed, still retaining the same string presentation. There are shown with the C spec's minimum value and a sample C11 compiler. I believe available pre-C99.

FLT_DIG   6, 6 (float)
DBL_DIG 10, 15 (double)
LDBL_DIG 10, 18 (long double)

The first set of macros seems to meet OP's goal of significant digits. But that macro is not always available.

#ifdef DBL_DECIMAL_DIG
#define OP_DBL_Digs (DBL_DECIMAL_DIG)
#else
#ifdef DECIMAL_DIG
#define OP_DBL_Digs (DECIMAL_DIG)
#else
#define OP_DBL_Digs (DBL_DIG + 3)
#endif
#endif

The "+ 3" was the crux of my previous answer.
Its centered on if knowing the round-trip conversion string-FP-string (set #2 macros available C89), how would one determine the digits for FP-string-FP (set #1 macros available post C89)? In general, add 3 was the result.

Now how many significant digits to print is known and driven via <float.h>.

To print N significant decimal digits one may use various formats.

With "%e", the precision field is the number of digits after the lead digit and decimal point.
So - 1 is in order. Note: This -1 is not in the initial int Digs = DECIMAL_DIG;

printf("%.*e\n", OP_DBL_Digs - 1, OneSeventh);
// 1.4285714285714285e-01

With "%f", the precision field is the number of digits after the decimal point.
For a number like OneSeventh/1000000.0, one would need OP_DBL_Digs + 6 to see all the significant digits.

printf("%.*f\n", OP_DBL_Digs    , OneSeventh);
// 0.14285714285714285
printf("%.*f\n", OP_DBL_Digs + 6, OneSeventh/1000000.0);
// 0.00000014285714285714285

Note: Many are use to "%f". That displays 6 digits after the decimal point; 6 is the display default, not the precision of the number.

Formatting floating point numbers in C

That's not a problem with scanning. That is a problem with printf formatting.

From the documentation (emphasis mine):

f, F

The double argument shall be converted to decimal notation in the style "[-]ddd.ddd", where the number of digits after the radix character is equal to the precision specification. If the precision is missing, it shall be taken as 6; if the precision is explicitly zero and no '#' flag is present, no radix character shall appear. If a radix character appears, at least one digit appears before it. The low-order digit shall be rounded in an implementation-defined manner.

You probably want %g (again, emphasis mine):

g, G

The double argument shall be converted in the style f or e (or in the style F or E in the case of a G conversion specifier), with the precision specifying the number of significant digits. If an explicit precision is zero, it shall be taken as 1. The style used depends on the value converted; style e (or E ) shall be used only if the exponent resulting from such a conversion is less than -4 or greater than or equal to the precision. Trailing zeros shall be removed from the fractional portion of the result; a radix character shall appear only if it is followed by a digit or a '#' flag is present.



Related Topics



Leave a reply



Submit