I have looked at quite a few places online and can\'t seem to find a good explanation as to why we should append an F or L after a value assigned to a C++ constant.
Floating-point constants have type double
by default in C++. Since a long double
is more precise than a double
, you may lose significant digits when long double
constants are converted to double
. To handle these constants, you need to use the L
suffix to maintain long double
precision. For example,
long double x = 8.99999999999999999;
long double y = 8.99999999999999999L;
std::cout.precision(100);
std::cout << "x=" << x << "\n";
std::cout << "y=" << y << "\n";
The output for this code on my system, where double
is 64 bits and long double
96, is
x=9
y=8.9999999999999999895916591441391574335284531116485595703125
What's happening here is that x
gets rounded before the assignment, because the constant is implicitly converted to a double
, and 8.99999999999999999
is not representable as a 64-bit floating point number. (Note that the representation as a long double
is not fully precise either. All of the digits after the first string of 9
s are an attempt to approximate the decimal number 8.99999999999999999
as closely as possible using 96 binary bits.)
In your example, there is no need for the L
constant, because 3.0
is representable precisely as either a double
or a long double
. The double
constant value is implicitly converted to a long double
without any loss of precision.
The case with F
is not so obvious. It can help with overloading, as Zan Lynx points out. I'm not sure, but it may also avoid some subtle rounding errors (i.e., it's possible that encoding as a float
will give a different result from encoding as a double
then rounding to a float
).
No, the declaration does not imply that the initializer has a specific type. The type of the initialize is the same, no matter what type the variable initialized is.
So, if you initialize a long double
, but use a double
for intialization, that would be pretty silly. By using the L
suffix, you say it's a floating point literal of type long double
. Appended to an integer literal, it would say the type has long int
.
Your example does not need it, but the biggest reason I know of to use explicit types on literal values is to make sure that the correct function overload is called.
This can make a large difference in constructors, operator overloads, etc.
Sometimes there is no convenient way to get the literal into the right type, so you have to use a static_cast or put a constructor around the literal.
When there is a literal value it is considered to be of a certain type. 3.0 is considered a double 3 is considered an int. 3.0F makes it in to a float instead of a double 3.0L makes it a long double instead of a double. 3L is a long int instead of an int.
Note at least in g++, and VS08 both of your examples work just fine.