Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does printf() promote a float to a double?

People also ask

Why would you use float over double?

A float uses less memory than a double, so if you don't need your number to be the size of a double, you might as well use a float since it will take up less memory. Just like you wouldn't use a bus to drive yourself and a friend to the beach... you would be far better off going in a 2 seater car.

Should I use float or double in C?

The default choice for a floating-point type should be double . This is also the type that you get with floating-point literals without a suffix or (in C) standard functions that operate on floating point numbers (e.g. exp , sin , etc.).

Why is float faster than double?

Floats are faster than doubles when you don't need double's precision and you are memory-bandwidth bound and your hardware doesn't carry a penalty on floats. They conserve memory-bandwidth because they occupy half the space per number. There are also platforms that can process more floats than doubles in parallel.

How floats and doubles are stored in C?

While float has 32 bit precision for floating number (8 bits for the exponent, and 23* for the value), i.e. float has 7 decimal digits of precision. As double has more precision as compare to that of flot then it is much obvious that it occupies twice memory as occupies by the float data type.


Yes, float arguments to variadic function are promoted to double.

The draft C99 standard section 6.5.2.2 Function calls says:

[...]and arguments that have type float are promoted to double. These are called the default argument promotions.[...]

from the draft C++ standard section 5.2.2 Function call:

[...]a floating point type that is subject to the floating point promotion (4.6), the value of the argument is converted to the promoted type before the call. [...]

and section 4.6:

A prvalue of type float can be converted to a prvalue of type double. The value is unchanged

cppreference covers the default conversions for variadic function in C++ well:

  • std::nullptr_t is converted to void*
  • float arguments are converted to double as in floating-point promotion
  • bool, char, short, and unscoped enumerations are converted to int or wider integer types as in integer promotion

We can see in C and presumably in C++ this conversion was kept around for compatibility with K&R C, from Rationale for International Standard—Programming Languages—C (emphasis mine):

For compatibility with past practice, all argument promotions occur as described in K&R in the absence of a prototype declaration, including the not always desirable promotion of float to double.


As for the why part of the question, it's simple: the C (and C++) standards consider double to be the "default" floating point type. Not float (which is what many of us programmers default to when using floating point numbers).

This can be seen by observing:

  1. 3.14 is a double (if you want a float, you've got to take an extra step and append an f)
  2. The standard math functions take a double by default (for example, sin() takes a double; if you want a float you've got to use sinf())

With this, it seems more "natural" that a float would be promoted to double in a variadic function call, given that double is the "natural" default in the language.


Given a function prototype, type float is only automatically promoted1 when used in trailing arguments. Function print uses those:

int printf(const char * restrict format, ...);

1 (Quoted from: ISO/IEC 9899:201x 6.5.2.2 Function calls)
6. 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.
7. The default argument promotions are performed on trailing arguments.


Because the (C99 or C11) standard says so. See answer by 2501.

There are several pragmatical reasons for that: history (first implementations of C have been used for system programming, where floating point operations don't matter), and the fact that on current (tablet, desktop, server...) processors, arithmetic operations on double are about as efficient as float (but some cheap microcontrollers don't have any FPU, or can only add float by hardware, and require a library for every operation on double). At last, I guess that such a rule enables slightly simpler calling conventions and ABIs.

Think of float as a sort-of short double (which of course is illegal in C). A float is useful mostly when you need to compact memory (and can afford the loss of precision). See also http://floating-point-gui.de/ for more.