views:

463

answers:

4

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. For example:

const long double MYCONSTANT = 3.0000000L;

Can anyone explain why that is necessary? Doesn't the type declaration imply the value assigned to MYCONSTANT is a long double? What is the difference between the above line and

const long double MYCONSTANT = 3.0000000;        // no 'L' appended

Whew!

+9  A: 

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.

Johannes Schaub - litb
Note that for integers, there are other rules if you have a hex or octal literal. Without any suffix, a hex or octal literal can also become unsigned if its value doesn't fit a corresponding signed type (int, unsigned int, long, unsigned long). In C++03, appending L will also give decimal literals an unsigned type depending on the value and range of the types (long, unsigned long). In C++0x, however, decimal literals will always have signed type, whether or not a suffix was appended (long, long long). Quite confusing i think...
Johannes Schaub - litb
+2  A: 

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.

stonemetal
+2  A: 

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 9s 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).

Chris Conway
But the compiler can work that out from the declaration. You don't need to put 'int a=1i' or 'char a=1c' if I say 'float a=1.0' or 'double a=1.0' it should be pretty obvious I mean float/double respectively.
Martin Beckett
You're asking the compiler to do type inference, which it doesn't do, even for integer constants. Integer constants are int by default. The compiler doesn't warn you about assigning an int constant to a char as long as it's within the char range. It could try to warn for floating point constants, but I guess the conversion rules are too complicated (integer bounds are much simpler).
Chris Conway
You can write all char values as int literals. The problem with flaoting point literals is that they're in decimal, not binary. Therefore even `0.1` won't fit in a long double. But given those constraints, `0.1L` is a better approximation then `0.1`.
MSalters
@mgb: The compiler can work that out from the declaration in some languages. In C++, the type of literal constants is fully specified by the standard, and a compiler that did literal type inference in any way you could notice it would be non-conforming.
David Thornley
Type inference exists in C++ but is restricted to function template arguments...
bltxd
A: 

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.

Zan Lynx